ropensci / geojsonio

Convert many data formats to & from GeoJSON & TopoJSON
https://docs.ropensci.org/geojsonio
Other
150 stars 59 forks source link

Workaround to convert geoJSON to topoJSON #193

Closed tonycmac closed 1 year ago

tonycmac commented 1 year ago

New to writing issues so apologies if this isn't done correctly but I'm curious if there's any known workarounds to converting geoJSON to topoJSON.

I know that issue 168 made geojsonio::topojson_write() defunct in April 2020 but wondering if there's any programmatic ways to do these conversions.

I've been using mapshaper to manually convert to topoJSON for now and it works but would love to have an R solution to this.

I was naively hopeful that perhaps the github/dev version of geojsonio had fixed this issue but it appears (after installing it) that the issue remains.

Additional info if useful:

My specific use case is utilizing the Government of Canada boundary files and using the Economic regions SHP file. I'm able to read in and use the file using sf::st_read() but attempting to convert it to topoJSON produces the defunct error message. Reviewing the documentation for geojsonio::topojson_write(), it indicates it's just a wrapper for geojsonio::geojson_write() and geojsonio::geo2topo() so I tried doing so and was able to convert successfully to geonJSON but geo2topo() fails.

library(tidyverse)
library(sf)
#> Linking to GEOS 3.9.3, GDAL 3.5.2, PROJ 8.2.1; sf_use_s2() is TRUE

# works fine
can_er_1km <- st_read("C:/Users/machadot/Documents/R/Projects/adhoc/data/econ_regions/ler_000b16a_e.shp") %>% 
  st_transform(crs = 4326) %>% # needs to be in 4326 to do st_intersection
  st_make_valid() %>%  # Nunavut comes up as invalid so this fixes it
  st_simplify(dTolerance = 1000)  # 1km
#> Reading layer `ler_000b16a_e' from data source 
#>   `C:\Users\machadot\Documents\R\Projects\adhoc\data\econ_regions\ler_000b16a_e.shp' 
#>   using driver `ESRI Shapefile'
#> Simple feature collection with 76 features and 4 fields
#> Geometry type: MULTIPOLYGON
#> Dimension:     XY
#> Bounding box:  xmin: 3689439 ymin: 659338.9 xmax: 9015737 ymax: 5242179
#> Projected CRS: PCS_Lambert_Conformal_Conic

# error
can_er_1km %>% 
  geojsonio::topojson_write("C:/Users/machadot/Documents/R/Projects/adhoc/data/er.json")
#> Registered S3 method overwritten by 'geojsonsf':
#>   method        from   
#>   print.geojson geojson
#> Error: topojson_write is temporarily defunct; check back later

# works
can_er_1km %>% 
  geojsonio::geojson_write(file = "C:/Users/machadot/Documents/R/Projects/adhoc/data/er.json")
#> Success! File is at C:/Users/machadot/Documents/R/Projects/adhoc/data/er.json
#> <geojson-file>
#>   Path:       C:/Users/machadot/Documents/R/Projects/adhoc/data/er.json
#>   From class: geo_list

can_geojson <- geojsonio::geojson_read("C:/Users/machadot/Documents/R/Projects/adhoc/data/er.json")

# doesn't work
can_geojson %>% 
  geojsonio::geo2topo()
#> Error in context_eval(join(src), private$context, serialize, await): ReferenceError: FeatureCollection is not defined

Created on 2022-12-16 with reprex v2.0.2

Session info ``` r sessioninfo::session_info() #> ─ Session info ─────────────────────────────────────────────────────────────── #> setting value #> version R version 4.2.2 (2022-10-31 ucrt) #> os Windows 10 x64 (build 19044) #> system x86_64, mingw32 #> ui RTerm #> language (EN) #> collate English_Canada.utf8 #> ctype English_Canada.utf8 #> tz America/New_York #> date 2022-12-16 #> pandoc 2.19.2 @ C:/Users/machadot/Documents/RStudio/bin/quarto/bin/tools/ (via rmarkdown) #> #> ─ Packages ─────────────────────────────────────────────────────────────────── #> package * version date (UTC) lib source #> assertthat 0.2.1 2019-03-21 [1] CRAN (R 4.2.2) #> backports 1.4.1 2021-12-13 [1] CRAN (R 4.2.0) #> broom 1.0.1 2022-08-29 [1] CRAN (R 4.2.2) #> cellranger 1.1.0 2016-07-27 [1] CRAN (R 4.2.2) #> class 7.3-20 2022-01-16 [1] CRAN (R 4.2.2) #> classInt 0.4-8 2022-09-29 [1] CRAN (R 4.2.2) #> cli 3.4.1 2022-09-23 [1] CRAN (R 4.2.2) #> colorspace 2.0-3 2022-02-21 [1] CRAN (R 4.2.2) #> crayon 1.5.2 2022-09-29 [1] CRAN (R 4.2.2) #> crul 1.3 2022-09-03 [1] CRAN (R 4.2.2) #> curl 4.3.3 2022-10-06 [1] CRAN (R 4.2.2) #> DBI 1.1.3 2022-06-18 [1] CRAN (R 4.2.2) #> dbplyr 2.2.1 2022-06-27 [1] CRAN (R 4.2.2) #> digest 0.6.30 2022-10-18 [1] CRAN (R 4.2.2) #> dplyr * 1.0.10 2022-09-01 [1] CRAN (R 4.2.2) #> e1071 1.7-12 2022-10-24 [1] CRAN (R 4.2.2) #> ellipsis 0.3.2 2021-04-29 [1] CRAN (R 4.2.2) #> evaluate 0.18 2022-11-07 [1] CRAN (R 4.2.2) #> fansi 1.0.3 2022-03-24 [1] CRAN (R 4.2.2) #> fastmap 1.1.0 2021-01-25 [1] CRAN (R 4.2.2) #> forcats * 0.5.2 2022-08-19 [1] CRAN (R 4.2.2) #> foreign 0.8-83 2022-09-28 [1] CRAN (R 4.2.2) #> fs 1.5.2 2021-12-08 [1] CRAN (R 4.2.2) #> gargle 1.2.1 2022-09-08 [1] CRAN (R 4.2.2) #> generics 0.1.3 2022-07-05 [1] CRAN (R 4.2.2) #> geojson 0.3.4 2020-06-23 [1] CRAN (R 4.2.2) #> geojsonio 0.10.0.9000 2022-12-16 [1] Github (ropensci/geojsonio@30897f2) #> geojsonsf 2.0.3 2022-05-30 [1] CRAN (R 4.2.2) #> ggplot2 * 3.4.0 2022-11-04 [1] CRAN (R 4.2.2) #> glue 1.6.2 2022-02-24 [1] CRAN (R 4.2.2) #> googledrive 2.0.0 2021-07-08 [1] CRAN (R 4.2.2) #> googlesheets4 1.0.1 2022-08-13 [1] CRAN (R 4.2.2) #> gtable 0.3.1 2022-09-01 [1] CRAN (R 4.2.2) #> haven 2.5.1 2022-08-22 [1] CRAN (R 4.2.2) #> highr 0.9 2021-04-16 [1] CRAN (R 4.2.2) #> hms 1.1.2 2022-08-19 [1] CRAN (R 4.2.2) #> htmltools 0.5.3 2022-07-18 [1] CRAN (R 4.2.2) #> httpcode 0.3.0 2020-04-10 [1] CRAN (R 4.2.2) #> httr 1.4.4 2022-08-17 [1] CRAN (R 4.2.2) #> jqr 1.2.3 2022-03-10 [1] CRAN (R 4.2.2) #> jsonlite 1.8.3 2022-10-21 [1] CRAN (R 4.2.2) #> KernSmooth 2.23-20 2021-05-03 [1] CRAN (R 4.2.2) #> knitr 1.40 2022-08-24 [1] CRAN (R 4.2.2) #> lattice 0.20-45 2021-09-22 [1] CRAN (R 4.2.2) #> lazyeval 0.2.2 2019-03-15 [1] CRAN (R 4.2.2) #> lifecycle 1.0.3 2022-10-07 [1] CRAN (R 4.2.2) #> lubridate 1.9.0 2022-11-06 [1] CRAN (R 4.2.2) #> magrittr 2.0.3 2022-03-30 [1] CRAN (R 4.2.2) #> maptools 1.1-6 2022-12-14 [1] CRAN (R 4.2.2) #> modelr 0.1.10 2022-11-11 [1] CRAN (R 4.2.2) #> munsell 0.5.0 2018-06-12 [1] CRAN (R 4.2.2) #> pillar 1.8.1 2022-08-19 [1] CRAN (R 4.2.2) #> pkgconfig 2.0.3 2019-09-22 [1] CRAN (R 4.2.2) #> proxy 0.4-27 2022-06-09 [1] CRAN (R 4.2.2) #> purrr * 0.3.5 2022-10-06 [1] CRAN (R 4.2.2) #> R.cache 0.16.0 2022-07-21 [1] CRAN (R 4.2.2) #> R.methodsS3 1.8.2 2022-06-13 [1] CRAN (R 4.2.0) #> R.oo 1.25.0 2022-06-12 [1] CRAN (R 4.2.0) #> R.utils 2.12.2 2022-11-11 [1] CRAN (R 4.2.2) #> R6 2.5.1 2021-08-19 [1] CRAN (R 4.2.2) #> Rcpp 1.0.9 2022-07-08 [1] CRAN (R 4.2.2) #> readr * 2.1.3 2022-10-01 [1] CRAN (R 4.2.2) #> readxl 1.4.1 2022-08-17 [1] CRAN (R 4.2.2) #> reprex 2.0.2 2022-08-17 [1] CRAN (R 4.2.2) #> rgeos 0.6-1 2022-12-14 [1] CRAN (R 4.2.2) #> rlang 1.0.6 2022-09-24 [1] CRAN (R 4.2.2) #> rmarkdown 2.18 2022-11-09 [1] CRAN (R 4.2.2) #> rstudioapi 0.14 2022-08-22 [1] CRAN (R 4.2.2) #> rvest 1.0.3 2022-08-19 [1] CRAN (R 4.2.2) #> s2 1.1.0 2022-07-18 [1] CRAN (R 4.2.2) #> scales 1.2.1 2022-08-20 [1] CRAN (R 4.2.2) #> sessioninfo 1.2.2 2021-12-06 [1] CRAN (R 4.2.2) #> sf * 1.0-9 2022-11-08 [1] CRAN (R 4.2.2) #> sp 1.5-1 2022-11-07 [1] CRAN (R 4.2.2) #> stringi 1.7.8 2022-07-11 [1] CRAN (R 4.2.1) #> stringr * 1.4.1 2022-08-20 [1] CRAN (R 4.2.2) #> styler 1.8.1 2022-11-07 [1] CRAN (R 4.2.2) #> tibble * 3.1.8 2022-07-22 [1] CRAN (R 4.2.2) #> tidyr * 1.2.1 2022-09-08 [1] CRAN (R 4.2.2) #> tidyselect 1.2.0 2022-10-10 [1] CRAN (R 4.2.2) #> tidyverse * 1.3.2 2022-07-18 [1] CRAN (R 4.2.2) #> timechange 0.1.1 2022-11-04 [1] CRAN (R 4.2.2) #> tzdb 0.3.0 2022-03-28 [1] CRAN (R 4.2.2) #> units 0.8-0 2022-02-05 [1] CRAN (R 4.2.2) #> utf8 1.2.2 2021-07-24 [1] CRAN (R 4.2.2) #> V8 4.2.2 2022-11-03 [1] CRAN (R 4.2.2) #> vctrs 0.5.0 2022-10-22 [1] CRAN (R 4.2.2) #> withr 2.5.0 2022-03-03 [1] CRAN (R 4.2.2) #> wk 0.7.0 2022-10-13 [1] CRAN (R 4.2.2) #> xfun 0.34 2022-10-18 [1] CRAN (R 4.2.2) #> xml2 1.3.3 2021-11-30 [1] CRAN (R 4.2.2) #> yaml 2.3.6 2022-10-18 [1] CRAN (R 4.2.1) #> #> [1] C:/Users/machadot/Documents/R/R-4.2.2/library #> #> ────────────────────────────────────────────────────────────────────────────── ```
mikemahoney218 commented 1 year ago

Hey @tonycmac , appreciate the issue.

Right now, geojsonio is broadly inactive; I took over maintenance of the package to keep it (and its dependencies) on CRAN, but I don't currently have the time (or, frankly, the familiarity with package internals) for feature development.

So, I'm going to leave this issue open in case anyone skimming issues has a good solution for you. I'm personally not aware of any implementations in R for dealing with TopoJSON yet. And if I am able to find anything, I'll make sure I let you know.

natereal commented 1 year ago

This is a real pity. Power BI requires shapefiles in topoJSON format and it would be great if it was possible to convert in R. I would have thought it was one of the core functions of geojson, so it's a shame the original makers abandoned it.

Shaunson26 commented 1 year ago

Hi all, I had a brief look at this, given my current line of study (JS for R) ...

I assume @oduilln is using mapshaper through node.js ? At least you've installed node.js, used npm to install mapshaper and are calling mapshaper from the command line ...

mapshaper -i input.geojson -o output.topojson format=topojson

I assume this topo is correct .. seems to have "arcs" in the output file ..

Which brings me to the idea that rmapshaper should be able to do it? (will use capital R from here on)

Having a look at the source code there, it either calls mapshaper by using a system2() call, or use the V8 package (running javascript from R, serializing data in and back to R) by including mapshaper.js in the source of the object - Rmapshaper seems to switch between them depending on whether you use a file.path or R object ..

Following on from using mapshaper through a system call by giving Rmapshaper a file.path, i see in Rmapshaper source code, there is this line (utils.R .. sys_mapshaper())

cmd_args <- c(sys_mem, shQuote(in_data_file), command, "-o", shQuote(out_data_file))

which gives the max memory to use, the -i, some command (say -simplify), -o , e.g.

mapshaper 8 -i input.geojson -simplify -o output.geojson

There doesn't seem to be an option (although i've spent little time looking at the source code) to tag on the end of the -o format=topojson .. If I edit the source code of Rmapshaper ..

 cmd_args <- c(sys_mem, shQuote(in_data_file), command, "-o",  shQuote(out_data_file), 'format=topojson')

where I leave command="", I seem to be able to produce the same topojson as calling mapshaper from the command line, given the system2() call now looks like

mapshaper 8 -i input.geojson -o output.geojson format=topojson

Conclusion

If this is correct - please advise! - then either

Shaunson26 commented 1 year ago

I created this .. https://github.com/ateucher/rmapshaper/issues/128

Shaunson26 commented 1 year ago

I had a look at the issue with geojsonio and geojsonio::topojson_write() #168 .. not sure what the check issues where, but when i uncomment the tests in test-topojson_write.R it seems that there are issues with finding the topojson_write methods? It says they're S3methods() in the NAMESPACE but devtools::missing_s3() showed they were missing... I found here - https://github.com/r-lib/devtools/issues/2293 - that you may need to export the methods (for R v4 .. is version came out around Apr 2020? seems plausible) Although I though you didn't have to .. if I add @export to all the topojson_write methods, they are no longer missing and all the tests pass ..

Was this the main isssue here, or somethin else?

mikemahoney218 commented 1 year ago

Honestly, no idea; I think that was done in ~2019, way before I had anything to do with this package. I can try to investigate once I've got a bit more time, or if you want to make a PR I'd be happy to look it over @Shaunson26

Shaunson26 commented 1 year ago

Sweet.. Can do..

mikemahoney218 commented 1 year ago

Hey folks ( @tonycmac , @oduilln and anyone else watching) -- @Shaunson26 contributed a PR which may have fixed this issue. Can someone install the newest development version (via remotes::install_github('ropensci/geojsonio')) and then try writing topojson, and tell me if the results match what you're after?

mikemahoney218 commented 1 year ago

Via email, Carina Hoyer confirms that this works (though is perhaps inefficient; I welcome issues/PRs to fix that!). I'm going to close this out; if there are related issues with writing topoJSON, please feel free to open a new issue.

github-actions[bot] commented 1 year ago

This issue has been automatically locked. If you believe you have found a related problem, please file a new issue (with a reprex: https://reprex.tidyverse.org) and link to this issue.