+ "markdown": "---\ntitle: \"`h3o` is now on CRAN‼️\"\ndescription: |\n R users now have access to a pure Rust implementation of Uber's H3, a \n hexagonal geospatial grid and indexing system.\nauthor: \n - name: Blake Vernon\n - name: Josiah Parry\ndate: \"2025/09/09\"\nimage: thumbnail.png\nimage-alt: \"The letters h3o on a hexagonal sticker.\"\ncategories: [Release]\n---\n\n\n\n\n\nThe extendr-powered R package `h3o` provides access to [a pure Rust implementation](https://github.com/HydroniumLabs/h3o) \nof [Uber's H3 Geospatial Indexing System](https://github.com/uber/h3). \nOriginally developed by Josiah Parry, the R package has also become an official \nproduct of extendr, which means community support 🤝 and maintenance 🏗️ into \nthe foreseeable future.\n\n\n## `h3o` at a glance 👀\n\nThe package provides functionality to interact with H3's grid as vectors, which \ncan be converted to and from `sf` geometries. \n\n\n\n::: {.cell}\n\n```{.r .cell-code}\nlibrary(h3o)\nlibrary(dplyr)\nlibrary(sf)\nlibrary(tibble)\n\nxy <- data.frame(\n x = runif(100, -5, 10),\n y = runif(100, 40, 50)\n)\n\npnts <- st_as_sf(\n xy,\n coords = c(\"x\", \"y\"),\n crs = 4326\n)\n\nmutate(pnts, h3 = h3_from_points(geometry, 5))\n```\n\n::: {.cell-output .cell-output-stdout}\n\n```\nSimple feature collection with 100 features and 1 field\nGeometry type: POINT\nDimension: XY\nBounding box: xmin: -4.861231 ymin: 40.05397 xmax: 9.846006 ymax: 49.98446\nGeodetic CRS: WGS 84\nFirst 10 features:\n geometry h3\n1 POINT (3.169478 45.06344) 851f92d7fffffff\n2 POINT (5.63995 44.91631) 851f9323fffffff\n3 POINT (1.263684 42.55526) 85396207fffffff\n4 POINT (0.3876174 41.06653) 853973b3fffffff\n5 POINT (-1.192501 44.22128) 85184d7bfffffff\n6 POINT (3.86172 41.56535) 8539419bfffffff\n7 POINT (-1.565639 49.98446) 851866bbfffffff\n8 POINT (3.704704 42.74759) 85396e47fffffff\n9 POINT (2.804652 47.0575) 851fb267fffffff\n10 POINT (-4.021278 47.52185) 851846affffffff\n```\n\n\n:::\n:::\n\n\n\nYou can use the `st_as_sfc()` method to convert H3 hexagons to sf `POLYGON`s.\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\n# replace geometry\nh3_cells <- pnts |>\n mutate(\n h3 = h3_from_points(geometry, 4),\n geometry = st_as_sfc(h3)\n )\n\n# plot the hexagons\nplot(st_geometry(h3_cells))\n```\n\n::: {.cell-output-display}\n{width=672}\n:::\n:::\n\n\n\nH3 cell centroids can be returned using `h3_to_points()`. If `sf` is avilable,\nthe results will be returned as an `sfc` (sf column) object. Otherwise it will\nreturn a list of `sfg` (sf geometries).\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\n# fetch h3 column\nh3s <- h3_cells[[\"h3\"]]\n\n# get there centers\nh3_centers <- h3_to_points(h3s)\n\n# plot the hexagons with the centers\nplot(st_geometry(h3_cells))\nplot(h3_centers, pch = 16, add = TRUE, col = \"black\")\n```\n\n::: {.cell-output-display}\n{width=672}\n:::\n:::\n\n\n\n## H3 at light speed ⚡\n\nBecause it builds on a pure Rust implementation, `h3o` is also very very fast. \nHere are some benchmarks, which also serve to showcase `h3o` tools.\n\n### Creating polygons\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\nh3_strs <- as.character(h3s)\nbench::mark(\n h3o = st_as_sfc(h3s),\n h3jsr = h3jsr::cell_to_polygon(h3_strs),\n relative = TRUE\n)\n```\n\n::: {.cell-output .cell-output-stdout}\n\n```\n# A tibble: 2 × 6\n expression min median `itr/sec` mem_alloc `gc/sec`\n <bch:expr> <dbl> <dbl> <dbl> <dbl> <dbl>\n1 h3o 1 1 26.1 1 1 \n2 h3jsr 27.0 25.6 1 268. 3.85\n```\n\n\n:::\n:::\n\n\n\n### Converting polygons to H3 cells:\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\nnc <- st_read(system.file(\"gpkg/nc.gpkg\", package = \"sf\"), quiet = TRUE) |>\n st_transform(4326) |>\n st_geometry()\n\nbench::mark(\n h3o = sfc_to_cells(nc, 5, \"centroid\"),\n h3jsr = h3jsr::polygon_to_cells(nc, 5),\n check = FALSE,\n relative = TRUE\n)\n```\n\n::: {.cell-output .cell-output-stdout}\n\n```\n# A tibble: 2 × 6\n expression min median `itr/sec` mem_alloc `gc/sec`\n <bch:expr> <dbl> <dbl> <dbl> <dbl> <dbl>\n1 h3o 1 1 7.79 1 5.84\n2 h3jsr 8.96 7.82 1 33.0 1 \n```\n\n\n:::\n:::\n\n\n\n### Converting points to cells\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\nbench::mark(\n h3o = h3_from_points(pnts$geometry, 3),\n h3jsr = h3jsr::point_to_cell(pnts$geometry, 3),\n check = FALSE,\n relative = TRUE\n)\n```\n\n::: {.cell-output .cell-output-stdout}\n\n```\n# A tibble: 2 × 6\n expression min median `itr/sec` mem_alloc `gc/sec`\n <bch:expr> <dbl> <dbl> <dbl> <dbl> <dbl>\n1 h3o 1 1 16.8 1 1.02\n2 h3jsr 16.7 19.4 1 1193. 1 \n```\n\n\n:::\n:::\n\n\n\n### Retrieve edges\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\nbench::mark(\n h3o = h3_edges(h3s),\n h3jsr = h3jsr::get_udedges(h3_strs),\n check = FALSE,\n relative = TRUE\n)\n```\n\n::: {.cell-output .cell-output-stdout}\n\n```\n# A tibble: 2 × 6\n expression min median `itr/sec` mem_alloc `gc/sec`\n <bch:expr> <dbl> <dbl> <dbl> <dbl> <dbl>\n1 h3o 1 1 2.95 1 1 \n2 h3jsr 2.97 2.83 1 7.02 2.65\n```\n\n\n:::\n:::\n\n\n\n### Get origins and destinations from edges.\n\n\n\n::: {.cell}\n\n```{.r .cell-code}\n# get edges for a single location\neds <- h3_edges(h3s[1])[[1]]\n# strings for h3jsr\neds_str <- as.character(eds)\n\nbench::mark(\n h3o = h3_edge_cells(eds),\n h3jsr = h3jsr::get_udends(eds_str),\n check = FALSE,\n relative = TRUE\n)\n```\n\n::: {.cell-output .cell-output-stdout}\n\n```\n# A tibble: 2 × 6\n expression min median `itr/sec` mem_alloc `gc/sec`\n <bch:expr> <dbl> <dbl> <dbl> <dbl> <dbl>\n1 h3o 1 1 24.6 1 1 \n2 h3jsr 21.3 26.1 1 2.52 3.01\n```\n\n\n:::\n:::\n\n\n\n## Installation 📦\n\nYou can install the release version of `h3o` from CRAN with:\n\n``` r\ninstall.packages(\"h3o\")\n```\n\nOr you can install the development version from [GitHub](https://github.com/)\nwith:\n\n``` r\n# install.packages(\"pak\")\npak::pak(\"extendr/h3o\")\n```\n\n## Learn more 🧑🎓\n\nSee the package documentation for more details: <http://extendr.rs/h3o/>. \n\nIf you encounter a bug or would like to request new features, head over to the \nGitHub repository: <https://github.com/extendr/h3o>.",
0 commit comments