35  Decode a geohash

  • use Robj
  • data_frame!() macro

Naturally, if we have encoded a geohash, we should be able to decode the geohash as well. The challenge is that encoding takes an (x, y) pair into a bounding box. And we cannot go back to the original point, but instead we can get the center of the box with an error amount in x and y directions.

The decode() function has the signature:

fn decode(hash_str: &str) -> Result<(Coord<f64>, f64, f64), GeohashError>

The return is a tuple with 3 values the coordinate, the x error, and y error.

How would a user want to access this information and data? Probably as a data.frame.

What’s data.frame?

It is not vector nor row, but list, in constume, pretending to be square.

A data.frame is a list masquerading as a rectangle. A data.frame consists of:

  • vectors of equal length
  • column names
  • row names
  • the data.frame class

Typically, I’d suggest we use a struct to represent the result of decode(), but this is not compatible with what a data.frame actually is.

data_frame!() macro

A data.frame doesn’t have a type safe representation in extendr (at this point). Constructing them is a bit awkward too. To help with this, there is a data_frame!() macro. It is a thin wrapper to data.frame() in R.

It returns an Robj which is an opaque type. We can use this to create a data.frame from any wrapper-vector compatible types. For example

Example

#[extendr]
fn xyz(x: Doubles, y: Doubles, z: Doubles) -> Robj {
    data_frame!(x = x, y = y, z = z)
}
xyz(rnorm(5), rnorm(5), rnorm(5))
#>            x          y          z
#> 1 -0.2688881  0.2349470  1.3468095
#> 2 -1.1228202  2.3786258  0.2405386
#> 3  1.6705694  1.4699630 -0.1370552
#> 4  3.1485605  0.6131987  0.9025077
#> 5  0.1374142 -1.5969236 -0.6165083

Exercise

Create a new function called gh_decode() which has one argument geohash: String and returns a data.frame as an Robj.

  • Import decode() from geohash
  • Decode the input geohash and unwrap the result.
    • Bonus points for using destructured assignment of the tuple
  • Create a data.frame with 4 columns x, y, x_err, and y_err using data_frame!()
  • Add the function to extendr_module! {}
  • Run rextendr::document() to update the package
  • Test the function locally on the geohash "q8nb00j"

Solution

View solution
#[extendr]
fn gh_decode(geohash: String) -> Robj {
    let (coord, x_err, y_err) = decode(&geohash).unwrap();
    data_frame!(x = coord.x, y = coord.y, x_err = x_err, y_err = y_err)
}