├── .github ├── .gitignore └── workflows │ ├── check_as_cran.yaml │ ├── check.yaml │ ├── pkgdown.yaml │ └── rhub.yaml ├── air.toml ├── docs ├── logo.png ├── favicon.ico ├── favicon-96x96.png ├── apple-touch-icon.png ├── reference │ └── figures │ │ └── logo.png ├── web-app-manifest-192x192.png ├── web-app-manifest-512x512.png ├── deps │ ├── font-awesome-6.5.2 │ │ └── webfonts │ │ │ ├── fa-solid-900.ttf │ │ │ ├── fa-brands-400.ttf │ │ │ ├── fa-brands-400.woff2 │ │ │ ├── fa-regular-400.ttf │ │ │ ├── fa-solid-900.woff2 │ │ │ ├── fa-regular-400.woff2 │ │ │ ├── fa-v4compatibility.ttf │ │ │ └── fa-v4compatibility.woff2 │ ├── Roboto-0.4.9 │ │ ├── KFOMCnqEu92Fr1ME7kSn66aGLdTylUAMQXC89YmC2DPNWubEbVmUiAo.woff2 │ │ ├── KFOMCnqEu92Fr1ME7kSn66aGLdTylUAMQXC89YmC2DPNWubEbVmQiArmlw.woff2 │ │ ├── KFOMCnqEu92Fr1ME7kSn66aGLdTylUAMQXC89YmC2DPNWubEbVmXiArmlw.woff2 │ │ ├── KFOMCnqEu92Fr1ME7kSn66aGLdTylUAMQXC89YmC2DPNWubEbVmYiArmlw.woff2 │ │ ├── KFOMCnqEu92Fr1ME7kSn66aGLdTylUAMQXC89YmC2DPNWubEbVmZiArmlw.woff2 │ │ ├── KFOMCnqEu92Fr1ME7kSn66aGLdTylUAMQXC89YmC2DPNWubEbVmaiArmlw.woff2 │ │ ├── KFOMCnqEu92Fr1ME7kSn66aGLdTylUAMQXC89YmC2DPNWubEbVmbiArmlw.woff2 │ │ ├── KFOMCnqEu92Fr1ME7kSn66aGLdTylUAMQXC89YmC2DPNWubEbVn6iArmlw.woff2 │ │ └── KFOMCnqEu92Fr1ME7kSn66aGLdTylUAMQXC89YmC2DPNWubEbVnoiArmlw.woff2 │ ├── Source_Code_Pro-0.4.9 │ │ ├── HI_diYsKILxRpg3hIP6sJ7fM7PqPMcMnZFqUwX28DMyQtMlrTA.woff2 │ │ ├── HI_diYsKILxRpg3hIP6sJ7fM7PqPMcMnZFqUwX28DMyQtM1rTEUc.woff2 │ │ ├── HI_diYsKILxRpg3hIP6sJ7fM7PqPMcMnZFqUwX28DMyQtMRrTEUc.woff2 │ │ ├── HI_diYsKILxRpg3hIP6sJ7fM7PqPMcMnZFqUwX28DMyQtMVrTEUc.woff2 │ │ ├── HI_diYsKILxRpg3hIP6sJ7fM7PqPMcMnZFqUwX28DMyQtMZrTEUc.woff2 │ │ ├── HI_diYsKILxRpg3hIP6sJ7fM7PqPMcMnZFqUwX28DMyQtMdrTEUc.woff2 │ │ ├── HI_diYsKILxRpg3hIP6sJ7fM7PqPMcMnZFqUwX28DMyQtMprTEUc.woff2 │ │ └── font.css │ ├── Merriweather-0.4.9 │ │ ├── u-4D0qyriQwlOrhSvowK_l5UcA6zuSYEqOzpPe3HOZJ5eX1WtLaQwmYiScCmDxhtNOKl8yDr3icaFF31.woff2 │ │ ├── u-4D0qyriQwlOrhSvowK_l5UcA6zuSYEqOzpPe3HOZJ5eX1WtLaQwmYiScCmDxhtNOKl8yDr3icaEF31GvU.woff2 │ │ ├── u-4D0qyriQwlOrhSvowK_l5UcA6zuSYEqOzpPe3HOZJ5eX1WtLaQwmYiScCmDxhtNOKl8yDr3icaG131GvU.woff2 │ │ ├── u-4D0qyriQwlOrhSvowK_l5UcA6zuSYEqOzpPe3HOZJ5eX1WtLaQwmYiScCmDxhtNOKl8yDr3icaGV31GvU.woff2 │ │ ├── u-4D0qyriQwlOrhSvowK_l5UcA6zuSYEqOzpPe3HOZJ5eX1WtLaQwmYiScCmDxhtNOKl8yDr3icaGl31GvU.woff2 │ │ └── font.css │ ├── headroom-0.11.0 │ │ ├── jQuery.headroom.min.js │ │ └── headroom.min.js │ ├── data-deps.txt │ └── bootstrap-toc-1.0.1 │ │ └── bootstrap-toc.min.js ├── pkgdown.yml ├── site.webmanifest ├── katex-auto.js ├── link.svg └── lightswitch.js ├── man ├── roxygen │ └── templates │ │ ├── conn.R │ │ ├── quiet.R │ │ ├── conn_null.R │ │ ├── new_column.R │ │ ├── predicate.R │ │ ├── overwrite.R │ │ ├── x.R │ │ ├── name.R │ │ ├── crs.R │ │ ├── predicate_args.R │ │ └── spatial_join_predicates.R ├── figures │ └── logo.png ├── get_query_name.Rd ├── dbConnCheck.Rd ├── feedback_query.Rd ├── get_st_predicate.Rd ├── ddbs_list_tables.Rd ├── get_geom_name.Rd ├── ddbs_stop_conn.Rd ├── ddbs_drivers.Rd ├── overwrite_table.Rd ├── convert_to_sf.Rd ├── ddbs_create_conn.Rd ├── convert_to_sf_native_geoarrow.Rd ├── ddbs_load.Rd ├── ddbs_install.Rd ├── ddbs_create_schema.Rd ├── ddbs_glimpse.Rd ├── ddbs_crs.Rd ├── ddbs_register_vector.Rd ├── ddbs_boundary.Rd ├── ddbs_make_valid.Rd ├── ddbs_centroid.Rd ├── ddbs_equals.Rd ├── ddbs_write_vector.Rd ├── ddbs_touches.Rd ├── ddbs_disjoint.Rd ├── ddbs_intersects.Rd ├── ddbs_read_vector.Rd ├── ddbs_crosses.Rd ├── ddbs_within.Rd ├── ddbs_contains.Rd ├── ddbs_covers.Rd ├── ddbs_overlaps.Rd ├── ddbs_buffer.Rd ├── ddbs_covered_by.Rd ├── ddbs_difference.Rd ├── ddbs_simplify.Rd ├── ddbs_intersection.Rd ├── ddbs_is_valid.Rd ├── ddbs_within_properly.Rd ├── ddbs_contains_properly.Rd ├── ddbs_is_simple.Rd ├── ddbs_intersects_extent.Rd ├── ddbs_bbox.Rd ├── ddbs_convex_hull.Rd ├── ddbs_length.Rd ├── ddbs_area.Rd ├── ddbs_concave_hull.Rd ├── ddbs_filter.Rd └── ddbs_join.Rd ├── .vscode ├── extensions.json └── settings.json ├── pkgdown └── favicon │ ├── favicon.ico │ ├── favicon-96x96.png │ ├── apple-touch-icon.png │ ├── web-app-manifest-192x192.png │ ├── web-app-manifest-512x512.png │ └── site.webmanifest ├── CRAN-SUBMISSION ├── .gitignore ├── codecov.yml ├── .Rbuildignore ├── tests ├── testthat.R └── testthat │ ├── setup.R │ ├── test-utils.R │ ├── test-ddbs_convex_hull.R │ ├── test-ddbs_bbox.R │ ├── test-db_read.R │ ├── test-ddbs_join.R │ └── test-ddbs_concave_hull.R ├── duckspatial.Rproj ├── cran-comments.md ├── vignettes ├── duckspatial.Rmd └── benchmark.Rmd ├── NAMESPACE ├── DESCRIPTION ├── NEWS.md ├── _pkgdown.yml └── R ├── ddbs_extension.R ├── ddbs_boundary.R ├── ddbs_convex_hull.R ├── ddbs_filter.R ├── db_register.R ├── utils_assert_fun.R └── ddbs_bbox.R /.github/.gitignore: -------------------------------------------------------------------------------- 1 | *.html 2 | -------------------------------------------------------------------------------- /air.toml: -------------------------------------------------------------------------------- 1 | [format] 2 | default-exclude = true 3 | exclude = ["R/"] 4 | -------------------------------------------------------------------------------- /docs/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cidree/duckspatial/HEAD/docs/logo.png -------------------------------------------------------------------------------- /docs/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cidree/duckspatial/HEAD/docs/favicon.ico -------------------------------------------------------------------------------- /man/roxygen/templates/conn.R: -------------------------------------------------------------------------------- 1 | #' @param conn A connection object to a DuckDB database 2 | 3 | -------------------------------------------------------------------------------- /docs/favicon-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cidree/duckspatial/HEAD/docs/favicon-96x96.png -------------------------------------------------------------------------------- /man/figures/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cidree/duckspatial/HEAD/man/figures/logo.png -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "Posit.air-vscode" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /docs/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cidree/duckspatial/HEAD/docs/apple-touch-icon.png -------------------------------------------------------------------------------- /pkgdown/favicon/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cidree/duckspatial/HEAD/pkgdown/favicon/favicon.ico -------------------------------------------------------------------------------- /CRAN-SUBMISSION: -------------------------------------------------------------------------------- 1 | Version: 0.2.0 2 | Date: 2025-04-29 17:55:06 UTC 3 | SHA: 91dd0ac2f577336b8ad7173e1f10c3121b5fc5ff 4 | -------------------------------------------------------------------------------- /docs/reference/figures/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cidree/duckspatial/HEAD/docs/reference/figures/logo.png -------------------------------------------------------------------------------- /docs/web-app-manifest-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cidree/duckspatial/HEAD/docs/web-app-manifest-192x192.png -------------------------------------------------------------------------------- /docs/web-app-manifest-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cidree/duckspatial/HEAD/docs/web-app-manifest-512x512.png -------------------------------------------------------------------------------- /pkgdown/favicon/favicon-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cidree/duckspatial/HEAD/pkgdown/favicon/favicon-96x96.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cidree/duckspatial/HEAD/pkgdown/favicon/apple-touch-icon.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .Rproj.user 2 | .Rhistory 3 | .RData 4 | .Ruserdata 5 | 6 | internal/* 7 | docs 8 | private 9 | /doc/ 10 | /Meta/ 11 | -------------------------------------------------------------------------------- /pkgdown/favicon/web-app-manifest-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cidree/duckspatial/HEAD/pkgdown/favicon/web-app-manifest-192x192.png -------------------------------------------------------------------------------- /pkgdown/favicon/web-app-manifest-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cidree/duckspatial/HEAD/pkgdown/favicon/web-app-manifest-512x512.png -------------------------------------------------------------------------------- /man/roxygen/templates/quiet.R: -------------------------------------------------------------------------------- 1 | #' @param quiet A logical value. If `TRUE`, suppresses any informational messages. 2 | #' Defaults to `FALSE`. 3 | -------------------------------------------------------------------------------- /docs/deps/font-awesome-6.5.2/webfonts/fa-solid-900.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cidree/duckspatial/HEAD/docs/deps/font-awesome-6.5.2/webfonts/fa-solid-900.ttf -------------------------------------------------------------------------------- /docs/deps/font-awesome-6.5.2/webfonts/fa-brands-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cidree/duckspatial/HEAD/docs/deps/font-awesome-6.5.2/webfonts/fa-brands-400.ttf -------------------------------------------------------------------------------- /docs/deps/font-awesome-6.5.2/webfonts/fa-brands-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cidree/duckspatial/HEAD/docs/deps/font-awesome-6.5.2/webfonts/fa-brands-400.woff2 -------------------------------------------------------------------------------- /docs/deps/font-awesome-6.5.2/webfonts/fa-regular-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cidree/duckspatial/HEAD/docs/deps/font-awesome-6.5.2/webfonts/fa-regular-400.ttf -------------------------------------------------------------------------------- /docs/deps/font-awesome-6.5.2/webfonts/fa-solid-900.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cidree/duckspatial/HEAD/docs/deps/font-awesome-6.5.2/webfonts/fa-solid-900.woff2 -------------------------------------------------------------------------------- /docs/deps/font-awesome-6.5.2/webfonts/fa-regular-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cidree/duckspatial/HEAD/docs/deps/font-awesome-6.5.2/webfonts/fa-regular-400.woff2 -------------------------------------------------------------------------------- /man/roxygen/templates/conn_null.R: -------------------------------------------------------------------------------- 1 | #' @param conn A connection object to a DuckDB database. If `NULL`, the function 2 | #' runs on a temporary DuckDB database. 3 | -------------------------------------------------------------------------------- /docs/deps/font-awesome-6.5.2/webfonts/fa-v4compatibility.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cidree/duckspatial/HEAD/docs/deps/font-awesome-6.5.2/webfonts/fa-v4compatibility.ttf -------------------------------------------------------------------------------- /docs/deps/font-awesome-6.5.2/webfonts/fa-v4compatibility.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cidree/duckspatial/HEAD/docs/deps/font-awesome-6.5.2/webfonts/fa-v4compatibility.woff2 -------------------------------------------------------------------------------- /man/roxygen/templates/new_column.R: -------------------------------------------------------------------------------- 1 | #' @param new_column Name of the new column to create on the input data. If NULL, 2 | #' the function will return a vector with the result 3 | -------------------------------------------------------------------------------- /man/roxygen/templates/predicate.R: -------------------------------------------------------------------------------- 1 | #' @param predicate A geometry predicate function. Defaults to `intersects`, 2 | #' a wrapper of `ST_Intersects`. See details for other options. 3 | -------------------------------------------------------------------------------- /man/roxygen/templates/overwrite.R: -------------------------------------------------------------------------------- 1 | #' @param overwrite Boolean. whether to overwrite the existing table if it exists. Defaults 2 | #' to `FALSE`. This argument is ignored when \code{name} is `NULL`. 3 | -------------------------------------------------------------------------------- /docs/deps/Roboto-0.4.9/KFOMCnqEu92Fr1ME7kSn66aGLdTylUAMQXC89YmC2DPNWubEbVmUiAo.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cidree/duckspatial/HEAD/docs/deps/Roboto-0.4.9/KFOMCnqEu92Fr1ME7kSn66aGLdTylUAMQXC89YmC2DPNWubEbVmUiAo.woff2 -------------------------------------------------------------------------------- /docs/deps/Roboto-0.4.9/KFOMCnqEu92Fr1ME7kSn66aGLdTylUAMQXC89YmC2DPNWubEbVmQiArmlw.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cidree/duckspatial/HEAD/docs/deps/Roboto-0.4.9/KFOMCnqEu92Fr1ME7kSn66aGLdTylUAMQXC89YmC2DPNWubEbVmQiArmlw.woff2 -------------------------------------------------------------------------------- /docs/deps/Roboto-0.4.9/KFOMCnqEu92Fr1ME7kSn66aGLdTylUAMQXC89YmC2DPNWubEbVmXiArmlw.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cidree/duckspatial/HEAD/docs/deps/Roboto-0.4.9/KFOMCnqEu92Fr1ME7kSn66aGLdTylUAMQXC89YmC2DPNWubEbVmXiArmlw.woff2 -------------------------------------------------------------------------------- /docs/deps/Roboto-0.4.9/KFOMCnqEu92Fr1ME7kSn66aGLdTylUAMQXC89YmC2DPNWubEbVmYiArmlw.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cidree/duckspatial/HEAD/docs/deps/Roboto-0.4.9/KFOMCnqEu92Fr1ME7kSn66aGLdTylUAMQXC89YmC2DPNWubEbVmYiArmlw.woff2 -------------------------------------------------------------------------------- /docs/deps/Roboto-0.4.9/KFOMCnqEu92Fr1ME7kSn66aGLdTylUAMQXC89YmC2DPNWubEbVmZiArmlw.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cidree/duckspatial/HEAD/docs/deps/Roboto-0.4.9/KFOMCnqEu92Fr1ME7kSn66aGLdTylUAMQXC89YmC2DPNWubEbVmZiArmlw.woff2 -------------------------------------------------------------------------------- /docs/deps/Roboto-0.4.9/KFOMCnqEu92Fr1ME7kSn66aGLdTylUAMQXC89YmC2DPNWubEbVmaiArmlw.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cidree/duckspatial/HEAD/docs/deps/Roboto-0.4.9/KFOMCnqEu92Fr1ME7kSn66aGLdTylUAMQXC89YmC2DPNWubEbVmaiArmlw.woff2 -------------------------------------------------------------------------------- /docs/deps/Roboto-0.4.9/KFOMCnqEu92Fr1ME7kSn66aGLdTylUAMQXC89YmC2DPNWubEbVmbiArmlw.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cidree/duckspatial/HEAD/docs/deps/Roboto-0.4.9/KFOMCnqEu92Fr1ME7kSn66aGLdTylUAMQXC89YmC2DPNWubEbVmbiArmlw.woff2 -------------------------------------------------------------------------------- /docs/deps/Roboto-0.4.9/KFOMCnqEu92Fr1ME7kSn66aGLdTylUAMQXC89YmC2DPNWubEbVn6iArmlw.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cidree/duckspatial/HEAD/docs/deps/Roboto-0.4.9/KFOMCnqEu92Fr1ME7kSn66aGLdTylUAMQXC89YmC2DPNWubEbVn6iArmlw.woff2 -------------------------------------------------------------------------------- /docs/deps/Roboto-0.4.9/KFOMCnqEu92Fr1ME7kSn66aGLdTylUAMQXC89YmC2DPNWubEbVnoiArmlw.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cidree/duckspatial/HEAD/docs/deps/Roboto-0.4.9/KFOMCnqEu92Fr1ME7kSn66aGLdTylUAMQXC89YmC2DPNWubEbVnoiArmlw.woff2 -------------------------------------------------------------------------------- /docs/deps/Source_Code_Pro-0.4.9/HI_diYsKILxRpg3hIP6sJ7fM7PqPMcMnZFqUwX28DMyQtMlrTA.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cidree/duckspatial/HEAD/docs/deps/Source_Code_Pro-0.4.9/HI_diYsKILxRpg3hIP6sJ7fM7PqPMcMnZFqUwX28DMyQtMlrTA.woff2 -------------------------------------------------------------------------------- /docs/deps/Source_Code_Pro-0.4.9/HI_diYsKILxRpg3hIP6sJ7fM7PqPMcMnZFqUwX28DMyQtM1rTEUc.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cidree/duckspatial/HEAD/docs/deps/Source_Code_Pro-0.4.9/HI_diYsKILxRpg3hIP6sJ7fM7PqPMcMnZFqUwX28DMyQtM1rTEUc.woff2 -------------------------------------------------------------------------------- /docs/deps/Source_Code_Pro-0.4.9/HI_diYsKILxRpg3hIP6sJ7fM7PqPMcMnZFqUwX28DMyQtMRrTEUc.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cidree/duckspatial/HEAD/docs/deps/Source_Code_Pro-0.4.9/HI_diYsKILxRpg3hIP6sJ7fM7PqPMcMnZFqUwX28DMyQtMRrTEUc.woff2 -------------------------------------------------------------------------------- /docs/deps/Source_Code_Pro-0.4.9/HI_diYsKILxRpg3hIP6sJ7fM7PqPMcMnZFqUwX28DMyQtMVrTEUc.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cidree/duckspatial/HEAD/docs/deps/Source_Code_Pro-0.4.9/HI_diYsKILxRpg3hIP6sJ7fM7PqPMcMnZFqUwX28DMyQtMVrTEUc.woff2 -------------------------------------------------------------------------------- /docs/deps/Source_Code_Pro-0.4.9/HI_diYsKILxRpg3hIP6sJ7fM7PqPMcMnZFqUwX28DMyQtMZrTEUc.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cidree/duckspatial/HEAD/docs/deps/Source_Code_Pro-0.4.9/HI_diYsKILxRpg3hIP6sJ7fM7PqPMcMnZFqUwX28DMyQtMZrTEUc.woff2 -------------------------------------------------------------------------------- /docs/deps/Source_Code_Pro-0.4.9/HI_diYsKILxRpg3hIP6sJ7fM7PqPMcMnZFqUwX28DMyQtMdrTEUc.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cidree/duckspatial/HEAD/docs/deps/Source_Code_Pro-0.4.9/HI_diYsKILxRpg3hIP6sJ7fM7PqPMcMnZFqUwX28DMyQtMdrTEUc.woff2 -------------------------------------------------------------------------------- /docs/deps/Source_Code_Pro-0.4.9/HI_diYsKILxRpg3hIP6sJ7fM7PqPMcMnZFqUwX28DMyQtMprTEUc.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cidree/duckspatial/HEAD/docs/deps/Source_Code_Pro-0.4.9/HI_diYsKILxRpg3hIP6sJ7fM7PqPMcMnZFqUwX28DMyQtMprTEUc.woff2 -------------------------------------------------------------------------------- /man/roxygen/templates/x.R: -------------------------------------------------------------------------------- 1 | #' @param x An `sf` spatial object. Alternatively, it can be a string with the 2 | #' name of a table with geometry column within the DuckDB database `conn`. 3 | #' Data is returned from this object. 4 | -------------------------------------------------------------------------------- /docs/deps/Merriweather-0.4.9/u-4D0qyriQwlOrhSvowK_l5UcA6zuSYEqOzpPe3HOZJ5eX1WtLaQwmYiScCmDxhtNOKl8yDr3icaFF31.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cidree/duckspatial/HEAD/docs/deps/Merriweather-0.4.9/u-4D0qyriQwlOrhSvowK_l5UcA6zuSYEqOzpPe3HOZJ5eX1WtLaQwmYiScCmDxhtNOKl8yDr3icaFF31.woff2 -------------------------------------------------------------------------------- /docs/deps/Merriweather-0.4.9/u-4D0qyriQwlOrhSvowK_l5UcA6zuSYEqOzpPe3HOZJ5eX1WtLaQwmYiScCmDxhtNOKl8yDr3icaEF31GvU.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cidree/duckspatial/HEAD/docs/deps/Merriweather-0.4.9/u-4D0qyriQwlOrhSvowK_l5UcA6zuSYEqOzpPe3HOZJ5eX1WtLaQwmYiScCmDxhtNOKl8yDr3icaEF31GvU.woff2 -------------------------------------------------------------------------------- /docs/deps/Merriweather-0.4.9/u-4D0qyriQwlOrhSvowK_l5UcA6zuSYEqOzpPe3HOZJ5eX1WtLaQwmYiScCmDxhtNOKl8yDr3icaG131GvU.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cidree/duckspatial/HEAD/docs/deps/Merriweather-0.4.9/u-4D0qyriQwlOrhSvowK_l5UcA6zuSYEqOzpPe3HOZJ5eX1WtLaQwmYiScCmDxhtNOKl8yDr3icaG131GvU.woff2 -------------------------------------------------------------------------------- /docs/deps/Merriweather-0.4.9/u-4D0qyriQwlOrhSvowK_l5UcA6zuSYEqOzpPe3HOZJ5eX1WtLaQwmYiScCmDxhtNOKl8yDr3icaGV31GvU.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cidree/duckspatial/HEAD/docs/deps/Merriweather-0.4.9/u-4D0qyriQwlOrhSvowK_l5UcA6zuSYEqOzpPe3HOZJ5eX1WtLaQwmYiScCmDxhtNOKl8yDr3icaGV31GvU.woff2 -------------------------------------------------------------------------------- /docs/deps/Merriweather-0.4.9/u-4D0qyriQwlOrhSvowK_l5UcA6zuSYEqOzpPe3HOZJ5eX1WtLaQwmYiScCmDxhtNOKl8yDr3icaGl31GvU.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Cidree/duckspatial/HEAD/docs/deps/Merriweather-0.4.9/u-4D0qyriQwlOrhSvowK_l5UcA6zuSYEqOzpPe3HOZJ5eX1WtLaQwmYiScCmDxhtNOKl8yDr3icaGl31GvU.woff2 -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "[r]": { 3 | "editor.formatOnSave": false, 4 | "editor.defaultFormatter": "Posit.air-vscode" 5 | }, 6 | "[quarto]": { 7 | "editor.formatOnSave": false, 8 | "editor.defaultFormatter": "quarto.quarto" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /man/roxygen/templates/name.R: -------------------------------------------------------------------------------- 1 | #' @param name A character string of length one specifying the name of the table, 2 | #' or a character string of length two specifying the schema and table 3 | #' names. If `NULL` (the default), the function returns the result as an 4 | #' \code{sf} object 5 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | comment: false 2 | 3 | coverage: 4 | status: 5 | project: 6 | default: 7 | target: auto 8 | threshold: 1% 9 | informational: true 10 | patch: 11 | default: 12 | target: auto 13 | threshold: 1% 14 | informational: true 15 | -------------------------------------------------------------------------------- /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^.*\.Rproj$ 2 | ^\.Rproj\.user$ 3 | ^README\.Rmd$ 4 | ^LICENSE\.md$ 5 | internal/* 6 | ^_pkgdown\.yml$ 7 | ^docs$ 8 | ^pkgdown$ 9 | ^cran-comments\.md$ 10 | ^CRAN-SUBMISSION$ 11 | ^\.github$ 12 | ^codecov\.yml$ 13 | ^ducksf$ 14 | ^private$ 15 | ^[.]?air[.]toml$ 16 | ^\.vscode$ 17 | ^doc$ 18 | ^docs$ 19 | ^Meta$ 20 | -------------------------------------------------------------------------------- /docs/pkgdown.yml: -------------------------------------------------------------------------------- 1 | pandoc: 3.6.3 2 | pkgdown: 2.1.3 3 | pkgdown_sha: ~ 4 | articles: 5 | benchmark: benchmark.html 6 | duckspatial: duckspatial.html 7 | spatial_joins: spatial_joins.html 8 | last_built: 2025-12-07T14:10Z 9 | urls: 10 | reference: https://cidree.github.io/duckspatial/reference 11 | article: https://cidree.github.io/duckspatial/articles 12 | -------------------------------------------------------------------------------- /man/roxygen/templates/crs.R: -------------------------------------------------------------------------------- 1 | #' @param crs The coordinates reference system of the data. Specify if the data 2 | #' doesn't have a \code{crs_column}, and you know the CRS. 3 | #' @param crs_column a character string of length one specifying the column 4 | #' storing the CRS (created automatically by \code{\link{ddbs_write_vector}}). 5 | #' Set to `NULL` if absent. 6 | -------------------------------------------------------------------------------- /man/get_query_name.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/db_utils_not_exported.R 3 | \name{get_query_name} 4 | \alias{get_query_name} 5 | \title{Get names for the query} 6 | \usage{ 7 | get_query_name(name) 8 | } 9 | \arguments{ 10 | \item{name}{table name} 11 | } 12 | \value{ 13 | list with fixed names 14 | } 15 | \description{ 16 | Get names for the query 17 | } 18 | \keyword{internal} 19 | -------------------------------------------------------------------------------- /man/roxygen/templates/predicate_args.R: -------------------------------------------------------------------------------- 1 | #' @param id_x Character; optional name of the column in `x` whose values will 2 | #' be used to name the list elements. If `NULL`, integer row numbers of `x` are used. 3 | #' @param id_y Character; optional name of the column in `y` whose values will 4 | #' replace the integer indices returned in each element of the list. 5 | #' @param sparse A logical value. If `TRUE`, it returns a sparse index list. If `FALSE`, 6 | #' it returns a dense logical matrix. 7 | -------------------------------------------------------------------------------- /tests/testthat.R: -------------------------------------------------------------------------------- 1 | # This file is part of the standard setup for testthat. 2 | # It is recommended that you do not modify it. 3 | # 4 | # Where should you do additional test configuration? 5 | # Learn more about the roles of various files in: 6 | # * https://r-pkgs.org/testing-design.html#sec-tests-files-overview 7 | # * https://testthat.r-lib.org/articles/special-files.html 8 | 9 | library(testthat) 10 | library(duckspatial) 11 | library(duckdb) 12 | 13 | test_check("duckspatial") 14 | -------------------------------------------------------------------------------- /man/dbConnCheck.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/db_utils_not_exported.R 3 | \name{dbConnCheck} 4 | \alias{dbConnCheck} 5 | \title{Check if a supported DuckDB connection} 6 | \usage{ 7 | dbConnCheck(conn) 8 | } 9 | \arguments{ 10 | \item{conn}{A connection object to a DuckDB database} 11 | } 12 | \value{ 13 | TRUE (invisibly) for successful import 14 | } 15 | \description{ 16 | Check if a supported DuckDB connection 17 | } 18 | \keyword{internal} 19 | -------------------------------------------------------------------------------- /docs/site.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "name": "", 3 | "short_name": "", 4 | "icons": [ 5 | { 6 | "src": "/web-app-manifest-192x192.png", 7 | "sizes": "192x192", 8 | "type": "image/png", 9 | "purpose": "maskable" 10 | }, 11 | { 12 | "src": "/web-app-manifest-512x512.png", 13 | "sizes": "512x512", 14 | "type": "image/png", 15 | "purpose": "maskable" 16 | } 17 | ], 18 | "theme_color": "#ffffff", 19 | "background_color": "#ffffff", 20 | "display": "standalone" 21 | } -------------------------------------------------------------------------------- /man/feedback_query.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/db_utils_not_exported.R 3 | \name{feedback_query} 4 | \alias{feedback_query} 5 | \title{Feedback for query success} 6 | \usage{ 7 | feedback_query(quiet) 8 | } 9 | \arguments{ 10 | \item{quiet}{A logical value. If \code{TRUE}, suppresses any informational messages. 11 | Defaults to \code{FALSE}.} 12 | } 13 | \value{ 14 | cli message 15 | } 16 | \description{ 17 | Feedback for query success 18 | } 19 | \keyword{internal} 20 | -------------------------------------------------------------------------------- /pkgdown/favicon/site.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "name": "", 3 | "short_name": "", 4 | "icons": [ 5 | { 6 | "src": "/web-app-manifest-192x192.png", 7 | "sizes": "192x192", 8 | "type": "image/png", 9 | "purpose": "maskable" 10 | }, 11 | { 12 | "src": "/web-app-manifest-512x512.png", 13 | "sizes": "512x512", 14 | "type": "image/png", 15 | "purpose": "maskable" 16 | } 17 | ], 18 | "theme_color": "#ffffff", 19 | "background_color": "#ffffff", 20 | "display": "standalone" 21 | } -------------------------------------------------------------------------------- /duckspatial.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | ProjectId: 13c7db16-0fd5-41dc-b9bc-ed7b7fcb4db5 3 | 4 | RestoreWorkspace: Default 5 | SaveWorkspace: Default 6 | AlwaysSaveHistory: Default 7 | 8 | EnableCodeIndexing: Yes 9 | UseSpacesForTab: Yes 10 | NumSpacesForTab: 4 11 | Encoding: UTF-8 12 | 13 | RnwWeave: Sweave 14 | LaTeX: pdfLaTeX 15 | 16 | AutoAppendNewline: Yes 17 | StripTrailingWhitespace: Yes 18 | 19 | BuildType: Package 20 | PackageUseDevtools: Yes 21 | PackageInstallArgs: --no-multiarch --with-keep.source 22 | 23 | SpellingDictionary: en_GB 24 | -------------------------------------------------------------------------------- /man/get_st_predicate.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/db_utils_not_exported.R 3 | \name{get_st_predicate} 4 | \alias{get_st_predicate} 5 | \title{Gets predicate name} 6 | \usage{ 7 | get_st_predicate(predicate) 8 | } 9 | \arguments{ 10 | \item{predicate}{A geometry predicate function. Defaults to \code{intersects}, 11 | a wrapper of \code{ST_Intersects}. See details for other options.} 12 | } 13 | \value{ 14 | character 15 | } 16 | \description{ 17 | Gets a full predicate name from the shorter version 18 | } 19 | \keyword{internal} 20 | -------------------------------------------------------------------------------- /cran-comments.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Test environments 4 | 5 | * local Windows 11 Pro 22H2, 64 bit, R 4.4.2 6 | 7 | * R Under development (unstable) x86_64-w64-mingw32 R 4.5.0 beta 8 | 9 | 10 | ## R CMD check results 11 | 12 | * local Windows 11 Pro 22H2: 13 | 14 | ``` 15 | Duration: 27.5s 16 | 17 | 0 errors ✔ | 0 warnings ✔ | 0 notes ✔ 18 | ``` 19 | 20 | * R Under development (unstable) x86_64-w64-mingw32: 21 | 22 | ``` 23 | * checking CRAN incoming feasibility ... NOTE 24 | Maintainer: 'Adrián Cidre González ' 25 | 26 | 0 errors ✔ | 0 warnings ✔ | 1 note ✖ 27 | ``` 28 | 29 | -------------------------------------------------------------------------------- /man/ddbs_list_tables.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/ddbs_utils.R 3 | \name{ddbs_list_tables} 4 | \alias{ddbs_list_tables} 5 | \title{Check tables and schemas inside a database} 6 | \usage{ 7 | ddbs_list_tables(conn) 8 | } 9 | \arguments{ 10 | \item{conn}{A connection object to a DuckDB database} 11 | } 12 | \value{ 13 | \code{data.frame} 14 | } 15 | \description{ 16 | Check tables and schemas inside a database 17 | } 18 | \examples{ 19 | \dontshow{if (interactive()) withAutoprint(\{ # examplesIf} 20 | ## TODO 21 | \dontshow{\}) # examplesIf} 22 | } 23 | -------------------------------------------------------------------------------- /docs/deps/headroom-0.11.0/jQuery.headroom.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * headroom.js v0.9.4 - Give your page some headroom. Hide your header until you need it 3 | * Copyright (c) 2017 Nick Williams - http://wicky.nillia.ms/headroom.js 4 | * License: MIT 5 | */ 6 | 7 | !function(a){a&&(a.fn.headroom=function(b){return this.each(function(){var c=a(this),d=c.data("headroom"),e="object"==typeof b&&b;e=a.extend(!0,{},Headroom.options,e),d||(d=new Headroom(this,e),d.init(),c.data("headroom",d)),"string"==typeof b&&(d[b](),"destroy"===b&&c.removeData("headroom"))})},a("[data-headroom]").each(function(){var b=a(this);b.headroom(b.data())}))}(window.Zepto||window.jQuery); -------------------------------------------------------------------------------- /man/get_geom_name.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/db_utils_not_exported.R 3 | \name{get_geom_name} 4 | \alias{get_geom_name} 5 | \title{Get column names in a DuckDB database} 6 | \usage{ 7 | get_geom_name(conn, x, rest = FALSE) 8 | } 9 | \arguments{ 10 | \item{conn}{A connection object to a DuckDB database} 11 | 12 | \item{x}{name of the table} 13 | 14 | \item{rest}{whether to return geometry column name, of the rest of the columns} 15 | } 16 | \value{ 17 | name of the geometry column of a table 18 | } 19 | \description{ 20 | Get column names in a DuckDB database 21 | } 22 | \keyword{internal} 23 | -------------------------------------------------------------------------------- /docs/katex-auto.js: -------------------------------------------------------------------------------- 1 | // https://github.com/jgm/pandoc/blob/29fa97ab96b8e2d62d48326e1b949a71dc41f47a/src/Text/Pandoc/Writers/HTML.hs#L332-L345 2 | document.addEventListener("DOMContentLoaded", function () { 3 | var mathElements = document.getElementsByClassName("math"); 4 | var macros = []; 5 | for (var i = 0; i < mathElements.length; i++) { 6 | var texText = mathElements[i].firstChild; 7 | if (mathElements[i].tagName == "SPAN") { 8 | katex.render(texText.data, mathElements[i], { 9 | displayMode: mathElements[i].classList.contains("display"), 10 | throwOnError: false, 11 | macros: macros, 12 | fleqn: false 13 | }); 14 | }}}); 15 | -------------------------------------------------------------------------------- /tests/testthat/setup.R: -------------------------------------------------------------------------------- 1 | # skip tests on CRAN because they take too much time 2 | # skip_if(Sys.getenv("TEST_ONE") != "") 3 | # testthat::skip_on_cran() 4 | testthat::skip_if_not_installed("duckdb") 5 | 6 | # read polygons data 7 | countries_sf <- sf::st_read(system.file("spatial/countries.geojson", package = "duckspatial")) 8 | argentina_sf <- sf::st_read(system.file("spatial/argentina.geojson", package = "duckspatial")) 9 | 10 | ## create points data 11 | set.seed(42) 12 | n <- 1000 13 | points_sf <- data.frame( 14 | id = 1:n, 15 | x = runif(n, min = -180, max = 180), 16 | y = runif(n, min = -90, max = 90) 17 | ) |> 18 | sf::st_as_sf(coords = c("x", "y"), crs = 4326) 19 | -------------------------------------------------------------------------------- /man/ddbs_stop_conn.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/ddbs_utils.R 3 | \name{ddbs_stop_conn} 4 | \alias{ddbs_stop_conn} 5 | \title{Close a duckdb connection} 6 | \usage{ 7 | ddbs_stop_conn(conn) 8 | } 9 | \arguments{ 10 | \item{conn}{A connection object to a DuckDB database} 11 | } 12 | \value{ 13 | TRUE (invisibly) for successful disconnection 14 | } 15 | \description{ 16 | Close a duckdb connection 17 | } 18 | \examples{ 19 | \dontshow{if (interactive()) withAutoprint(\{ # examplesIf} 20 | ## load packages 21 | library(duckspatial) 22 | 23 | ## create an in-memory duckdb database 24 | conn <- ddbs_create_conn(dbdir = "memory") 25 | 26 | ## close the connection 27 | ddbs_stop_conn(conn) 28 | \dontshow{\}) # examplesIf} 29 | } 30 | -------------------------------------------------------------------------------- /man/ddbs_drivers.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/ddbs_utils.R 3 | \name{ddbs_drivers} 4 | \alias{ddbs_drivers} 5 | \title{Get list of GDAL drivers and file formats} 6 | \usage{ 7 | ddbs_drivers(conn) 8 | } 9 | \arguments{ 10 | \item{conn}{A connection object to a DuckDB database} 11 | } 12 | \value{ 13 | \code{data.frame} 14 | } 15 | \description{ 16 | Get list of GDAL drivers and file formats 17 | } 18 | \examples{ 19 | \dontshow{if (interactive()) withAutoprint(\{ # examplesIf} 20 | ## load packages 21 | library(duckdb) 22 | library(duckspatial) 23 | 24 | ## database setup 25 | conn <- dbConnect(duckdb()) 26 | ddbs_install(conn) 27 | ddbs_load(conn) 28 | 29 | ## check drivers 30 | ddbs_drivers(conn) 31 | \dontshow{\}) # examplesIf} 32 | } 33 | -------------------------------------------------------------------------------- /man/overwrite_table.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/db_utils_not_exported.R 3 | \name{overwrite_table} 4 | \alias{overwrite_table} 5 | \title{Feedback for overwrite argument} 6 | \usage{ 7 | overwrite_table(x, conn, quiet, overwrite) 8 | } 9 | \arguments{ 10 | \item{x}{table name} 11 | 12 | \item{conn}{A connection object to a DuckDB database} 13 | 14 | \item{quiet}{A logical value. If \code{TRUE}, suppresses any informational messages. 15 | Defaults to \code{FALSE}.} 16 | 17 | \item{overwrite}{Boolean. whether to overwrite the existing table if it exists. Defaults 18 | to \code{FALSE}. This argument is ignored when \code{name} is \code{NULL}.} 19 | } 20 | \value{ 21 | cli message 22 | } 23 | \description{ 24 | Feedback for overwrite argument 25 | } 26 | \keyword{internal} 27 | -------------------------------------------------------------------------------- /docs/link.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 8 | 12 | 13 | -------------------------------------------------------------------------------- /man/convert_to_sf.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/db_utils_not_exported.R 3 | \name{convert_to_sf} 4 | \alias{convert_to_sf} 5 | \title{Converts from data frame to sf} 6 | \usage{ 7 | convert_to_sf(data, crs, crs_column, x_geom) 8 | } 9 | \arguments{ 10 | \item{data}{a tibble or data frame} 11 | 12 | \item{crs}{The coordinates reference system of the data. Specify if the data 13 | doesn't have a \code{crs_column}, and you know the CRS.} 14 | 15 | \item{crs_column}{a character string of length one specifying the column 16 | storing the CRS (created automatically by \code{\link{ddbs_write_vector}}). 17 | Set to \code{NULL} if absent.} 18 | 19 | \item{x_geom}{name of geometry} 20 | } 21 | \value{ 22 | sf 23 | } 24 | \description{ 25 | Converts a table that has been read from DuckDB into an sf object 26 | } 27 | \keyword{internal} 28 | -------------------------------------------------------------------------------- /man/ddbs_create_conn.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/ddbs_utils.R 3 | \name{ddbs_create_conn} 4 | \alias{ddbs_create_conn} 5 | \title{Create a duckdb connection} 6 | \usage{ 7 | ddbs_create_conn(dbdir = "memory") 8 | } 9 | \arguments{ 10 | \item{dbdir}{String. Either \code{"tempdir"} or \code{"memory"}. Defaults to \code{"memory"}.} 11 | } 12 | \value{ 13 | A \code{duckdb_connection} 14 | } 15 | \description{ 16 | Create a duckdb connection 17 | } 18 | \examples{ 19 | \dontshow{if (interactive()) withAutoprint(\{ # examplesIf} 20 | # load packages 21 | library(duckspatial) 22 | 23 | # create a duckdb database in memory (with spatial extension) 24 | conn <- ddbs_create_conn(dbdir = "memory") 25 | 26 | # create a duckdb database in disk (with spatial extension) 27 | conn <- ddbs_create_conn(dbdir = "tempdir") 28 | \dontshow{\}) # examplesIf} 29 | } 30 | -------------------------------------------------------------------------------- /vignettes/duckspatial.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Intro to duckspatial" 3 | date: "`r Sys.Date()`" 4 | output: rmarkdown::html_vignette 5 | code-annotations: hover 6 | urlcolor: blue 7 | vignette: > 8 | %\VignetteIndexEntry{Intro to duckspatial} 9 | %\VignetteEngine{knitr::rmarkdown} 10 | \usepackage[utf8]{inputenc} 11 | --- 12 | 13 | ```{r, include = FALSE} 14 | knitr::opts_chunk$set( 15 | collapse = TRUE, 16 | comment = "#>", 17 | eval = identical(tolower(Sys.getenv("NOT_CRAN")), "true"), 18 | out.width = "100%" 19 | ) 20 | 21 | # CRAN OMP THREAD LIMIT to avoid CRAN NOTE 22 | Sys.setenv(OMP_THREAD_LIMIT = 2) 23 | ``` 24 | 25 | **{duckspatial}** is an R package to run fast & memory-efficient operations in 26 | spatial data. It leverage the fast analytical capabilities of [DuckDB](https://duckdb.org/) 27 | and its spatial extension while maintaining compatibility with R’s spatial data ecosystem. 28 | 29 | 30 | ... 31 | 32 | -------------------------------------------------------------------------------- /man/roxygen/templates/spatial_join_predicates.R: -------------------------------------------------------------------------------- 1 | #' @details Spatial Join Predicates: 2 | #' 3 | #' A spatial predicate is really just a function that evaluates some spatial 4 | #' relation between two geometries and returns true or false, e.g., “does a 5 | #' contain b” or “is a within distance x of b”. Here is a quick overview of the 6 | #' most commonly used ones, taking two geometries a and b: 7 | #' 8 | #' - `"ST_Intersects"`: Whether a intersects b 9 | #' - `"ST_Contains"`: Whether a contains b 10 | #' - `"ST_ContainsProperly"`: Whether a contains b without b touching a's boundary 11 | #' - `"ST_Within"`: Whether a is within b 12 | #' - `"ST_Overlaps"`: Whether a overlaps b 13 | #' - `"ST_Touches"`: Whether a touches b 14 | #' - `"ST_Equals"`: Whether a is equal to b 15 | #' - `"ST_Crosses"`: Whether a crosses b 16 | #' - `"ST_Covers"`: Whether a covers b 17 | #' - `"ST_CoveredBy"`: Whether a is covered by b 18 | #' - `"ST_DWithin"`: x) Whether a is within distance x of b 19 | -------------------------------------------------------------------------------- /man/convert_to_sf_native_geoarrow.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/db_utils_not_exported.R 3 | \name{convert_to_sf_native_geoarrow} 4 | \alias{convert_to_sf_native_geoarrow} 5 | \title{Converts from data frame to sf using native geoarrow} 6 | \usage{ 7 | convert_to_sf_native_geoarrow(data, crs, crs_column, x_geom) 8 | } 9 | \arguments{ 10 | \item{data}{a tibble or data frame} 11 | 12 | \item{crs}{The coordinates reference system of the data. Specify if the data 13 | doesn't have a \code{crs_column}, and you know the CRS.} 14 | 15 | \item{crs_column}{a character string of length one specifying the column 16 | storing the CRS (created automatically by \code{\link{ddbs_write_vector}}). 17 | Set to \code{NULL} if absent.} 18 | 19 | \item{x_geom}{name of geometry column} 20 | } 21 | \value{ 22 | sf 23 | } 24 | \description{ 25 | Converts a table that has been read from DuckDB into an sf object. 26 | Optimized to handle Arrow-native binary streams using wk and geoarrow. 27 | } 28 | \keyword{internal} 29 | -------------------------------------------------------------------------------- /man/ddbs_load.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/ddbs_extension.R 3 | \name{ddbs_load} 4 | \alias{ddbs_load} 5 | \title{Loads the Spatial extension} 6 | \usage{ 7 | ddbs_load(conn, quiet = FALSE) 8 | } 9 | \arguments{ 10 | \item{conn}{A connection object to a DuckDB database} 11 | 12 | \item{quiet}{A logical value. If \code{TRUE}, suppresses any informational messages. 13 | Defaults to \code{FALSE}.} 14 | } 15 | \value{ 16 | TRUE (invisibly) for successful installation 17 | } 18 | \description{ 19 | Checks if a spatial extension is installed, and loads it in a DuckDB database 20 | } 21 | \examples{ 22 | \dontshow{if (interactive()) withAutoprint(\{ # examplesIf} 23 | ## load packages 24 | library(duckdb) 25 | library(duckspatial) 26 | 27 | ## connect to in memory database 28 | conn <- dbConnect(duckdb::duckdb()) 29 | 30 | ## install the spatial exntesion 31 | ddbs_install(conn) 32 | ddbs_load(conn) 33 | 34 | ## disconnect from db 35 | dbDisconnect(conn) 36 | \dontshow{\}) # examplesIf} 37 | } 38 | -------------------------------------------------------------------------------- /man/ddbs_install.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/ddbs_extension.R 3 | \name{ddbs_install} 4 | \alias{ddbs_install} 5 | \title{Checks and installs the Spatial extension} 6 | \usage{ 7 | ddbs_install(conn, upgrade = FALSE, quiet = FALSE) 8 | } 9 | \arguments{ 10 | \item{conn}{A connection object to a DuckDB database} 11 | 12 | \item{upgrade}{if TRUE, it upgrades the DuckDB extension to the latest version} 13 | 14 | \item{quiet}{A logical value. If \code{TRUE}, suppresses any informational messages. 15 | Defaults to \code{FALSE}.} 16 | } 17 | \value{ 18 | TRUE (invisibly) for successful installation 19 | } 20 | \description{ 21 | Checks if a spatial extension is available, and installs it in a DuckDB database 22 | } 23 | \examples{ 24 | ## load packages 25 | library(duckdb) 26 | library(duckspatial) 27 | 28 | # connect to in memory database 29 | conn <- dbConnect(duckdb::duckdb()) 30 | 31 | # install the spatial extension 32 | ddbs_install(conn) 33 | 34 | # disconnect from db 35 | dbDisconnect(conn) 36 | } 37 | -------------------------------------------------------------------------------- /man/ddbs_create_schema.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/ddbs_utils.R 3 | \name{ddbs_create_schema} 4 | \alias{ddbs_create_schema} 5 | \title{Check and create schema} 6 | \usage{ 7 | ddbs_create_schema(conn, name, quiet = FALSE) 8 | } 9 | \arguments{ 10 | \item{conn}{A connection object to a DuckDB database} 11 | 12 | \item{name}{A character string with the name of the schema to be created} 13 | 14 | \item{quiet}{A logical value. If \code{TRUE}, suppresses any informational messages. 15 | Defaults to \code{FALSE}.} 16 | } 17 | \value{ 18 | TRUE (invisibly) for successful schema creation 19 | } 20 | \description{ 21 | Check and create schema 22 | } 23 | \examples{ 24 | ## load packages 25 | library(duckdb) 26 | library(duckspatial) 27 | 28 | ## connect to in memory database 29 | conn <- ddbs_create_conn(dbdir = "memory") 30 | 31 | ## create a new schema 32 | ddbs_create_schema(conn, "new_schema") 33 | 34 | ## check schemas 35 | dbGetQuery(conn, "SELECT * FROM information_schema.schemata;") 36 | 37 | ## disconnect from db 38 | ddbs_stop_conn(conn) 39 | 40 | } 41 | -------------------------------------------------------------------------------- /docs/deps/data-deps.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /.github/workflows/check_as_cran.yaml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - main 5 | pull_request: 6 | branches: 7 | - main 8 | 9 | name: check_as_cran 10 | 11 | jobs: 12 | check_as_cran: 13 | runs-on: ${{ matrix.config.os }} 14 | 15 | name: ${{ matrix.config.os }} (${{ matrix.config.r }}) 16 | 17 | strategy: 18 | fail-fast: false 19 | matrix: 20 | config: 21 | - {os: ubuntu-22.04, r: 'release', rspm: "https://packagemanager.rstudio.com/cran/__linux__/jammy/latest"} 22 | 23 | env: 24 | RSPM: ${{ matrix.config.rspm }} 25 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 26 | 27 | steps: 28 | - uses: actions/checkout@v2 29 | 30 | - uses: r-lib/actions/setup-r@v2 31 | with: 32 | r-version: ${{ matrix.config.r }} 33 | 34 | - uses: r-lib/actions/setup-pandoc@v2 35 | 36 | - uses: r-lib/actions/setup-r-dependencies@v2 37 | with: 38 | extra-packages: any::rcmdcheck 39 | needs: check 40 | 41 | - uses: r-lib/actions/check-r-package@v2 42 | env: 43 | _R_CHECK_CRAN_INCOMING_: false 44 | NOT_CRAN: false 45 | -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | export(ddbs_area) 4 | export(ddbs_bbox) 5 | export(ddbs_boundary) 6 | export(ddbs_buffer) 7 | export(ddbs_centroid) 8 | export(ddbs_concave_hull) 9 | export(ddbs_contains) 10 | export(ddbs_contains_properly) 11 | export(ddbs_convex_hull) 12 | export(ddbs_covered_by) 13 | export(ddbs_covers) 14 | export(ddbs_create_conn) 15 | export(ddbs_create_schema) 16 | export(ddbs_crosses) 17 | export(ddbs_crs) 18 | export(ddbs_difference) 19 | export(ddbs_disjoint) 20 | export(ddbs_drivers) 21 | export(ddbs_equals) 22 | export(ddbs_filter) 23 | export(ddbs_glimpse) 24 | export(ddbs_install) 25 | export(ddbs_interpolate_aw) 26 | export(ddbs_intersection) 27 | export(ddbs_intersects) 28 | export(ddbs_intersects_extent) 29 | export(ddbs_is_simple) 30 | export(ddbs_is_valid) 31 | export(ddbs_join) 32 | export(ddbs_length) 33 | export(ddbs_list_tables) 34 | export(ddbs_load) 35 | export(ddbs_make_valid) 36 | export(ddbs_overlaps) 37 | export(ddbs_predicate) 38 | export(ddbs_read_vector) 39 | export(ddbs_register_vector) 40 | export(ddbs_simplify) 41 | export(ddbs_stop_conn) 42 | export(ddbs_touches) 43 | export(ddbs_within) 44 | export(ddbs_within_properly) 45 | export(ddbs_write_vector) 46 | -------------------------------------------------------------------------------- /man/ddbs_glimpse.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/ddbs_utils.R 3 | \name{ddbs_glimpse} 4 | \alias{ddbs_glimpse} 5 | \title{Check first rows of the data} 6 | \usage{ 7 | ddbs_glimpse( 8 | conn, 9 | name, 10 | crs = NULL, 11 | crs_column = "crs_duckspatial", 12 | quiet = FALSE 13 | ) 14 | } 15 | \arguments{ 16 | \item{conn}{A connection object to a DuckDB database} 17 | 18 | \item{name}{A character string of length one specifying the name of the table, 19 | or a character string of length two specifying the schema and table 20 | names.} 21 | 22 | \item{crs}{The coordinates reference system of the data. Specify if the data 23 | doesn't have a \code{crs_column}, and you know the CRS.} 24 | 25 | \item{crs_column}{a character string of length one specifying the column 26 | storing the CRS (created automatically by \code{\link{ddbs_write_vector}}). 27 | Set to \code{NULL} if absent.} 28 | 29 | \item{quiet}{A logical value. If \code{TRUE}, suppresses any informational messages. 30 | Defaults to \code{FALSE}.} 31 | } 32 | \value{ 33 | \code{sf} object 34 | } 35 | \description{ 36 | Check first rows of the data 37 | } 38 | \examples{ 39 | \dontshow{if (interactive()) withAutoprint(\{ # examplesIf} 40 | ## TODO 41 | \dontshow{\}) # examplesIf} 42 | } 43 | -------------------------------------------------------------------------------- /man/ddbs_crs.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/ddbs_utils.R 3 | \name{ddbs_crs} 4 | \alias{ddbs_crs} 5 | \title{Check CRS of a table} 6 | \usage{ 7 | ddbs_crs(conn, name, crs_column = "crs_duckspatial") 8 | } 9 | \arguments{ 10 | \item{conn}{A connection object to a DuckDB database} 11 | 12 | \item{name}{A character string of length one specifying the name of the table, 13 | or a character string of length two specifying the schema and table 14 | names.} 15 | 16 | \item{crs_column}{a character string of length one specifying the column 17 | storing the CRS (created automatically by \code{\link{ddbs_write_vector}})} 18 | } 19 | \value{ 20 | CRS object 21 | } 22 | \description{ 23 | Check CRS of a table 24 | } 25 | \examples{ 26 | \dontshow{if (interactive()) withAutoprint(\{ # examplesIf} 27 | ## load packages 28 | library(duckdb) 29 | library(duckspatial) 30 | library(sf) 31 | 32 | # create a duckdb database in memory (with spatial extension) 33 | conn <- ddbs_create_conn(dbdir = "memory") 34 | 35 | ## read data 36 | countries_sf <- st_read(system.file("spatial/countries.geojson", package = "duckspatial")) 37 | 38 | ## store in duckdb 39 | ddbs_write_vector(conn, countries_sf, "countries") 40 | 41 | ## check CRS 42 | ddbs_crs(conn, "countries") 43 | \dontshow{\}) # examplesIf} 44 | } 45 | -------------------------------------------------------------------------------- /.github/workflows/check.yaml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - main 5 | pull_request: 6 | branches: 7 | - main 8 | 9 | name: check 10 | 11 | jobs: 12 | check: 13 | runs-on: ${{ matrix.config.os }} 14 | 15 | name: ${{ matrix.config.os }} (${{ matrix.config.r }}) 16 | 17 | strategy: 18 | fail-fast: false 19 | matrix: 20 | config: 21 | - {os: windows-latest, r: 'release'} 22 | - {os: macos-latest, r: 'release'} 23 | - {os: ubuntu-22.04, r: 'devel', rspm: "https://packagemanager.rstudio.com/cran/__linux__/jammy/latest"} 24 | - {os: ubuntu-22.04, r: 'release', rspm: "https://packagemanager.rstudio.com/cran/__linux__/jammy/latest"} 25 | - {os: ubuntu-22.04, r: 'oldrel', rspm: "https://packagemanager.rstudio.com/cran/__linux__/jammy/latest"} 26 | 27 | env: 28 | RSPM: ${{ matrix.config.rspm }} 29 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 30 | 31 | steps: 32 | - uses: actions/checkout@v2 33 | 34 | - uses: r-lib/actions/setup-r@v2 35 | with: 36 | r-version: ${{ matrix.config.r }} 37 | 38 | - uses: r-lib/actions/setup-pandoc@v2 39 | 40 | - uses: r-lib/actions/setup-r-dependencies@v2 41 | with: 42 | extra-packages: any::rcmdcheck 43 | needs: check 44 | 45 | - uses: r-lib/actions/check-r-package@v2 46 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Type: Package 2 | Package: duckspatial 3 | Title: R Interface to 'DuckDB' Database with Spatial Extension 4 | Version: 0.2.0999 5 | Authors@R: c( 6 | person("Adrián", "Cidre González", email = "adrian.cidre@gmail.com", role = c("aut", "cre")), 7 | person("Rafael H. M.", "Pereira", , "rafa.pereira.br@gmail.com", role = "aut", 8 | comment = c(ORCID = "0000-0003-2125-7465")), 9 | person("Egor", "Kotov", , "kotov.egor@gmail.com", role = "aut", 10 | comment = c(ORCID = "0000-0001-6690-5345")) 11 | ) 12 | Description: Provides an interface between R and the 'DuckDB' (see ) 13 | database with spatial extensions. It supports reading, writing, and 14 | performing some geometric operations. 15 | URL: https://cidree.github.io/duckspatial/, https://github.com/Cidree/duckspatial 16 | BugReports: https://github.com/Cidree/duckspatial/issues 17 | License: GPL (>= 3) 18 | Depends: 19 | R (>= 4.1.0) 20 | Imports: 21 | arrow, 22 | cli, 23 | duckdb, 24 | geoarrow, 25 | DBI, 26 | glue, 27 | sf, 28 | wk, 29 | uuid 30 | Suggests: 31 | areal, 32 | bench, 33 | dplyr, 34 | ggplot2 (>= 3.3.1), 35 | knitr, 36 | rmarkdown, 37 | testthat (>= 3.0.0) 38 | VignetteBuilder: 39 | knitr 40 | RoxygenNote: 7.3.3 41 | Roxygen: list(markdown = TRUE) 42 | Config/testthat/edition: 3 43 | Encoding: UTF-8 44 | LazyData: true 45 | -------------------------------------------------------------------------------- /.github/workflows/pkgdown.yaml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | on: 4 | push: 5 | branches: [main, master] 6 | pull_request: 7 | release: 8 | types: [published] 9 | workflow_dispatch: 10 | 11 | name: pkgdown.yaml 12 | 13 | permissions: read-all 14 | 15 | jobs: 16 | pkgdown: 17 | runs-on: ubuntu-latest 18 | # Only restrict concurrency for non-PR jobs 19 | concurrency: 20 | group: pkgdown-${{ github.event_name != 'pull_request' || github.run_id }} 21 | env: 22 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 23 | permissions: 24 | contents: write 25 | steps: 26 | - uses: actions/checkout@v4 27 | 28 | - uses: r-lib/actions/setup-pandoc@v2 29 | 30 | - uses: r-lib/actions/setup-r@v2 31 | with: 32 | use-public-rspm: true 33 | 34 | - uses: r-lib/actions/setup-r-dependencies@v2 35 | with: 36 | extra-packages: any::pkgdown, local::. 37 | needs: website 38 | 39 | - name: Build site 40 | run: pkgdown::build_site_github_pages(new_process = FALSE, install = FALSE) 41 | shell: Rscript {0} 42 | 43 | - name: Deploy to GitHub pages 🚀 44 | if: github.event_name != 'pull_request' 45 | uses: JamesIves/github-pages-deploy-action@v4.5.0 46 | with: 47 | clean: false 48 | branch: gh-pages 49 | folder: docs 50 | -------------------------------------------------------------------------------- /man/ddbs_register_vector.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/db_register.R 3 | \name{ddbs_register_vector} 4 | \alias{ddbs_register_vector} 5 | \title{Register an SF Object as an Arrow Table in DuckDB} 6 | \usage{ 7 | ddbs_register_vector(conn, data, name, overwrite = FALSE, quiet = FALSE) 8 | } 9 | \arguments{ 10 | \item{conn}{A connection object to a DuckDB database} 11 | 12 | \item{data}{A \code{sf} object to write to the DuckDB database, or the path to 13 | a local file that can be read with \code{ST_READ}} 14 | 15 | \item{name}{A character string of length one specifying the name of the table, 16 | or a character string of length two specifying the schema and table 17 | names. If \code{NULL} (the default), the function returns the result as an 18 | \code{sf} object} 19 | 20 | \item{overwrite}{Boolean. whether to overwrite the existing table if it exists. Defaults 21 | to \code{FALSE}. This argument is ignored when \code{name} is \code{NULL}.} 22 | 23 | \item{quiet}{A logical value. If \code{TRUE}, suppresses any informational messages. 24 | Defaults to \code{FALSE}.} 25 | } 26 | \value{ 27 | TRUE (invisibly) on successful registration. 28 | } 29 | \description{ 30 | This function registers a Simple Features (SF) object as a temporary Arrow-backed 31 | view in a DuckDB database. This is a zero-copy operation and is significantly 32 | faster than \code{ddbs_write_vector} for workflows that do not require data to be 33 | permanently materialized in the database. 34 | } 35 | \examples{ 36 | \dontrun{ 37 | library(duckdb) 38 | library(duckspatial) 39 | library(sf) 40 | 41 | conn <- ddbs_create_conn("memory") 42 | 43 | nc <- st_read(system.file("shape/nc.shp", package="sf"), quiet = TRUE) 44 | 45 | ddbs_register_vector(conn, nc, "nc_arrow_view") 46 | 47 | dbGetQuery(conn, "SELECT COUNT(*) FROM nc_arrow_view;") 48 | 49 | ddbs_stop_conn(conn, shutdown = TRUE) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /docs/deps/bootstrap-toc-1.0.1/bootstrap-toc.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Table of Contents v1.0.1 (http://afeld.github.io/bootstrap-toc/) 3 | * Copyright 2015 Aidan Feldman 4 | * Licensed under MIT (https://github.com/afeld/bootstrap-toc/blob/gh-pages/LICENSE.md) */ 5 | !function(a){"use strict";window.Toc={helpers:{findOrFilter:function(e,t){var n=e.find(t);return e.filter(t).add(n).filter(":not([data-toc-skip])")},generateUniqueIdBase:function(e){return a(e).text().trim().replace(/\'/gi,"").replace(/[& +$,:;=?@"#{}|^~[`%!'<>\]\.\/\(\)\*\\\n\t\b\v]/g,"-").replace(/-{2,}/g,"-").substring(0,64).replace(/^-+|-+$/gm,"").toLowerCase()||e.tagName.toLowerCase()},generateUniqueId:function(e){for(var t=this.generateUniqueIdBase(e),n=0;;n++){var r=t;if(0')},createChildNavList:function(e){var t=this.createNavList();return e.append(t),t},generateNavEl:function(e,t){var n=a('');n.attr("href","#"+e),n.text(t);var r=a("
  • ");return r.append(n),r},generateNavItem:function(e){var t=this.generateAnchor(e),n=a(e),r=n.data("toc-text")||n.text();return this.generateNavEl(t,r)},getTopLevel:function(e){for(var t=1;t<=6;t++){if(1 61 | filter(CNTR_ID \%in\% c("PT", "ES", "FR", "IT")) 62 | 63 | ddbs_equals(countries_sf, countries_sf, id_x = "NAME_ENGL") 64 | } 65 | \seealso{ 66 | \code{\link[=ddbs_predicate]{ddbs_predicate()}} for other spatial predicates. 67 | } 68 | -------------------------------------------------------------------------------- /man/ddbs_write_vector.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/ddbs_write.R 3 | \name{ddbs_write_vector} 4 | \alias{ddbs_write_vector} 5 | \title{Write an SF Object to a DuckDB Database} 6 | \usage{ 7 | ddbs_write_vector( 8 | conn, 9 | data, 10 | name, 11 | overwrite = FALSE, 12 | temp_view = FALSE, 13 | quiet = FALSE 14 | ) 15 | } 16 | \arguments{ 17 | \item{conn}{A connection object to a DuckDB database} 18 | 19 | \item{data}{A \code{sf} object to write to the DuckDB database, or the path to 20 | a local file that can be read with \code{ST_READ}} 21 | 22 | \item{name}{A character string of length one specifying the name of the table, 23 | or a character string of length two specifying the schema and table 24 | names. If \code{NULL} (the default), the function returns the result as an 25 | \code{sf} object} 26 | 27 | \item{overwrite}{Boolean. whether to overwrite the existing table if it exists. Defaults 28 | to \code{FALSE}. This argument is ignored when \code{name} is \code{NULL}.} 29 | 30 | \item{temp_view}{If \code{TRUE}, registers the \code{sf} object as a temporary Arrow-backed database 'view' using \code{ddbs_register_vector} instead of creating a persistent table. This is much faster but the view will not persist. Defaults to \code{FALSE}.} 31 | 32 | \item{quiet}{A logical value. If \code{TRUE}, suppresses any informational messages. 33 | Defaults to \code{FALSE}.} 34 | } 35 | \value{ 36 | TRUE (invisibly) for successful import 37 | } 38 | \description{ 39 | This function writes a Simple Features (SF) object into a DuckDB database as a new table. 40 | The table is created in the specified schema of the DuckDB database. 41 | } 42 | \examples{ 43 | \dontshow{if (interactive()) withAutoprint(\{ # examplesIf} 44 | ## load packages 45 | library(duckdb) 46 | library(duckspatial) 47 | library(sf) 48 | 49 | # create a duckdb database in memory (with spatial extension) 50 | conn <- ddbs_create_conn(dbdir = "memory") 51 | 52 | ## create random points 53 | random_points <- data.frame( 54 | id = 1:5, 55 | x = runif(5, min = -180, max = 180), # Random longitude values 56 | y = runif(5, min = -90, max = 90) # Random latitude values 57 | ) 58 | 59 | ## convert to sf 60 | sf_points <- st_as_sf(random_points, coords = c("x", "y"), crs = 4326) 61 | 62 | ## insert data into the database 63 | ddbs_write_vector(conn, sf_points, "points") 64 | 65 | ## read data back into R 66 | ddbs_read_vector(conn, "points", crs = 4326) 67 | 68 | ## disconnect from db 69 | dbDisconnect(conn) 70 | \dontshow{\}) # examplesIf} 71 | } 72 | -------------------------------------------------------------------------------- /man/ddbs_touches.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/ddbs_predicates.R 3 | \name{ddbs_touches} 4 | \alias{ddbs_touches} 5 | \title{Spatial touches predicate} 6 | \usage{ 7 | ddbs_touches( 8 | x, 9 | y, 10 | conn = NULL, 11 | id_x = NULL, 12 | id_y = NULL, 13 | sparse = TRUE, 14 | quiet = FALSE 15 | ) 16 | } 17 | \arguments{ 18 | \item{x}{An \code{sf} spatial object. Alternatively, it can be a string with the 19 | name of a table with geometry column within the DuckDB database \code{conn}. 20 | Data is returned from this object.} 21 | 22 | \item{y}{An \code{sf} spatial object. Alternatively, it can be a string with the 23 | name of a table with geometry column within the DuckDB database \code{conn}.} 24 | 25 | \item{conn}{A connection object to a DuckDB database. If \code{NULL}, the function 26 | runs on a temporary DuckDB database.} 27 | 28 | \item{id_x}{Character; optional name of the column in \code{x} whose values will 29 | be used to name the list elements. If \code{NULL}, integer row numbers of \code{x} are used.} 30 | 31 | \item{id_y}{Character; optional name of the column in \code{y} whose values will 32 | replace the integer indices returned in each element of the list.} 33 | 34 | \item{sparse}{A logical value. If \code{TRUE}, it returns a sparse index list. If \code{FALSE}, 35 | it returns a dense logical matrix.} 36 | 37 | \item{quiet}{A logical value. If \code{TRUE}, suppresses any informational messages. 38 | Defaults to \code{FALSE}.} 39 | } 40 | \value{ 41 | A list where each element contains indices (or IDs) of geometries in \code{y} that 42 | touch the corresponding geometry in \code{x}. See \code{\link[=ddbs_predicate]{ddbs_predicate()}} for details. 43 | } 44 | \description{ 45 | Tests if geometries in \code{x} touch geometries in \code{y}. Returns TRUE if 46 | geometries share a boundary but their interiors do not intersect. 47 | } 48 | \details{ 49 | This is a convenience wrapper around \code{\link[=ddbs_predicate]{ddbs_predicate()}} with 50 | \code{predicate = "touches"}. 51 | } 52 | \examples{ 53 | 54 | ## load packages 55 | library(dplyr) 56 | library(duckspatial) 57 | library(sf) 58 | 59 | ## read countries data, and rivers 60 | countries_sf <- read_sf(system.file("spatial/countries.geojson", package = "duckspatial")) 61 | countries_filter_sf <- countries_sf |> filter(CNTR_ID \%in\% c("PT", "ES", "FR", "IT")) 62 | 63 | # Find neighboring countries 64 | ddbs_touches(countries_filter_sf, countries_sf, id_x = "NAME_ENGL", id_y = "NAME_ENGL") 65 | } 66 | \seealso{ 67 | \code{\link[=ddbs_predicate]{ddbs_predicate()}} for other spatial predicates. 68 | } 69 | -------------------------------------------------------------------------------- /docs/deps/Source_Code_Pro-0.4.9/font.css: -------------------------------------------------------------------------------- 1 | /* cyrillic-ext */ 2 | @font-face { 3 | font-family: 'Source Code Pro'; 4 | font-style: normal; 5 | font-weight: 400; 6 | font-display: swap; 7 | src: url(HI_diYsKILxRpg3hIP6sJ7fM7PqPMcMnZFqUwX28DMyQtMRrTEUc.woff2) format('woff2'); 8 | unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; 9 | } 10 | /* cyrillic */ 11 | @font-face { 12 | font-family: 'Source Code Pro'; 13 | font-style: normal; 14 | font-weight: 400; 15 | font-display: swap; 16 | src: url(HI_diYsKILxRpg3hIP6sJ7fM7PqPMcMnZFqUwX28DMyQtM1rTEUc.woff2) format('woff2'); 17 | unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; 18 | } 19 | /* greek-ext */ 20 | @font-face { 21 | font-family: 'Source Code Pro'; 22 | font-style: normal; 23 | font-weight: 400; 24 | font-display: swap; 25 | src: url(HI_diYsKILxRpg3hIP6sJ7fM7PqPMcMnZFqUwX28DMyQtMVrTEUc.woff2) format('woff2'); 26 | unicode-range: U+1F00-1FFF; 27 | } 28 | /* greek */ 29 | @font-face { 30 | font-family: 'Source Code Pro'; 31 | font-style: normal; 32 | font-weight: 400; 33 | font-display: swap; 34 | src: url(HI_diYsKILxRpg3hIP6sJ7fM7PqPMcMnZFqUwX28DMyQtMprTEUc.woff2) format('woff2'); 35 | unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF; 36 | } 37 | /* vietnamese */ 38 | @font-face { 39 | font-family: 'Source Code Pro'; 40 | font-style: normal; 41 | font-weight: 400; 42 | font-display: swap; 43 | src: url(HI_diYsKILxRpg3hIP6sJ7fM7PqPMcMnZFqUwX28DMyQtMZrTEUc.woff2) format('woff2'); 44 | unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; 45 | } 46 | /* latin-ext */ 47 | @font-face { 48 | font-family: 'Source Code Pro'; 49 | font-style: normal; 50 | font-weight: 400; 51 | font-display: swap; 52 | src: url(HI_diYsKILxRpg3hIP6sJ7fM7PqPMcMnZFqUwX28DMyQtMdrTEUc.woff2) format('woff2'); 53 | unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; 54 | } 55 | /* latin */ 56 | @font-face { 57 | font-family: 'Source Code Pro'; 58 | font-style: normal; 59 | font-weight: 400; 60 | font-display: swap; 61 | src: url(HI_diYsKILxRpg3hIP6sJ7fM7PqPMcMnZFqUwX28DMyQtMlrTA.woff2) format('woff2'); 62 | unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; 63 | } 64 | -------------------------------------------------------------------------------- /man/ddbs_disjoint.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/ddbs_predicates.R 3 | \name{ddbs_disjoint} 4 | \alias{ddbs_disjoint} 5 | \title{Spatial disjoint predicate} 6 | \usage{ 7 | ddbs_disjoint( 8 | x, 9 | y, 10 | conn = NULL, 11 | id_x = NULL, 12 | id_y = NULL, 13 | sparse = TRUE, 14 | quiet = FALSE 15 | ) 16 | } 17 | \arguments{ 18 | \item{x}{An \code{sf} spatial object. Alternatively, it can be a string with the 19 | name of a table with geometry column within the DuckDB database \code{conn}. 20 | Data is returned from this object.} 21 | 22 | \item{y}{An \code{sf} spatial object. Alternatively, it can be a string with the 23 | name of a table with geometry column within the DuckDB database \code{conn}.} 24 | 25 | \item{conn}{A connection object to a DuckDB database. If \code{NULL}, the function 26 | runs on a temporary DuckDB database.} 27 | 28 | \item{id_x}{Character; optional name of the column in \code{x} whose values will 29 | be used to name the list elements. If \code{NULL}, integer row numbers of \code{x} are used.} 30 | 31 | \item{id_y}{Character; optional name of the column in \code{y} whose values will 32 | replace the integer indices returned in each element of the list.} 33 | 34 | \item{sparse}{A logical value. If \code{TRUE}, it returns a sparse index list. If \code{FALSE}, 35 | it returns a dense logical matrix.} 36 | 37 | \item{quiet}{A logical value. If \code{TRUE}, suppresses any informational messages. 38 | Defaults to \code{FALSE}.} 39 | } 40 | \value{ 41 | A list where each element contains indices (or IDs) of geometries in \code{y} that 42 | are disjoint from the corresponding geometry in \code{x}. See \code{\link[=ddbs_predicate]{ddbs_predicate()}} for details. 43 | } 44 | \description{ 45 | Tests if geometries in \code{x} are disjoint from geometries in \code{y}. Returns TRUE if 46 | geometries have no points in common. 47 | } 48 | \details{ 49 | This is a convenience wrapper around \code{\link[=ddbs_predicate]{ddbs_predicate()}} with 50 | \code{predicate = "disjoint"}. 51 | } 52 | \examples{ 53 | 54 | ## load packages 55 | library(dplyr) 56 | library(duckspatial) 57 | library(sf) 58 | 59 | ## read countries data, and rivers 60 | countries_sf <- read_sf(system.file("spatial/countries.geojson", package = "duckspatial")) |> 61 | filter(CNTR_ID \%in\% c("PT", "ES", "FR", "IT")) 62 | rivers_sf <- st_read(system.file("spatial/rivers.geojson", package = "duckspatial")) |> 63 | st_transform(st_crs(countries_sf)) 64 | 65 | ddbs_disjoint(countries_sf, rivers_sf, id_x = "NAME_ENGL") 66 | } 67 | \seealso{ 68 | \code{\link[=ddbs_predicate]{ddbs_predicate()}} for other spatial predicates. 69 | } 70 | -------------------------------------------------------------------------------- /man/ddbs_intersects.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/ddbs_predicates.R 3 | \name{ddbs_intersects} 4 | \alias{ddbs_intersects} 5 | \title{Spatial intersects predicate} 6 | \usage{ 7 | ddbs_intersects( 8 | x, 9 | y, 10 | conn = NULL, 11 | id_x = NULL, 12 | id_y = NULL, 13 | sparse = TRUE, 14 | quiet = FALSE 15 | ) 16 | } 17 | \arguments{ 18 | \item{x}{An \code{sf} spatial object. Alternatively, it can be a string with the 19 | name of a table with geometry column within the DuckDB database \code{conn}. 20 | Data is returned from this object.} 21 | 22 | \item{y}{An \code{sf} spatial object. Alternatively, it can be a string with the 23 | name of a table with geometry column within the DuckDB database \code{conn}.} 24 | 25 | \item{conn}{A connection object to a DuckDB database. If \code{NULL}, the function 26 | runs on a temporary DuckDB database.} 27 | 28 | \item{id_x}{Character; optional name of the column in \code{x} whose values will 29 | be used to name the list elements. If \code{NULL}, integer row numbers of \code{x} are used.} 30 | 31 | \item{id_y}{Character; optional name of the column in \code{y} whose values will 32 | replace the integer indices returned in each element of the list.} 33 | 34 | \item{sparse}{A logical value. If \code{TRUE}, it returns a sparse index list. If \code{FALSE}, 35 | it returns a dense logical matrix.} 36 | 37 | \item{quiet}{A logical value. If \code{TRUE}, suppresses any informational messages. 38 | Defaults to \code{FALSE}.} 39 | } 40 | \value{ 41 | A list where each element contains indices (or IDs) of geometries in \code{y} that 42 | intersect the corresponding geometry in \code{x}. See \code{\link[=ddbs_predicate]{ddbs_predicate()}} for details. 43 | } 44 | \description{ 45 | Tests if geometries in \code{x} intersect geometries in \code{y}. Returns TRUE if 46 | geometries share at least one point in common. 47 | } 48 | \details{ 49 | This is a convenience wrapper around \code{\link[=ddbs_predicate]{ddbs_predicate()}} with 50 | \code{predicate = "intersects"}. 51 | } 52 | \examples{ 53 | 54 | ## load packages 55 | library(dplyr) 56 | library(duckspatial) 57 | library(sf) 58 | 59 | ## read countries data, and rivers 60 | countries_sf <- read_sf(system.file("spatial/countries.geojson", package = "duckspatial")) |> 61 | filter(CNTR_ID \%in\% c("PT", "ES", "FR", "IT")) 62 | rivers_sf <- st_read(system.file("spatial/rivers.geojson", package = "duckspatial")) |> 63 | st_transform(st_crs(countries_sf)) 64 | 65 | ddbs_intersects(countries_sf, rivers_sf, id_x = "NAME_ENGL") 66 | } 67 | \seealso{ 68 | \code{\link[=ddbs_predicate]{ddbs_predicate()}} for other spatial predicates. 69 | } 70 | -------------------------------------------------------------------------------- /man/ddbs_read_vector.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/ddbs_read.R 3 | \name{ddbs_read_vector} 4 | \alias{ddbs_read_vector} 5 | \title{Load spatial vector data from DuckDB into R} 6 | \usage{ 7 | ddbs_read_vector( 8 | conn, 9 | name, 10 | crs = NULL, 11 | crs_column = "crs_duckspatial", 12 | clauses = NULL, 13 | quiet = FALSE 14 | ) 15 | } 16 | \arguments{ 17 | \item{conn}{A connection object to a DuckDB database} 18 | 19 | \item{name}{A character string of length one specifying the name of the table, 20 | or a character string of length two specifying the schema and table 21 | names. If \code{NULL} (the default), the function returns the result as an 22 | \code{sf} object} 23 | 24 | \item{crs}{The coordinates reference system of the data. Specify if the data 25 | doesn't have a \code{crs_column}, and you know the CRS.} 26 | 27 | \item{crs_column}{a character string of length one specifying the column 28 | storing the CRS (created automatically by \code{\link{ddbs_write_vector}}). 29 | Set to \code{NULL} if absent.} 30 | 31 | \item{clauses}{character, additional SQL code to modify the query from the 32 | table (e.g. "WHERE ...", "ORDER BY...")} 33 | 34 | \item{quiet}{A logical value. If \code{TRUE}, suppresses any informational messages. 35 | Defaults to \code{FALSE}.} 36 | } 37 | \value{ 38 | an sf object 39 | } 40 | \description{ 41 | Retrieves the data from a DuckDB table, view, or Arrow view with a geometry 42 | column, and converts it to an R \code{sf} object. This function works with 43 | both persistent tables created by \code{ddbs_write_vector} and temporary 44 | Arrow views created by \code{ddbs_register_vector}. 45 | } 46 | \examples{ 47 | \dontshow{if (interactive()) withAutoprint(\{ # examplesIf} 48 | ## load packages 49 | library(duckdb) 50 | library(duckspatial) 51 | library(sf) 52 | 53 | # create a duckdb database in memory (with spatial extension) 54 | conn <- ddbs_create_conn(dbdir = "memory") 55 | 56 | ## create random points 57 | random_points <- data.frame( 58 | id = 1:5, 59 | x = runif(5, min = -180, max = 180), 60 | y = runif(5, min = -90, max = 90) 61 | ) 62 | 63 | ## convert to sf 64 | sf_points <- st_as_sf(random_points, coords = c("x", "y"), crs = 4326) 65 | 66 | ## Example 1: Write and read persistent table 67 | ddbs_write_vector(conn, sf_points, "points") 68 | ddbs_read_vector(conn, "points", crs = 4326) 69 | 70 | ## Example 2: Register and read Arrow view (faster, temporary) 71 | ddbs_register_vector(conn, sf_points, "points_view") 72 | ddbs_read_vector(conn, "points_view", crs = 4326) 73 | 74 | ## disconnect from db 75 | ddbs_stop_conn(conn) 76 | \dontshow{\}) # examplesIf} 77 | } 78 | -------------------------------------------------------------------------------- /man/ddbs_crosses.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/ddbs_predicates.R 3 | \name{ddbs_crosses} 4 | \alias{ddbs_crosses} 5 | \title{Spatial crosses predicate} 6 | \usage{ 7 | ddbs_crosses( 8 | x, 9 | y, 10 | conn = NULL, 11 | id_x = NULL, 12 | id_y = NULL, 13 | sparse = TRUE, 14 | quiet = FALSE 15 | ) 16 | } 17 | \arguments{ 18 | \item{x}{An \code{sf} spatial object. Alternatively, it can be a string with the 19 | name of a table with geometry column within the DuckDB database \code{conn}. 20 | Data is returned from this object.} 21 | 22 | \item{y}{An \code{sf} spatial object. Alternatively, it can be a string with the 23 | name of a table with geometry column within the DuckDB database \code{conn}.} 24 | 25 | \item{conn}{A connection object to a DuckDB database. If \code{NULL}, the function 26 | runs on a temporary DuckDB database.} 27 | 28 | \item{id_x}{Character; optional name of the column in \code{x} whose values will 29 | be used to name the list elements. If \code{NULL}, integer row numbers of \code{x} are used.} 30 | 31 | \item{id_y}{Character; optional name of the column in \code{y} whose values will 32 | replace the integer indices returned in each element of the list.} 33 | 34 | \item{sparse}{A logical value. If \code{TRUE}, it returns a sparse index list. If \code{FALSE}, 35 | it returns a dense logical matrix.} 36 | 37 | \item{quiet}{A logical value. If \code{TRUE}, suppresses any informational messages. 38 | Defaults to \code{FALSE}.} 39 | } 40 | \value{ 41 | A list where each element contains indices (or IDs) of geometries in \code{y} that 42 | cross the corresponding geometry in \code{x}. See \code{\link[=ddbs_predicate]{ddbs_predicate()}} for details. 43 | } 44 | \description{ 45 | Tests if geometries in \code{x} cross geometries in \code{y}. Returns TRUE if 46 | geometries have some but not all interior points in common. 47 | } 48 | \details{ 49 | This is a convenience wrapper around \code{\link[=ddbs_predicate]{ddbs_predicate()}} with 50 | \code{predicate = "crosses"}. 51 | } 52 | \examples{ 53 | 54 | ## load packages 55 | library(dplyr) 56 | library(duckspatial) 57 | library(sf) 58 | 59 | ## read countries data, and rivers 60 | countries_sf <- read_sf(system.file("spatial/countries.geojson", package = "duckspatial")) |> 61 | filter(CNTR_ID \%in\% c("PT", "ES", "FR", "IT")) 62 | rivers_sf <- st_read(system.file("spatial/rivers.geojson", package = "duckspatial")) |> 63 | st_transform(st_crs(countries_sf)) 64 | 65 | ddbs_crosses(rivers_sf, countries_sf, id_x = "RIVER_NAME", id_y = "NAME_ENGL") 66 | } 67 | \seealso{ 68 | \code{\link[=ddbs_predicate]{ddbs_predicate()}} for other spatial predicates. 69 | } 70 | -------------------------------------------------------------------------------- /man/ddbs_within.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/ddbs_predicates.R 3 | \name{ddbs_within} 4 | \alias{ddbs_within} 5 | \title{Spatial within predicate} 6 | \usage{ 7 | ddbs_within( 8 | x, 9 | y, 10 | conn = NULL, 11 | id_x = NULL, 12 | id_y = NULL, 13 | sparse = TRUE, 14 | quiet = FALSE 15 | ) 16 | } 17 | \arguments{ 18 | \item{x}{An \code{sf} spatial object. Alternatively, it can be a string with the 19 | name of a table with geometry column within the DuckDB database \code{conn}. 20 | Data is returned from this object.} 21 | 22 | \item{y}{An \code{sf} spatial object. Alternatively, it can be a string with the 23 | name of a table with geometry column within the DuckDB database \code{conn}.} 24 | 25 | \item{conn}{A connection object to a DuckDB database. If \code{NULL}, the function 26 | runs on a temporary DuckDB database.} 27 | 28 | \item{id_x}{Character; optional name of the column in \code{x} whose values will 29 | be used to name the list elements. If \code{NULL}, integer row numbers of \code{x} are used.} 30 | 31 | \item{id_y}{Character; optional name of the column in \code{y} whose values will 32 | replace the integer indices returned in each element of the list.} 33 | 34 | \item{sparse}{A logical value. If \code{TRUE}, it returns a sparse index list. If \code{FALSE}, 35 | it returns a dense logical matrix.} 36 | 37 | \item{quiet}{A logical value. If \code{TRUE}, suppresses any informational messages. 38 | Defaults to \code{FALSE}.} 39 | } 40 | \value{ 41 | A list where each element contains indices (or IDs) of geometries in \code{y} that 42 | contain the corresponding geometry in \code{x}. See \code{\link[=ddbs_predicate]{ddbs_predicate()}} for details. 43 | } 44 | \description{ 45 | Tests if geometries in \code{x} are within geometries in \code{y}. Returns TRUE if 46 | geometry \code{x} is completely inside geometry \code{y}. 47 | } 48 | \details{ 49 | This is a convenience wrapper around \code{\link[=ddbs_predicate]{ddbs_predicate()}} with 50 | \code{predicate = "within"}. 51 | } 52 | \examples{ 53 | 54 | ## load packages 55 | library(dplyr) 56 | library(duckspatial) 57 | library(sf) 58 | 59 | ## read countries data, and rivers 60 | countries_sf <- read_sf(system.file("spatial/countries.geojson", package = "duckspatial")) |> 61 | filter(CNTR_ID \%in\% c("PT", "ES", "FR", "IT")) 62 | rivers_sf <- st_read(system.file("spatial/rivers.geojson", package = "duckspatial")) |> 63 | st_transform(st_crs(countries_sf)) 64 | 65 | ddbs_within(rivers_sf, countries_sf, id_x = "RIVER_NAME", id_y = "NAME_ENGL") 66 | } 67 | \seealso{ 68 | \code{\link[=ddbs_predicate]{ddbs_predicate()}} for other spatial predicates. 69 | } 70 | -------------------------------------------------------------------------------- /man/ddbs_contains.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/ddbs_predicates.R 3 | \name{ddbs_contains} 4 | \alias{ddbs_contains} 5 | \title{Spatial contains predicate} 6 | \usage{ 7 | ddbs_contains( 8 | x, 9 | y, 10 | conn = NULL, 11 | id_x = NULL, 12 | id_y = NULL, 13 | sparse = TRUE, 14 | quiet = FALSE 15 | ) 16 | } 17 | \arguments{ 18 | \item{x}{An \code{sf} spatial object. Alternatively, it can be a string with the 19 | name of a table with geometry column within the DuckDB database \code{conn}. 20 | Data is returned from this object.} 21 | 22 | \item{y}{An \code{sf} spatial object. Alternatively, it can be a string with the 23 | name of a table with geometry column within the DuckDB database \code{conn}.} 24 | 25 | \item{conn}{A connection object to a DuckDB database. If \code{NULL}, the function 26 | runs on a temporary DuckDB database.} 27 | 28 | \item{id_x}{Character; optional name of the column in \code{x} whose values will 29 | be used to name the list elements. If \code{NULL}, integer row numbers of \code{x} are used.} 30 | 31 | \item{id_y}{Character; optional name of the column in \code{y} whose values will 32 | replace the integer indices returned in each element of the list.} 33 | 34 | \item{sparse}{A logical value. If \code{TRUE}, it returns a sparse index list. If \code{FALSE}, 35 | it returns a dense logical matrix.} 36 | 37 | \item{quiet}{A logical value. If \code{TRUE}, suppresses any informational messages. 38 | Defaults to \code{FALSE}.} 39 | } 40 | \value{ 41 | A list where each element contains indices (or IDs) of geometries in \code{y} that 42 | are contained by the corresponding geometry in \code{x}. See \code{\link[=ddbs_predicate]{ddbs_predicate()}} for details. 43 | } 44 | \description{ 45 | Tests if geometries in \code{x} contain geometries in \code{y}. Returns TRUE if 46 | geometry \code{x} completely contains geometry \code{y}. 47 | } 48 | \details{ 49 | This is a convenience wrapper around \code{\link[=ddbs_predicate]{ddbs_predicate()}} with 50 | \code{predicate = "contains"}. 51 | } 52 | \examples{ 53 | 54 | ## load packages 55 | library(dplyr) 56 | library(duckspatial) 57 | library(sf) 58 | 59 | ## read countries data, and rivers 60 | countries_sf <- read_sf(system.file("spatial/countries.geojson", package = "duckspatial")) |> 61 | filter(CNTR_ID \%in\% c("PT", "ES", "FR", "IT")) 62 | rivers_sf <- st_read(system.file("spatial/rivers.geojson", package = "duckspatial")) |> 63 | st_transform(st_crs(countries_sf)) 64 | 65 | ddbs_contains(countries_sf, rivers_sf, id_x = "NAME_ENGL", id_y = "RIVER_NAME") 66 | } 67 | \seealso{ 68 | \code{\link[=ddbs_predicate]{ddbs_predicate()}} for other spatial predicates. 69 | } 70 | -------------------------------------------------------------------------------- /man/ddbs_covers.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/ddbs_predicates.R 3 | \name{ddbs_covers} 4 | \alias{ddbs_covers} 5 | \title{Spatial covers predicate} 6 | \usage{ 7 | ddbs_covers( 8 | x, 9 | y, 10 | conn = NULL, 11 | id_x = NULL, 12 | id_y = NULL, 13 | sparse = TRUE, 14 | quiet = FALSE 15 | ) 16 | } 17 | \arguments{ 18 | \item{x}{An \code{sf} spatial object. Alternatively, it can be a string with the 19 | name of a table with geometry column within the DuckDB database \code{conn}. 20 | Data is returned from this object.} 21 | 22 | \item{y}{An \code{sf} spatial object. Alternatively, it can be a string with the 23 | name of a table with geometry column within the DuckDB database \code{conn}.} 24 | 25 | \item{conn}{A connection object to a DuckDB database. If \code{NULL}, the function 26 | runs on a temporary DuckDB database.} 27 | 28 | \item{id_x}{Character; optional name of the column in \code{x} whose values will 29 | be used to name the list elements. If \code{NULL}, integer row numbers of \code{x} are used.} 30 | 31 | \item{id_y}{Character; optional name of the column in \code{y} whose values will 32 | replace the integer indices returned in each element of the list.} 33 | 34 | \item{sparse}{A logical value. If \code{TRUE}, it returns a sparse index list. If \code{FALSE}, 35 | it returns a dense logical matrix.} 36 | 37 | \item{quiet}{A logical value. If \code{TRUE}, suppresses any informational messages. 38 | Defaults to \code{FALSE}.} 39 | } 40 | \value{ 41 | A list where each element contains indices (or IDs) of geometries in \code{y} that 42 | are covered by the corresponding geometry in \code{x}. See \code{\link[=ddbs_predicate]{ddbs_predicate()}} for details. 43 | } 44 | \description{ 45 | Tests if geometries in \code{x} cover geometries in \code{y}. Returns TRUE if 46 | geometry \code{x} completely covers geometry \code{y} (no point of \code{y} lies outside \code{x}). 47 | } 48 | \details{ 49 | This is a convenience wrapper around \code{\link[=ddbs_predicate]{ddbs_predicate()}} with 50 | \code{predicate = "covers"}. 51 | } 52 | \examples{ 53 | 54 | ## load packages 55 | library(dplyr) 56 | library(duckspatial) 57 | library(sf) 58 | 59 | ## read countries data, and rivers 60 | countries_sf <- read_sf(system.file("spatial/countries.geojson", package = "duckspatial")) |> 61 | filter(CNTR_ID \%in\% c("PT", "ES", "FR", "IT")) 62 | rivers_sf <- st_read(system.file("spatial/rivers.geojson", package = "duckspatial")) |> 63 | st_transform(st_crs(countries_sf)) 64 | 65 | ddbs_covers(countries_sf, rivers_sf, id_x = "NAME_ENGL") 66 | } 67 | \seealso{ 68 | \code{\link[=ddbs_predicate]{ddbs_predicate()}} for other spatial predicates. 69 | } 70 | -------------------------------------------------------------------------------- /man/ddbs_overlaps.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/ddbs_predicates.R 3 | \name{ddbs_overlaps} 4 | \alias{ddbs_overlaps} 5 | \title{Spatial overlaps predicate} 6 | \usage{ 7 | ddbs_overlaps( 8 | x, 9 | y, 10 | conn = NULL, 11 | id_x = NULL, 12 | id_y = NULL, 13 | sparse = TRUE, 14 | quiet = FALSE 15 | ) 16 | } 17 | \arguments{ 18 | \item{x}{An \code{sf} spatial object. Alternatively, it can be a string with the 19 | name of a table with geometry column within the DuckDB database \code{conn}. 20 | Data is returned from this object.} 21 | 22 | \item{y}{An \code{sf} spatial object. Alternatively, it can be a string with the 23 | name of a table with geometry column within the DuckDB database \code{conn}.} 24 | 25 | \item{conn}{A connection object to a DuckDB database. If \code{NULL}, the function 26 | runs on a temporary DuckDB database.} 27 | 28 | \item{id_x}{Character; optional name of the column in \code{x} whose values will 29 | be used to name the list elements. If \code{NULL}, integer row numbers of \code{x} are used.} 30 | 31 | \item{id_y}{Character; optional name of the column in \code{y} whose values will 32 | replace the integer indices returned in each element of the list.} 33 | 34 | \item{sparse}{A logical value. If \code{TRUE}, it returns a sparse index list. If \code{FALSE}, 35 | it returns a dense logical matrix.} 36 | 37 | \item{quiet}{A logical value. If \code{TRUE}, suppresses any informational messages. 38 | Defaults to \code{FALSE}.} 39 | } 40 | \value{ 41 | A list where each element contains indices (or IDs) of geometries in \code{y} that 42 | overlap the corresponding geometry in \code{x}. See \code{\link[=ddbs_predicate]{ddbs_predicate()}} for details. 43 | } 44 | \description{ 45 | Tests if geometries in \code{x} overlap geometries in \code{y}. Returns TRUE if 46 | geometries share some but not all points, and the intersection has the same dimension as the geometries. 47 | } 48 | \details{ 49 | This is a convenience wrapper around \code{\link[=ddbs_predicate]{ddbs_predicate()}} with 50 | \code{predicate = "overlaps"}. 51 | } 52 | \examples{ 53 | 54 | ## load packages 55 | library(dplyr) 56 | library(duckspatial) 57 | library(sf) 58 | 59 | ## read countries data, and rivers 60 | countries_sf <- read_sf(system.file("spatial/countries.geojson", package = "duckspatial")) |> 61 | filter(CNTR_ID \%in\% c("PT", "ES", "FR", "IT")) 62 | spain_sf <- st_read(system.file("spatial/countries.geojson", package = "duckspatial")) |> 63 | filter(CNTR_ID == c("PT", "ES", "FR", "FI")) 64 | 65 | ddbs_overlaps(countries_sf, countries_sf) 66 | } 67 | \seealso{ 68 | \code{\link[=ddbs_predicate]{ddbs_predicate()}} for other spatial predicates. 69 | } 70 | -------------------------------------------------------------------------------- /man/ddbs_buffer.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/ddbs_ops_unary.R 3 | \name{ddbs_buffer} 4 | \alias{ddbs_buffer} 5 | \title{Creates a buffer around geometries} 6 | \usage{ 7 | ddbs_buffer( 8 | x, 9 | distance, 10 | conn = NULL, 11 | name = NULL, 12 | crs = NULL, 13 | crs_column = "crs_duckspatial", 14 | overwrite = FALSE, 15 | quiet = FALSE 16 | ) 17 | } 18 | \arguments{ 19 | \item{x}{An \code{sf} spatial object. Alternatively, it can be a string with the 20 | name of a table with geometry column within the DuckDB database \code{conn}. 21 | Data is returned from this object.} 22 | 23 | \item{distance}{a numeric value specifying the buffer distance. Units correspond to 24 | the coordinate system of the geometry (e.g. degrees or meters)} 25 | 26 | \item{conn}{A connection object to a DuckDB database. If \code{NULL}, the function 27 | runs on a temporary DuckDB database.} 28 | 29 | \item{name}{A character string of length one specifying the name of the table, 30 | or a character string of length two specifying the schema and table 31 | names. If \code{NULL} (the default), the function returns the result as an 32 | \code{sf} object} 33 | 34 | \item{crs}{The coordinates reference system of the data. Specify if the data 35 | doesn't have a \code{crs_column}, and you know the CRS.} 36 | 37 | \item{crs_column}{a character string of length one specifying the column 38 | storing the CRS (created automatically by \code{\link{ddbs_write_vector}}). 39 | Set to \code{NULL} if absent.} 40 | 41 | \item{overwrite}{Boolean. whether to overwrite the existing table if it exists. Defaults 42 | to \code{FALSE}. This argument is ignored when \code{name} is \code{NULL}.} 43 | 44 | \item{quiet}{A logical value. If \code{TRUE}, suppresses any informational messages. 45 | Defaults to \code{FALSE}.} 46 | } 47 | \value{ 48 | an \code{sf} object or \code{TRUE} (invisibly) for table creation 49 | } 50 | \description{ 51 | Calculates the buffer of geometries from a DuckDB table using the spatial extension. 52 | Returns the result as an \code{sf} object or creates a new table in the database. 53 | } 54 | \examples{ 55 | \dontrun{ 56 | ## load packages 57 | library(duckdb) 58 | library(duckspatial) 59 | library(sf) 60 | 61 | # create a duckdb database in memory (with spatial extension) 62 | conn <- ddbs_create_conn(dbdir = "memory") 63 | 64 | ## read data 65 | argentina_sf <- st_read(system.file("spatial/argentina.geojson", package = "duckspatial")) 66 | 67 | ## store in duckdb 68 | ddbs_write_vector(conn, argentina_sf, "argentina") 69 | 70 | ## buffer 71 | ddbs_buffer(conn = conn, "argentina", distance = 1) 72 | 73 | ## buffer without using a connection 74 | ddbs_buffer(argentina_sf, distance = 1) 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /man/ddbs_covered_by.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/ddbs_predicates.R 3 | \name{ddbs_covered_by} 4 | \alias{ddbs_covered_by} 5 | \title{Spatial covered by predicate} 6 | \usage{ 7 | ddbs_covered_by( 8 | x, 9 | y, 10 | conn = NULL, 11 | id_x = NULL, 12 | id_y = NULL, 13 | sparse = TRUE, 14 | quiet = FALSE 15 | ) 16 | } 17 | \arguments{ 18 | \item{x}{An \code{sf} spatial object. Alternatively, it can be a string with the 19 | name of a table with geometry column within the DuckDB database \code{conn}. 20 | Data is returned from this object.} 21 | 22 | \item{y}{An \code{sf} spatial object. Alternatively, it can be a string with the 23 | name of a table with geometry column within the DuckDB database \code{conn}.} 24 | 25 | \item{conn}{A connection object to a DuckDB database. If \code{NULL}, the function 26 | runs on a temporary DuckDB database.} 27 | 28 | \item{id_x}{Character; optional name of the column in \code{x} whose values will 29 | be used to name the list elements. If \code{NULL}, integer row numbers of \code{x} are used.} 30 | 31 | \item{id_y}{Character; optional name of the column in \code{y} whose values will 32 | replace the integer indices returned in each element of the list.} 33 | 34 | \item{sparse}{A logical value. If \code{TRUE}, it returns a sparse index list. If \code{FALSE}, 35 | it returns a dense logical matrix.} 36 | 37 | \item{quiet}{A logical value. If \code{TRUE}, suppresses any informational messages. 38 | Defaults to \code{FALSE}.} 39 | } 40 | \value{ 41 | A list where each element contains indices (or IDs) of geometries in \code{y} that 42 | cover the corresponding geometry in \code{x}. See \code{\link[=ddbs_predicate]{ddbs_predicate()}} for details. 43 | } 44 | \description{ 45 | Tests if geometries in \code{x} are covered by geometries in \code{y}. Returns TRUE if 46 | geometry \code{x} is completely covered by geometry \code{y} (no point of \code{x} lies outside \code{y}). 47 | } 48 | \details{ 49 | This is a convenience wrapper around \code{\link[=ddbs_predicate]{ddbs_predicate()}} with 50 | \code{predicate = "covered_by"}. 51 | } 52 | \examples{ 53 | 54 | ## load packages 55 | library(dplyr) 56 | library(duckspatial) 57 | library(sf) 58 | 59 | ## read countries data, and rivers 60 | countries_sf <- read_sf(system.file("spatial/countries.geojson", package = "duckspatial")) |> 61 | filter(CNTR_ID \%in\% c("PT", "ES", "FR", "IT")) 62 | rivers_sf <- st_read(system.file("spatial/rivers.geojson", package = "duckspatial")) |> 63 | st_transform(st_crs(countries_sf)) 64 | 65 | ddbs_covered_by(rivers_sf, countries_sf, id_x = "RIVER_NAME", id_y = "NAME_ENGL") 66 | } 67 | \seealso{ 68 | \code{\link[=ddbs_predicate]{ddbs_predicate()}} for other spatial predicates. 69 | } 70 | -------------------------------------------------------------------------------- /man/ddbs_difference.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/ddbs_ops_binary.R 3 | \name{ddbs_difference} 4 | \alias{ddbs_difference} 5 | \title{Calculates the difference of two geometries} 6 | \usage{ 7 | ddbs_difference( 8 | x, 9 | y, 10 | conn = NULL, 11 | name = NULL, 12 | crs = NULL, 13 | crs_column = "crs_duckspatial", 14 | overwrite = FALSE, 15 | quiet = FALSE 16 | ) 17 | } 18 | \arguments{ 19 | \item{x}{An \code{sf} spatial object. Alternatively, it can be a string with the 20 | name of a table with geometry column within the DuckDB database \code{conn}. 21 | Data is returned from this object.} 22 | 23 | \item{y}{A table with geometry column within the DuckDB database} 24 | 25 | \item{conn}{A connection object to a DuckDB database. If \code{NULL}, the function 26 | runs on a temporary DuckDB database.} 27 | 28 | \item{name}{A character string of length one specifying the name of the table, 29 | or a character string of length two specifying the schema and table 30 | names. If \code{NULL} (the default), the function returns the result as an 31 | \code{sf} object} 32 | 33 | \item{crs}{The coordinates reference system of the data. Specify if the data 34 | doesn't have a \code{crs_column}, and you know the CRS.} 35 | 36 | \item{crs_column}{a character string of length one specifying the column 37 | storing the CRS (created automatically by \code{\link{ddbs_write_vector}}). 38 | Set to \code{NULL} if absent.} 39 | 40 | \item{overwrite}{Boolean. whether to overwrite the existing table if it exists. Defaults 41 | to \code{FALSE}. This argument is ignored when \code{name} is \code{NULL}.} 42 | 43 | \item{quiet}{A logical value. If \code{TRUE}, suppresses any informational messages. 44 | Defaults to \code{FALSE}.} 45 | } 46 | \value{ 47 | An sf object or TRUE (invisibly) for table creation 48 | } 49 | \description{ 50 | Calculates the geometric difference of two geometries, and returns a \code{sf} 51 | object or creates a new table 52 | } 53 | \examples{ 54 | \dontrun{ 55 | ## load packages 56 | library(duckdb) 57 | library(duckspatial) 58 | library(sf) 59 | 60 | # create a duckdb database in memory (with spatial extension) 61 | conn <- ddbs_create_conn(dbdir = "memory") 62 | 63 | ## read data 64 | countries_sf <- st_read(system.file("spatial/countries.geojson", package = "duckspatial")) 65 | argentina_sf <- st_read(system.file("spatial/argentina.geojson", package = "duckspatial")) 66 | 67 | ## store in duckdb 68 | ddbs_write_vector(conn, countries_sf, "countries") 69 | ddbs_write_vector(conn, argentina_sf, "argentina") 70 | 71 | ## difference with a connection 72 | ddbs_difference("countries", "argentina", conn) 73 | 74 | ## difference without a connection 75 | ddbs_difference(countries_sf, argentina_sf) 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /man/ddbs_simplify.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/ddbs_ops_unary.R 3 | \name{ddbs_simplify} 4 | \alias{ddbs_simplify} 5 | \title{Simplify geometries} 6 | \usage{ 7 | ddbs_simplify( 8 | x, 9 | conn = NULL, 10 | name = NULL, 11 | tolerance, 12 | crs = NULL, 13 | crs_column = "crs_duckspatial", 14 | overwrite = FALSE, 15 | quiet = FALSE 16 | ) 17 | } 18 | \arguments{ 19 | \item{x}{An \code{sf} spatial object. Alternatively, it can be a string with the 20 | name of a table with geometry column within the DuckDB database \code{conn}. 21 | Data is returned from this object.} 22 | 23 | \item{conn}{A connection object to a DuckDB database. If \code{NULL}, the function 24 | runs on a temporary DuckDB database.} 25 | 26 | \item{name}{A character string of length one specifying the name of the table, 27 | or a character string of length two specifying the schema and table 28 | names. If \code{NULL} (the default), the function returns the result as an 29 | \code{sf} object} 30 | 31 | \item{tolerance}{Tolerance distance for simplification. Larger values result in more simplified geometries.} 32 | 33 | \item{crs}{The coordinates reference system of the data. Specify if the data 34 | doesn't have a \code{crs_column}, and you know the CRS.} 35 | 36 | \item{crs_column}{a character string of length one specifying the column 37 | storing the CRS (created automatically by \code{\link{ddbs_write_vector}}). 38 | Set to \code{NULL} if absent.} 39 | 40 | \item{overwrite}{Boolean. whether to overwrite the existing table if it exists. Defaults 41 | to \code{FALSE}. This argument is ignored when \code{name} is \code{NULL}.} 42 | 43 | \item{quiet}{A logical value. If \code{TRUE}, suppresses any informational messages. 44 | Defaults to \code{FALSE}.} 45 | } 46 | \value{ 47 | an \code{sf} object with simplified geometries or \code{TRUE} (invisibly) for table creation 48 | } 49 | \description{ 50 | Simplifies geometries from a DuckDB table using the Douglas-Peucker algorithm via the spatial extension. 51 | Returns the result as an \code{sf} object or creates a new table in the database. 52 | } 53 | \examples{ 54 | \dontrun{ 55 | ## load packages 56 | library(duckdb) 57 | library(duckspatial) 58 | library(sf) 59 | 60 | # create a duckdb database in memory (with spatial extension) 61 | conn <- ddbs_create_conn(dbdir = "memory") 62 | 63 | ## read data 64 | countries_sf <- st_read(system.file("spatial/countries.geojson", package = "duckspatial")) 65 | 66 | ## store in duckdb 67 | ddbs_write_vector(conn, countries_sf, "countries") 68 | 69 | ## simplify with tolerance of 0.01 70 | ddbs_simplify("countries", conn, tolerance = 0.01) 71 | 72 | ## simplify without using a connection 73 | ddbs_simplify(countries_sf, tolerance = 0.01) 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /man/ddbs_intersection.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/ddbs_ops_binary.R 3 | \name{ddbs_intersection} 4 | \alias{ddbs_intersection} 5 | \title{Calculates the intersection of two geometries} 6 | \usage{ 7 | ddbs_intersection( 8 | x, 9 | y, 10 | conn = NULL, 11 | name = NULL, 12 | crs = NULL, 13 | crs_column = "crs_duckspatial", 14 | overwrite = FALSE, 15 | quiet = FALSE 16 | ) 17 | } 18 | \arguments{ 19 | \item{x}{An \code{sf} spatial object. Alternatively, it can be a string with the 20 | name of a table with geometry column within the DuckDB database \code{conn}. 21 | Data is returned from this object.} 22 | 23 | \item{y}{A table with geometry column within the DuckDB database} 24 | 25 | \item{conn}{A connection object to a DuckDB database. If \code{NULL}, the function 26 | runs on a temporary DuckDB database.} 27 | 28 | \item{name}{A character string of length one specifying the name of the table, 29 | or a character string of length two specifying the schema and table 30 | names. If \code{NULL} (the default), the function returns the result as an 31 | \code{sf} object} 32 | 33 | \item{crs}{The coordinates reference system of the data. Specify if the data 34 | doesn't have a \code{crs_column}, and you know the CRS.} 35 | 36 | \item{crs_column}{a character string of length one specifying the column 37 | storing the CRS (created automatically by \code{\link{ddbs_write_vector}}). 38 | Set to \code{NULL} if absent.} 39 | 40 | \item{overwrite}{Boolean. whether to overwrite the existing table if it exists. Defaults 41 | to \code{FALSE}. This argument is ignored when \code{name} is \code{NULL}.} 42 | 43 | \item{quiet}{A logical value. If \code{TRUE}, suppresses any informational messages. 44 | Defaults to \code{FALSE}.} 45 | } 46 | \value{ 47 | an sf object or TRUE (invisibly) for table creation 48 | } 49 | \description{ 50 | Calculates the intersection of two geometries, and return a \code{sf} object 51 | or creates a new table 52 | } 53 | \examples{ 54 | \dontrun{ 55 | ## load packages 56 | library(duckdb) 57 | library(duckspatial) 58 | library(sf) 59 | 60 | # create a duckdb database in memory (with spatial extension) 61 | conn <- ddbs_create_conn(dbdir = "memory") 62 | 63 | ## read data 64 | countries_sf <- st_read(system.file("spatial/countries.geojson", package = "duckspatial")) 65 | argentina_sf <- st_read(system.file("spatial/argentina.geojson", package = "duckspatial")) 66 | 67 | ## store in duckdb 68 | ddbs_write_vector(conn, countries_sf, "countries") 69 | ddbs_write_vector(conn, argentina_sf, "argentina") 70 | 71 | ## intersection inside the connection 72 | ddbs_intersection("countries", "argentina", conn) 73 | 74 | ## intersection without using a connection 75 | ddbs_intersection(countries_sf, argentina_sf) 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /man/ddbs_is_valid.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/ddbs_ops_unary.R 3 | \name{ddbs_is_valid} 4 | \alias{ddbs_is_valid} 5 | \title{Check if geometries are valid} 6 | \usage{ 7 | ddbs_is_valid( 8 | x, 9 | conn = NULL, 10 | name = NULL, 11 | new_column = NULL, 12 | crs = NULL, 13 | crs_column = "crs_duckspatial", 14 | overwrite = FALSE, 15 | quiet = FALSE 16 | ) 17 | } 18 | \arguments{ 19 | \item{x}{An \code{sf} spatial object. Alternatively, it can be a string with the 20 | name of a table with geometry column within the DuckDB database \code{conn}. 21 | Data is returned from this object.} 22 | 23 | \item{conn}{A connection object to a DuckDB database. If \code{NULL}, the function 24 | runs on a temporary DuckDB database.} 25 | 26 | \item{name}{A character string of length one specifying the name of the table, 27 | or a character string of length two specifying the schema and table 28 | names. If \code{NULL} (the default), the function returns the result as an 29 | \code{sf} object} 30 | 31 | \item{new_column}{Name of the new column to create on the input data. If NULL, 32 | the function will return a vector with the result} 33 | 34 | \item{crs}{The coordinates reference system of the data. Specify if the data 35 | doesn't have a \code{crs_column}, and you know the CRS.} 36 | 37 | \item{crs_column}{a character string of length one specifying the column 38 | storing the CRS (created automatically by \code{\link{ddbs_write_vector}}). 39 | Set to \code{NULL} if absent.} 40 | 41 | \item{overwrite}{Boolean. whether to overwrite the existing table if it exists. Defaults 42 | to \code{FALSE}. This argument is ignored when \code{name} is \code{NULL}.} 43 | 44 | \item{quiet}{A logical value. If \code{TRUE}, suppresses any informational messages. 45 | Defaults to \code{FALSE}.} 46 | } 47 | \value{ 48 | a vector, an \code{sf} object with validity information or \code{TRUE} (invisibly) for table creation 49 | } 50 | \description{ 51 | Checks the validity of geometries from a DuckDB table using the spatial extension. 52 | Returns the result as an \code{sf} object with a boolean validity column or creates 53 | a new table in the database. 54 | } 55 | \examples{ 56 | \dontrun{ 57 | ## load packages 58 | library(duckdb) 59 | library(duckspatial) 60 | library(sf) 61 | 62 | # create a duckdb database in memory (with spatial extension) 63 | conn <- ddbs_create_conn(dbdir = "memory") 64 | 65 | ## read data 66 | argentina_sf <- st_read(system.file("spatial/argentina.geojson", package = "duckspatial")) 67 | 68 | ## store in duckdb 69 | ddbs_write_vector(conn, argentina_sf, "argentina") 70 | 71 | ## check validity 72 | ddbs_is_valid("argentina", conn) 73 | 74 | ## check validity without using a connection 75 | ddbs_is_valid(argentina_sf) 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /man/ddbs_within_properly.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/ddbs_predicates.R 3 | \name{ddbs_within_properly} 4 | \alias{ddbs_within_properly} 5 | \title{Spatial within properly predicate} 6 | \usage{ 7 | ddbs_within_properly( 8 | x, 9 | y, 10 | conn = NULL, 11 | id_x = NULL, 12 | id_y = NULL, 13 | sparse = TRUE, 14 | quiet = FALSE 15 | ) 16 | } 17 | \arguments{ 18 | \item{x}{An \code{sf} spatial object. Alternatively, it can be a string with the 19 | name of a table with geometry column within the DuckDB database \code{conn}. 20 | Data is returned from this object.} 21 | 22 | \item{y}{An \code{sf} spatial object. Alternatively, it can be a string with the 23 | name of a table with geometry column within the DuckDB database \code{conn}.} 24 | 25 | \item{conn}{A connection object to a DuckDB database. If \code{NULL}, the function 26 | runs on a temporary DuckDB database.} 27 | 28 | \item{id_x}{Character; optional name of the column in \code{x} whose values will 29 | be used to name the list elements. If \code{NULL}, integer row numbers of \code{x} are used.} 30 | 31 | \item{id_y}{Character; optional name of the column in \code{y} whose values will 32 | replace the integer indices returned in each element of the list.} 33 | 34 | \item{sparse}{A logical value. If \code{TRUE}, it returns a sparse index list. If \code{FALSE}, 35 | it returns a dense logical matrix.} 36 | 37 | \item{quiet}{A logical value. If \code{TRUE}, suppresses any informational messages. 38 | Defaults to \code{FALSE}.} 39 | } 40 | \value{ 41 | A list where each element contains indices (or IDs) of geometries in \code{y} that 42 | properly contain the corresponding geometry in \code{x}. See \code{\link[=ddbs_predicate]{ddbs_predicate()}} for details. 43 | } 44 | \description{ 45 | Tests if geometries in \code{x} are properly within geometries in \code{y}. Returns TRUE if 46 | geometry \code{x} is completely inside geometry \code{y} and does not touch its boundary. 47 | } 48 | \details{ 49 | This is a convenience wrapper around \code{\link[=ddbs_predicate]{ddbs_predicate()}} with 50 | \code{predicate = "within_properly"}. 51 | } 52 | \examples{ 53 | 54 | ## load packages 55 | library(dplyr) 56 | library(duckspatial) 57 | library(sf) 58 | 59 | ## read countries data, and rivers 60 | countries_sf <- read_sf(system.file("spatial/countries.geojson", package = "duckspatial")) |> 61 | filter(CNTR_ID \%in\% c("PT", "ES", "FR", "IT")) 62 | rivers_sf <- st_read(system.file("spatial/rivers.geojson", package = "duckspatial")) |> 63 | st_transform(st_crs(countries_sf)) 64 | 65 | ddbs_within_properly(countries_sf, rivers_sf, id_x = "NAME_ENGL", id_y = "RIVER_NAME") 66 | } 67 | \seealso{ 68 | \code{\link[=ddbs_predicate]{ddbs_predicate()}} for other spatial predicates. 69 | } 70 | -------------------------------------------------------------------------------- /man/ddbs_contains_properly.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/ddbs_predicates.R 3 | \name{ddbs_contains_properly} 4 | \alias{ddbs_contains_properly} 5 | \title{Spatial contains properly predicate} 6 | \usage{ 7 | ddbs_contains_properly( 8 | x, 9 | y, 10 | conn = NULL, 11 | id_x = NULL, 12 | id_y = NULL, 13 | sparse = TRUE, 14 | quiet = FALSE 15 | ) 16 | } 17 | \arguments{ 18 | \item{x}{An \code{sf} spatial object. Alternatively, it can be a string with the 19 | name of a table with geometry column within the DuckDB database \code{conn}. 20 | Data is returned from this object.} 21 | 22 | \item{y}{An \code{sf} spatial object. Alternatively, it can be a string with the 23 | name of a table with geometry column within the DuckDB database \code{conn}.} 24 | 25 | \item{conn}{A connection object to a DuckDB database. If \code{NULL}, the function 26 | runs on a temporary DuckDB database.} 27 | 28 | \item{id_x}{Character; optional name of the column in \code{x} whose values will 29 | be used to name the list elements. If \code{NULL}, integer row numbers of \code{x} are used.} 30 | 31 | \item{id_y}{Character; optional name of the column in \code{y} whose values will 32 | replace the integer indices returned in each element of the list.} 33 | 34 | \item{sparse}{A logical value. If \code{TRUE}, it returns a sparse index list. If \code{FALSE}, 35 | it returns a dense logical matrix.} 36 | 37 | \item{quiet}{A logical value. If \code{TRUE}, suppresses any informational messages. 38 | Defaults to \code{FALSE}.} 39 | } 40 | \value{ 41 | A list where each element contains indices (or IDs) of geometries in \code{y} that 42 | are properly contained by the corresponding geometry in \code{x}. See \code{\link[=ddbs_predicate]{ddbs_predicate()}} for details. 43 | } 44 | \description{ 45 | Tests if geometries in \code{x} properly contain geometries in \code{y}. Returns TRUE if 46 | geometry \code{y} is completely inside geometry \code{x} and does not touch its boundary. 47 | } 48 | \details{ 49 | This is a convenience wrapper around \code{\link[=ddbs_predicate]{ddbs_predicate()}} with 50 | \code{predicate = "contains_properly"}. 51 | } 52 | \examples{ 53 | 54 | ## load packages 55 | library(dplyr) 56 | library(duckspatial) 57 | library(sf) 58 | 59 | ## read countries data, and rivers 60 | countries_sf <- read_sf(system.file("spatial/countries.geojson", package = "duckspatial")) |> 61 | filter(CNTR_ID \%in\% c("PT", "ES", "FR", "IT")) 62 | rivers_sf <- st_read(system.file("spatial/rivers.geojson", package = "duckspatial")) |> 63 | st_transform(st_crs(countries_sf)) 64 | 65 | ddbs_contains_properly(countries_sf, rivers_sf, id_x = "NAME_ENGL", id_y = "RIVER_NAME") 66 | } 67 | \seealso{ 68 | \code{\link[=ddbs_predicate]{ddbs_predicate()}} for other spatial predicates. 69 | } 70 | -------------------------------------------------------------------------------- /man/ddbs_is_simple.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/ddbs_ops_unary.R 3 | \name{ddbs_is_simple} 4 | \alias{ddbs_is_simple} 5 | \title{Check if geometries are simple} 6 | \usage{ 7 | ddbs_is_simple( 8 | x, 9 | conn = NULL, 10 | name = NULL, 11 | new_column = NULL, 12 | crs = NULL, 13 | crs_column = "crs_duckspatial", 14 | overwrite = FALSE, 15 | quiet = FALSE 16 | ) 17 | } 18 | \arguments{ 19 | \item{x}{An \code{sf} spatial object. Alternatively, it can be a string with the 20 | name of a table with geometry column within the DuckDB database \code{conn}. 21 | Data is returned from this object.} 22 | 23 | \item{conn}{A connection object to a DuckDB database. If \code{NULL}, the function 24 | runs on a temporary DuckDB database.} 25 | 26 | \item{name}{A character string of length one specifying the name of the table, 27 | or a character string of length two specifying the schema and table 28 | names. If \code{NULL} (the default), the function returns the result as an 29 | \code{sf} object} 30 | 31 | \item{new_column}{Name of the new column to create on the input data. If NULL, 32 | the function will return a vector with the result} 33 | 34 | \item{crs}{The coordinates reference system of the data. Specify if the data 35 | doesn't have a \code{crs_column}, and you know the CRS.} 36 | 37 | \item{crs_column}{a character string of length one specifying the column 38 | storing the CRS (created automatically by \code{\link{ddbs_write_vector}}). 39 | Set to \code{NULL} if absent.} 40 | 41 | \item{overwrite}{Boolean. whether to overwrite the existing table if it exists. Defaults 42 | to \code{FALSE}. This argument is ignored when \code{name} is \code{NULL}.} 43 | 44 | \item{quiet}{A logical value. If \code{TRUE}, suppresses any informational messages. 45 | Defaults to \code{FALSE}.} 46 | } 47 | \value{ 48 | a vector, an \code{sf} object with simplicity information or \code{TRUE} (invisibly) for table creation 49 | } 50 | \description{ 51 | Checks if geometries are simple (no self-intersections) from a DuckDB table using the spatial extension. 52 | Returns the result as an \code{sf} object with a boolean simplicity column or creates 53 | a new table in the database. 54 | } 55 | \examples{ 56 | \dontrun{ 57 | ## load packages 58 | library(duckdb) 59 | library(duckspatial) 60 | library(sf) 61 | 62 | # create a duckdb database in memory (with spatial extension) 63 | conn <- ddbs_create_conn(dbdir = "memory") 64 | 65 | ## read data 66 | argentina_sf <- st_read(system.file("spatial/argentina.geojson", package = "duckspatial")) 67 | 68 | ## store in duckdb 69 | ddbs_write_vector(conn, argentina_sf, "argentina") 70 | 71 | ## check simplicity 72 | ddbs_is_simple("argentina", conn) 73 | 74 | ## check simplicity without using a connection 75 | ddbs_is_simple(argentina_sf) 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /docs/lightswitch.js: -------------------------------------------------------------------------------- 1 | 2 | /*! 3 | * Color mode toggler for Bootstrap's docs (https://getbootstrap.com/) 4 | * Copyright 2011-2023 The Bootstrap Authors 5 | * Licensed under the Creative Commons Attribution 3.0 Unported License. 6 | * Updates for {pkgdown} by the {bslib} authors, also licensed under CC-BY-3.0. 7 | */ 8 | 9 | const getStoredTheme = () => localStorage.getItem('theme') 10 | const setStoredTheme = theme => localStorage.setItem('theme', theme) 11 | 12 | const getPreferredTheme = () => { 13 | const storedTheme = getStoredTheme() 14 | if (storedTheme) { 15 | return storedTheme 16 | } 17 | 18 | return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light' 19 | } 20 | 21 | const setTheme = theme => { 22 | if (theme === 'auto') { 23 | document.documentElement.setAttribute('data-bs-theme', (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light')) 24 | } else { 25 | document.documentElement.setAttribute('data-bs-theme', theme) 26 | } 27 | } 28 | 29 | function bsSetupThemeToggle () { 30 | 'use strict' 31 | 32 | const showActiveTheme = (theme, focus = false) => { 33 | var activeLabel, activeIcon; 34 | 35 | document.querySelectorAll('[data-bs-theme-value]').forEach(element => { 36 | const buttonTheme = element.getAttribute('data-bs-theme-value') 37 | const isActive = buttonTheme == theme 38 | 39 | element.classList.toggle('active', isActive) 40 | element.setAttribute('aria-pressed', isActive) 41 | 42 | if (isActive) { 43 | activeLabel = element.textContent; 44 | activeIcon = element.querySelector('span').classList.value; 45 | } 46 | }) 47 | 48 | const themeSwitcher = document.querySelector('#dropdown-lightswitch') 49 | if (!themeSwitcher) { 50 | return 51 | } 52 | 53 | themeSwitcher.setAttribute('aria-label', activeLabel) 54 | themeSwitcher.querySelector('span').classList.value = activeIcon; 55 | 56 | if (focus) { 57 | themeSwitcher.focus() 58 | } 59 | } 60 | 61 | window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => { 62 | const storedTheme = getStoredTheme() 63 | if (storedTheme !== 'light' && storedTheme !== 'dark') { 64 | setTheme(getPreferredTheme()) 65 | } 66 | }) 67 | 68 | window.addEventListener('DOMContentLoaded', () => { 69 | showActiveTheme(getPreferredTheme()) 70 | 71 | document 72 | .querySelectorAll('[data-bs-theme-value]') 73 | .forEach(toggle => { 74 | toggle.addEventListener('click', () => { 75 | const theme = toggle.getAttribute('data-bs-theme-value') 76 | setTheme(theme) 77 | setStoredTheme(theme) 78 | showActiveTheme(theme, true) 79 | }) 80 | }) 81 | }) 82 | } 83 | 84 | setTheme(getPreferredTheme()); 85 | bsSetupThemeToggle(); 86 | -------------------------------------------------------------------------------- /man/ddbs_intersects_extent.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/ddbs_predicates.R 3 | \name{ddbs_intersects_extent} 4 | \alias{ddbs_intersects_extent} 5 | \title{Spatial intersects extent predicate} 6 | \usage{ 7 | ddbs_intersects_extent( 8 | x, 9 | y, 10 | conn = NULL, 11 | id_x = NULL, 12 | id_y = NULL, 13 | sparse = TRUE, 14 | quiet = FALSE 15 | ) 16 | } 17 | \arguments{ 18 | \item{x}{An \code{sf} spatial object. Alternatively, it can be a string with the 19 | name of a table with geometry column within the DuckDB database \code{conn}. 20 | Data is returned from this object.} 21 | 22 | \item{y}{An \code{sf} spatial object. Alternatively, it can be a string with the 23 | name of a table with geometry column within the DuckDB database \code{conn}.} 24 | 25 | \item{conn}{A connection object to a DuckDB database. If \code{NULL}, the function 26 | runs on a temporary DuckDB database.} 27 | 28 | \item{id_x}{Character; optional name of the column in \code{x} whose values will 29 | be used to name the list elements. If \code{NULL}, integer row numbers of \code{x} are used.} 30 | 31 | \item{id_y}{Character; optional name of the column in \code{y} whose values will 32 | replace the integer indices returned in each element of the list.} 33 | 34 | \item{sparse}{A logical value. If \code{TRUE}, it returns a sparse index list. If \code{FALSE}, 35 | it returns a dense logical matrix.} 36 | 37 | \item{quiet}{A logical value. If \code{TRUE}, suppresses any informational messages. 38 | Defaults to \code{FALSE}.} 39 | } 40 | \value{ 41 | A list where each element contains indices (or IDs) of geometries in \code{y} whose 42 | bounding box intersects the bounding box of the corresponding geometry in \code{x}. 43 | See \code{\link[=ddbs_predicate]{ddbs_predicate()}} for details. 44 | } 45 | \description{ 46 | Tests if the bounding box of geometries in \code{x} intersect the bounding box of geometries in \code{y}. 47 | Returns TRUE if the extents (bounding boxes) overlap. This is faster than full geometry intersection 48 | but less precise. 49 | } 50 | \details{ 51 | This is a convenience wrapper around \code{\link[=ddbs_predicate]{ddbs_predicate()}} with 52 | \code{predicate = "intersects_extent"}. 53 | } 54 | \examples{ 55 | 56 | ## load packages 57 | library(dplyr) 58 | library(duckspatial) 59 | library(sf) 60 | 61 | ## read countries data, and rivers 62 | countries_sf <- read_sf(system.file("spatial/countries.geojson", package = "duckspatial")) |> 63 | filter(CNTR_ID \%in\% c("PT", "ES", "FR", "IT")) 64 | rivers_sf <- st_read(system.file("spatial/rivers.geojson", package = "duckspatial")) |> 65 | st_transform(st_crs(countries_sf)) 66 | 67 | # Fast bounding box intersection check 68 | ddbs_intersects_extent(countries_sf, rivers_sf, id_x = "NAME_ENGL") 69 | } 70 | \seealso{ 71 | \code{\link[=ddbs_predicate]{ddbs_predicate()}} for other spatial predicates. 72 | } 73 | -------------------------------------------------------------------------------- /man/ddbs_bbox.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/ddbs_bbox.R 3 | \name{ddbs_bbox} 4 | \alias{ddbs_bbox} 5 | \title{Returns the minimal bounding box enclosing the input geometry} 6 | \usage{ 7 | ddbs_bbox( 8 | x, 9 | by_feature = FALSE, 10 | conn = NULL, 11 | name = NULL, 12 | crs = NULL, 13 | crs_column = "crs_duckspatial", 14 | overwrite = FALSE, 15 | quiet = FALSE 16 | ) 17 | } 18 | \arguments{ 19 | \item{x}{An \code{sf} spatial object. Alternatively, it can be a string with the 20 | name of a table with geometry column within the DuckDB database \code{conn}. 21 | Data is returned from this object.} 22 | 23 | \item{by_feature}{Boolean. The function defaults to \code{FALSE}, and returns a 24 | single bounding box for \code{x}. If \code{TRUE}, it return one bounding box for 25 | each feature.} 26 | 27 | \item{conn}{A connection object to a DuckDB database. If \code{NULL}, the function 28 | runs on a temporary DuckDB database.} 29 | 30 | \item{name}{A character string of length one specifying the name of the table, 31 | or a character string of length two specifying the schema and table 32 | names. If \code{NULL} (the default), the function returns the result as an 33 | \code{sf} object} 34 | 35 | \item{crs}{The coordinates reference system of the data. Specify if the data 36 | doesn't have a \code{crs_column}, and you know the CRS.} 37 | 38 | \item{crs_column}{a character string of length one specifying the column 39 | storing the CRS (created automatically by \code{\link{ddbs_write_vector}}). 40 | Set to \code{NULL} if absent.} 41 | 42 | \item{overwrite}{Boolean. whether to overwrite the existing table if it exists. Defaults 43 | to \code{FALSE}. This argument is ignored when \code{name} is \code{NULL}.} 44 | 45 | \item{quiet}{A logical value. If \code{TRUE}, suppresses any informational messages. 46 | Defaults to \code{FALSE}.} 47 | } 48 | \value{ 49 | an \code{sf} object or \code{TRUE} (invisibly) for table creation 50 | } 51 | \description{ 52 | Returns the minimal bounding box enclosing the input geometry from a \code{sf} object 53 | or a DuckDB table. Returns the result as an \code{sf} object or creates a new 54 | table in the database. 55 | } 56 | \examples{ 57 | ## load packages 58 | library(duckdb) 59 | library(duckspatial) 60 | library(sf) 61 | 62 | ## read data 63 | argentina_sf <- st_read(system.file("spatial/argentina.geojson", package = "duckspatial")) 64 | 65 | # option 1: passing sf objects 66 | ddbs_bbox(argentina_sf) 67 | 68 | 69 | ## option 2: passing the names of tables in a duckdb db 70 | 71 | # creates a duckdb write sf to it 72 | conn <- duckspatial::ddbs_create_conn() 73 | ddbs_write_vector(conn, argentina_sf, "argentina_tbl", overwrite = TRUE) 74 | 75 | output2 <- ddbs_bbox( 76 | conn = conn, 77 | x = "argentina_tbl", 78 | name = "argentina_bbox" 79 | ) 80 | 81 | DBI::dbReadTable(conn, "argentina_bbox") 82 | 83 | } 84 | -------------------------------------------------------------------------------- /man/ddbs_convex_hull.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/ddbs_convex_hull.R 3 | \name{ddbs_convex_hull} 4 | \alias{ddbs_convex_hull} 5 | \title{Returns the convex hull enclosing the geometry} 6 | \usage{ 7 | ddbs_convex_hull( 8 | x, 9 | conn = NULL, 10 | name = NULL, 11 | crs = NULL, 12 | crs_column = "crs_duckspatial", 13 | overwrite = FALSE, 14 | quiet = FALSE 15 | ) 16 | } 17 | \arguments{ 18 | \item{x}{An \code{sf} spatial object. Alternatively, it can be a string with the 19 | name of a table with geometry column within the DuckDB database \code{conn}. 20 | Data is returned from this object.} 21 | 22 | \item{conn}{A connection object to a DuckDB database. If \code{NULL}, the function 23 | runs on a temporary DuckDB database.} 24 | 25 | \item{name}{A character string of length one specifying the name of the table, 26 | or a character string of length two specifying the schema and table 27 | names. If \code{NULL} (the default), the function returns the result as an 28 | \code{sf} object} 29 | 30 | \item{crs}{The coordinates reference system of the data. Specify if the data 31 | doesn't have a \code{crs_column}, and you know the CRS.} 32 | 33 | \item{crs_column}{a character string of length one specifying the column 34 | storing the CRS (created automatically by \code{\link{ddbs_write_vector}}). 35 | Set to \code{NULL} if absent.} 36 | 37 | \item{overwrite}{Boolean. whether to overwrite the existing table if it exists. Defaults 38 | to \code{FALSE}. This argument is ignored when \code{name} is \code{NULL}.} 39 | 40 | \item{quiet}{A logical value. If \code{TRUE}, suppresses any informational messages. 41 | Defaults to \code{FALSE}.} 42 | } 43 | \value{ 44 | an \code{sf} object or \code{TRUE} (invisibly) for table creation 45 | } 46 | \description{ 47 | Returns the convex hull enclosing the geometry from an \code{sf} object or 48 | from a DuckDB table using the spatial extension. Returns the result as an 49 | \code{sf} object or creates a new table in the database. 50 | } 51 | \examples{ 52 | \dontrun{ 53 | ## load packages 54 | library(duckdb) 55 | library(duckspatial) 56 | library(sf) 57 | 58 | # create a duckdb database in memory (with spatial extension) 59 | conn <- ddbs_create_conn(dbdir = "memory") 60 | 61 | # read data 62 | argentina_sf <- st_read(system.file("spatial/argentina.geojson", package = "duckspatial")) 63 | 64 | # option 1: passing sf objects 65 | output1 <- duckspatial::ddbs_convex_hull(x = argentina_sf) 66 | 67 | plot(output1["CNTR_NAME"])#' # store in duckdb 68 | 69 | # option 2: passing the name of a table in a duckdb db 70 | 71 | # creates a duckdb 72 | conn <- duckspatial::ddbs_create_conn() 73 | 74 | # write sf to duckdb 75 | ddbs_write_vector(conn, argentina_sf, "argentina_tbl") 76 | 77 | # spatial join 78 | output2 <- duckspatial::ddbs_convex_hull( 79 | conn = conn, 80 | x = "argentina_tbl" 81 | ) 82 | 83 | plot(output2["CNTR_NAME"]) 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /NEWS.md: -------------------------------------------------------------------------------- 1 | # duckspatial 0.2.0999 dev 2 | 3 | ## MAJOR CHANGES 4 | 5 | * `conn` argument defaults now to NULL. This parameter is not mandatory anymore in spatial operations, and it will be handled internally. The argument has been moved after `x` and `y` arguments. 6 | 7 | * `ddbs_filter()`: uses `intersects` for `ST_Intersects` instead of `intersection`. 8 | 9 | * Allow the use of either `sf` object or a DuckDB table as input/output in every operation. 10 | 11 | * Functions that use `x` and `y` arguments, can indistinctively use `sf`, DuckDB table name, or mixed. 12 | 13 | ## NEW FEATURES 14 | 15 | * `ddbs_boundary()`: returns the boundary of geometries. 16 | 17 | * `ddbs_concave_hull()`: new function to create the concave hull enclosing a geometry. 18 | 19 | * `ddbs_convex_hull()`: new function to create the convex hull enclosing a geometry. 20 | 21 | * `ddbs_create_conn()`: new convenient function to create a DuckDB connection. 22 | 23 | * `ddbs_drivers()`: get list of GDAL drivers and file formats supported by DuckDB spatial extension. 24 | 25 | * `ddbs_join()`: new function to perform spatial join operations. 26 | 27 | * `ddbs_length()`: adds a new column with the length of the geometries 28 | 29 | * `ddbs_area()`: adds a new column with the area of the geometries 30 | 31 | * `ddbs_is_valid()`: adds a new logical column asserting the simplicity of the geometries 32 | 33 | * `ddbs_is_valid()`: adds a new logical column asserting the validity of the geometries 34 | 35 | * `ddbs_make_valid()`: makes the geometries valid 36 | 37 | * `ddbs_simplify()`: makes the geometries simple 38 | 39 | * `ddbs_bbox()`: calculates the bounding box 40 | 41 | * **Spatial predicates**: spatial predicates are all included in a function called `ddbs_predicate()`, where the user can specify the spatial predicate. Another option, it's to use the spatial predicate function, such as `ddbs_intersects()`, `ddbs_crosses()`, `ddbs_touches()`, etc. 42 | 43 | ## MINOR CHANGES 44 | 45 | * All functions now have a parameter `quiet` that allows users to suppress informational messages. Closed [#3](https://github.com/Cidree/duckspatial/issues/3) 46 | 47 | 48 | # duckspatial 0.2.0 49 | 50 | ## NEW FEATURES 51 | 52 | * `ddbs_read_vector()`: gains a new argument `clauses` to modify the query from the table (e.g. "WHERE ...", "ORDER BY...") 53 | 54 | ## NEW FUNCTIONS 55 | 56 | * `ddbs_list_tables()`: lists table schemas and tables inside the database 57 | 58 | * `ddbs_glimpse()`: check first rows of a table 59 | 60 | * `ddbs_buffer()`: calculates the buffer around the input geometry 61 | 62 | * `ddbs_centroid()`: calculates the centroid of the input geometry 63 | 64 | * `ddbs_difference()`: calculates the geometric difference between two objects 65 | 66 | 67 | ## IMPROVEMENTS 68 | 69 | * `ddbs_intersection()`: overwrite argument defaults to `FALSE` instead of `NULL` 70 | 71 | * Better schemas management. Added support for all functions. 72 | 73 | # duckspatial 0.1.0 74 | 75 | * Initial CRAN submission. 76 | -------------------------------------------------------------------------------- /man/ddbs_length.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/ddbs_measure.R 3 | \name{ddbs_length} 4 | \alias{ddbs_length} 5 | \title{Calculates the length of geometries} 6 | \usage{ 7 | ddbs_length( 8 | x, 9 | conn = NULL, 10 | name = NULL, 11 | new_column = NULL, 12 | crs = NULL, 13 | crs_column = "crs_duckspatial", 14 | overwrite = FALSE, 15 | quiet = FALSE 16 | ) 17 | } 18 | \arguments{ 19 | \item{x}{An \code{sf} spatial object. Alternatively, it can be a string with the 20 | name of a table with geometry column within the DuckDB database \code{conn}. 21 | Data is returned from this object.} 22 | 23 | \item{conn}{A connection object to a DuckDB database. If \code{NULL}, the function 24 | runs on a temporary DuckDB database.} 25 | 26 | \item{name}{A character string of length one specifying the name of the table, 27 | or a character string of length two specifying the schema and table 28 | names. If \code{NULL} (the default), the function returns the result as an 29 | \code{sf} object} 30 | 31 | \item{new_column}{Name of the new column to create on the input data. If NULL, 32 | the function will return a vector with the result} 33 | 34 | \item{crs}{The coordinates reference system of the data. Specify if the data 35 | doesn't have a \code{crs_column}, and you know the CRS.} 36 | 37 | \item{crs_column}{a character string of length one specifying the column 38 | storing the CRS (created automatically by \code{\link{ddbs_write_vector}}). 39 | Set to \code{NULL} if absent.} 40 | 41 | \item{overwrite}{Boolean. whether to overwrite the existing table if it exists. Defaults 42 | to \code{FALSE}. This argument is ignored when \code{name} is \code{NULL}.} 43 | 44 | \item{quiet}{A logical value. If \code{TRUE}, suppresses any informational messages. 45 | Defaults to \code{FALSE}.} 46 | } 47 | \value{ 48 | an \code{sf} object or \code{TRUE} (invisibly) for table creation 49 | } 50 | \description{ 51 | Calculates the length of geometries from a DuckDB table or a \code{sf} object 52 | Returns the result as an \code{sf} object with a length column or creates a new table in the database. 53 | Note: Length units depend on the CRS of the input geometries (e.g., meters for projected CRS, 54 | or degrees for geographic CRS). 55 | } 56 | \examples{ 57 | ## load packages 58 | library(duckdb) 59 | library(duckspatial) 60 | library(sf) 61 | 62 | # create a duckdb database in memory (with spatial extension) 63 | conn <- ddbs_create_conn(dbdir = "memory") 64 | 65 | ## read data 66 | rivers_sf <- st_read(system.file("spatial/rivers.geojson", package = "duckspatial")) 67 | 68 | ## store in duckdb 69 | ddbs_write_vector(conn, rivers_sf, "rivers") 70 | 71 | ## calculate length (returns sf object with length column) 72 | ddbs_length("rivers", conn) 73 | 74 | ## calculate length with custom column name 75 | ddbs_length("rivers", conn, new_column = "length_meters") 76 | 77 | ## create a new table with length calculations 78 | ddbs_length("rivers", conn, name = "rivers_with_length") 79 | 80 | ## calculate length in a sf object (without a connection) 81 | ddbs_length(rivers_sf) 82 | } 83 | -------------------------------------------------------------------------------- /man/ddbs_area.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/ddbs_measure.R 3 | \name{ddbs_area} 4 | \alias{ddbs_area} 5 | \title{Calculates the area of geometries} 6 | \usage{ 7 | ddbs_area( 8 | x, 9 | conn = NULL, 10 | name = NULL, 11 | new_column = NULL, 12 | crs = NULL, 13 | crs_column = "crs_duckspatial", 14 | overwrite = FALSE, 15 | quiet = FALSE 16 | ) 17 | } 18 | \arguments{ 19 | \item{x}{An \code{sf} spatial object. Alternatively, it can be a string with the 20 | name of a table with geometry column within the DuckDB database \code{conn}. 21 | Data is returned from this object.} 22 | 23 | \item{conn}{A connection object to a DuckDB database. If \code{NULL}, the function 24 | runs on a temporary DuckDB database.} 25 | 26 | \item{name}{A character string of length one specifying the name of the table, 27 | or a character string of length two specifying the schema and table 28 | names. If \code{NULL} (the default), the function returns the result as an 29 | \code{sf} object} 30 | 31 | \item{new_column}{Name of the new column to create on the input data. If NULL, 32 | the function will return a vector with the result} 33 | 34 | \item{crs}{The coordinates reference system of the data. Specify if the data 35 | doesn't have a \code{crs_column}, and you know the CRS.} 36 | 37 | \item{crs_column}{a character string of length one specifying the column 38 | storing the CRS (created automatically by \code{\link{ddbs_write_vector}}). 39 | Set to \code{NULL} if absent.} 40 | 41 | \item{overwrite}{Boolean. whether to overwrite the existing table if it exists. Defaults 42 | to \code{FALSE}. This argument is ignored when \code{name} is \code{NULL}.} 43 | 44 | \item{quiet}{A logical value. If \code{TRUE}, suppresses any informational messages. 45 | Defaults to \code{FALSE}.} 46 | } 47 | \value{ 48 | a vector, an \code{sf} object or \code{TRUE} (invisibly) for table creation 49 | } 50 | \description{ 51 | Calculates the area of geometries from a DuckDB table or a \code{sf} object 52 | Returns the result as an \code{sf} object with an area column or creates a new table in the database. 53 | Note: Area units depend on the CRS of the input geometries (e.g., square meters for projected CRS, 54 | or degrees for geographic CRS). 55 | } 56 | \examples{ 57 | ## load packages 58 | library(duckdb) 59 | library(duckspatial) 60 | library(sf) 61 | 62 | # create a duckdb database in memory (with spatial extension) 63 | conn <- ddbs_create_conn(dbdir = "memory") 64 | 65 | ## read data 66 | argentina_sf <- st_read(system.file("spatial/argentina.geojson", package = "duckspatial")) |> 67 | st_transform("EPSG:3857") 68 | 69 | ## store in duckdb 70 | ddbs_write_vector(conn, argentina_sf, "argentina") 71 | 72 | ## calculate area (returns sf object with area column) 73 | ddbs_area("argentina", conn) 74 | 75 | ## calculate area with custom column name 76 | ddbs_area("argentina", conn, new_column = "area_sqm") 77 | 78 | ## create a new table with area calculations 79 | ddbs_area("argentina", conn, name = "argentina_with_area") 80 | 81 | ## calculate area in a sf object 82 | ddbs_area(argentina_sf) 83 | } 84 | -------------------------------------------------------------------------------- /_pkgdown.yml: -------------------------------------------------------------------------------- 1 | url: https://cidree.github.io/duckspatial/ 2 | template: 3 | bootstrap: 5 4 | bslib: 5 | bg: '#F5F7FA' 6 | fg: '#202123' 7 | primary: '#333C4A' 8 | secondary: '#ff5733' 9 | pkgdown-nav-height: 75px 10 | base_font: 11 | google: Roboto 12 | heading_font: 13 | google: Merriweather 14 | code_font: 15 | google: Source Code Pro 16 | theme: pygments 17 | authors: 18 | Adrián Cidre González: 19 | href: https://adrian-cidre.com/ 20 | Egor Kotov: 21 | href: https://www.ekotov.pro/ 22 | 23 | reference: 24 | - title: Spatial extension 25 | contents: 26 | - ddbs_install 27 | - ddbs_load 28 | 29 | - title: Read/Write 30 | contents: 31 | - ddbs_read_vector 32 | - ddbs_write_vector 33 | - ddbs_register_vector 34 | 35 | - title: Spatial Predicates 36 | contents: 37 | - ddbs_predicate 38 | - ddbs_contains 39 | - ddbs_contains_properly 40 | - ddbs_covered_by 41 | - ddbs_covers 42 | - ddbs_crosses 43 | - ddbs_disjoint 44 | - ddbs_equals 45 | - ddbs_intersects 46 | - ddbs_intersects_extent 47 | - ddbs_overlaps 48 | - ddbs_touches 49 | - ddbs_within 50 | - ddbs_within_properly 51 | 52 | - title: Spatial operations (binary) 53 | contents: 54 | - ddbs_difference 55 | - ddbs_filter 56 | - ddbs_intersection 57 | - ddbs_join 58 | - ddbs_interpolate_aw 59 | 60 | - title: Spatial operations (unary) 61 | contents: 62 | - ddbs_bbox 63 | - ddbs_boundary 64 | - ddbs_buffer 65 | - ddbs_centroid 66 | - ddbs_concave_hull 67 | - ddbs_convex_hull 68 | - ddbs_is_simple 69 | - ddbs_is_valid 70 | - ddbs_make_valid 71 | - ddbs_simplify 72 | 73 | - title: Spatial operations (measures) 74 | contents: 75 | - ddbs_area 76 | - ddbs_length 77 | 78 | - title: SQL wrappers 79 | contents: 80 | - ddbs_create_conn 81 | - ddbs_stop_conn 82 | - ddbs_create_schema 83 | - ddbs_crs 84 | - ddbs_drivers 85 | - ddbs_glimpse 86 | - ddbs_list_tables 87 | 88 | navbar: 89 | title: duckspatial 90 | bg: dark 91 | left: 92 | - icon: fa-home 93 | href: index.html 94 | - text: Reference 95 | href: reference/index.html 96 | - text: Articles 97 | menu: 98 | - text: Get Started 99 | href: articles/duckspatial.html 100 | - text: "---" 101 | - text: Spatial Joins 102 | href: articles/spatial_joins.html 103 | - text: Areal-Weighted Interpolation 104 | href: articles/aw_interpolation.html 105 | - text: Benchmarks 106 | href: articles/benchmark.html 107 | - text: News 108 | href: news/index.html 109 | structure: 110 | right: 111 | - search 112 | - github 113 | components: 114 | github: 115 | icon: fa-github 116 | href: https://github.com/Cidree/duckspatial 117 | aria-label: GitHub 118 | 119 | articles: 120 | - title: "Introduction" 121 | contents: 122 | - duckspatial 123 | - title: "Advanced Features" 124 | contents: 125 | - spatial_joins 126 | - aw_interpolation 127 | - title: "Performance" 128 | contents: 129 | - benchmark 130 | -------------------------------------------------------------------------------- /R/ddbs_extension.R: -------------------------------------------------------------------------------- 1 | 2 | #' Checks and installs the Spatial extension 3 | #' 4 | #' Checks if a spatial extension is available, and installs it in a DuckDB database 5 | #' 6 | #' @template conn 7 | #' @param upgrade if TRUE, it upgrades the DuckDB extension to the latest version 8 | #' @template quiet 9 | #' 10 | #' @returns TRUE (invisibly) for successful installation 11 | #' @export 12 | #' 13 | #' @examples 14 | #' ## load packages 15 | #' library(duckdb) 16 | #' library(duckspatial) 17 | #' 18 | #' # connect to in memory database 19 | #' conn <- dbConnect(duckdb::duckdb()) 20 | #' 21 | #' # install the spatial extension 22 | #' ddbs_install(conn) 23 | #' 24 | #' # disconnect from db 25 | #' dbDisconnect(conn) 26 | ddbs_install <- function(conn, upgrade = FALSE, quiet = FALSE) { 27 | 28 | # 1. Get extensions list 29 | ext <- DBI::dbGetQuery(conn, "SELECT * FROM duckdb_extensions();") 30 | 31 | # 2. Checks 32 | ## 2.1. Check connection 33 | dbConnCheck(conn) 34 | ## 2.2. Check if spatial extension is available 35 | if (!("spatial" %in% ext$extension_name)) 36 | cli::cli_abort("spatial extension is not available") 37 | ## 2.3. Check if it's installed 38 | spatial_ext <- ext[ext$extension_name == "spatial", ] 39 | if (spatial_ext$installed & !upgrade) { 40 | 41 | if (isFALSE(quiet)) { 42 | cli::cli_alert_info("spatial extension version <{spatial_ext$extension_version}> is already installed in this database") 43 | } 44 | 45 | return(invisible(TRUE)) 46 | } 47 | 48 | # 3. Install extension 49 | suppressMessages(DBI::dbExecute(conn, "INSTALL spatial;")) 50 | 51 | if (isFALSE(quiet)) { 52 | cli::cli_alert_success("Spatial extension installed") 53 | } 54 | 55 | return(invisible(TRUE)) 56 | 57 | 58 | } 59 | 60 | 61 | #' Loads the Spatial extension 62 | #' 63 | #' Checks if a spatial extension is installed, and loads it in a DuckDB database 64 | #' 65 | #' @template conn 66 | #' @template quiet 67 | #' 68 | #' @returns TRUE (invisibly) for successful installation 69 | #' @export 70 | #' 71 | #' @examplesIf interactive() 72 | #' ## load packages 73 | #' library(duckdb) 74 | #' library(duckspatial) 75 | #' 76 | #' ## connect to in memory database 77 | #' conn <- dbConnect(duckdb::duckdb()) 78 | #' 79 | #' ## install the spatial exntesion 80 | #' ddbs_install(conn) 81 | #' ddbs_load(conn) 82 | #' 83 | #' ## disconnect from db 84 | #' dbDisconnect(conn) 85 | ddbs_load <- function(conn, quiet = FALSE) { 86 | 87 | # 1. Get extensions list 88 | ext <- DBI::dbGetQuery(conn, "SELECT * FROM duckdb_extensions();") 89 | 90 | # 2. Checks 91 | ## 2.1. Check connection 92 | dbConnCheck(conn) 93 | ## 2.2. Check if spatial extension is installed 94 | spatial_ext <- ext[ext$extension_name == "spatial", ] 95 | if (!spatial_ext$installed) 96 | cli::cli_abort("spatial extension is not installed, please use `ddbs_install()`") 97 | 98 | # 3. Load spatial extension 99 | if (isFALSE(spatial_ext$loaded)) suppressMessages(DBI::dbExecute(conn, "LOAD spatial;")) 100 | 101 | 102 | if (isFALSE(quiet)) { 103 | cli::cli_alert_success("Spatial extension loaded") 104 | } 105 | 106 | } 107 | -------------------------------------------------------------------------------- /.github/workflows/rhub.yaml: -------------------------------------------------------------------------------- 1 | # R-hub's generic GitHub Actions workflow file. It's canonical location is at 2 | # https://github.com/r-hub/actions/blob/v1/workflows/rhub.yaml 3 | # You can update this file to a newer version using the rhub2 package: 4 | # 5 | # rhub::rhub_setup() 6 | # 7 | # It is unlikely that you need to modify this file manually. 8 | 9 | name: R-hub 10 | run-name: "${{ github.event.inputs.id }}: ${{ github.event.inputs.name || format('Manually run by {0}', github.triggering_actor) }}" 11 | 12 | on: 13 | workflow_dispatch: 14 | inputs: 15 | config: 16 | description: 'A comma separated list of R-hub platforms to use.' 17 | type: string 18 | default: 'linux,windows,macos' 19 | name: 20 | description: 'Run name. You can leave this empty now.' 21 | type: string 22 | id: 23 | description: 'Unique ID. You can leave this empty now.' 24 | type: string 25 | 26 | jobs: 27 | 28 | setup: 29 | runs-on: ubuntu-latest 30 | outputs: 31 | containers: ${{ steps.rhub-setup.outputs.containers }} 32 | platforms: ${{ steps.rhub-setup.outputs.platforms }} 33 | 34 | steps: 35 | # NO NEED TO CHECKOUT HERE 36 | - uses: r-hub/actions/setup@v1 37 | with: 38 | config: ${{ github.event.inputs.config }} 39 | id: rhub-setup 40 | 41 | linux-containers: 42 | needs: setup 43 | if: ${{ needs.setup.outputs.containers != '[]' }} 44 | runs-on: ubuntu-latest 45 | name: ${{ matrix.config.label }} 46 | strategy: 47 | fail-fast: false 48 | matrix: 49 | config: ${{ fromJson(needs.setup.outputs.containers) }} 50 | container: 51 | image: ${{ matrix.config.container }} 52 | 53 | steps: 54 | - uses: r-hub/actions/checkout@v1 55 | - uses: r-hub/actions/platform-info@v1 56 | with: 57 | token: ${{ secrets.RHUB_TOKEN }} 58 | job-config: ${{ matrix.config.job-config }} 59 | - uses: r-hub/actions/setup-deps@v1 60 | with: 61 | token: ${{ secrets.RHUB_TOKEN }} 62 | job-config: ${{ matrix.config.job-config }} 63 | - uses: r-hub/actions/run-check@v1 64 | with: 65 | token: ${{ secrets.RHUB_TOKEN }} 66 | job-config: ${{ matrix.config.job-config }} 67 | 68 | other-platforms: 69 | needs: setup 70 | if: ${{ needs.setup.outputs.platforms != '[]' }} 71 | runs-on: ${{ matrix.config.os }} 72 | name: ${{ matrix.config.label }} 73 | strategy: 74 | fail-fast: false 75 | matrix: 76 | config: ${{ fromJson(needs.setup.outputs.platforms) }} 77 | 78 | steps: 79 | - uses: r-hub/actions/checkout@v1 80 | - uses: r-hub/actions/setup-r@v1 81 | with: 82 | job-config: ${{ matrix.config.job-config }} 83 | token: ${{ secrets.RHUB_TOKEN }} 84 | - uses: r-hub/actions/platform-info@v1 85 | with: 86 | token: ${{ secrets.RHUB_TOKEN }} 87 | job-config: ${{ matrix.config.job-config }} 88 | - uses: r-hub/actions/setup-deps@v1 89 | with: 90 | job-config: ${{ matrix.config.job-config }} 91 | token: ${{ secrets.RHUB_TOKEN }} 92 | - uses: r-hub/actions/run-check@v1 93 | with: 94 | job-config: ${{ matrix.config.job-config }} 95 | token: ${{ secrets.RHUB_TOKEN }} 96 | -------------------------------------------------------------------------------- /man/ddbs_concave_hull.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/ddbs_concave_hull.R 3 | \name{ddbs_concave_hull} 4 | \alias{ddbs_concave_hull} 5 | \title{Returns the concave hull enclosing the geometry} 6 | \usage{ 7 | ddbs_concave_hull( 8 | x, 9 | ratio = 0.5, 10 | allow_holes = TRUE, 11 | conn = NULL, 12 | name = NULL, 13 | crs = NULL, 14 | crs_column = "crs_duckspatial", 15 | overwrite = FALSE, 16 | quiet = FALSE 17 | ) 18 | } 19 | \arguments{ 20 | \item{x}{An \code{sf} spatial object. Alternatively, it can be a string with the 21 | name of a table with geometry column within the DuckDB database \code{conn}. 22 | Data is returned from this object.} 23 | 24 | \item{ratio}{Numeric. The ratio parameter dictates the level of concavity; \code{1} 25 | returns the convex hull, while \code{0} indicates to return the most concave 26 | hull possible. Defaults to \code{0.5}.} 27 | 28 | \item{allow_holes}{Boolean. If \code{TRUE} (the default), it allows the output to 29 | contain holes.} 30 | 31 | \item{conn}{A connection object to a DuckDB database. If \code{NULL}, the function 32 | runs on a temporary DuckDB database.} 33 | 34 | \item{name}{A character string of length one specifying the name of the table, 35 | or a character string of length two specifying the schema and table 36 | names. If \code{NULL} (the default), the function returns the result as an 37 | \code{sf} object} 38 | 39 | \item{crs}{The coordinates reference system of the data. Specify if the data 40 | doesn't have a \code{crs_column}, and you know the CRS.} 41 | 42 | \item{crs_column}{a character string of length one specifying the column 43 | storing the CRS (created automatically by \code{\link{ddbs_write_vector}}). 44 | Set to \code{NULL} if absent.} 45 | 46 | \item{overwrite}{Boolean. whether to overwrite the existing table if it exists. Defaults 47 | to \code{FALSE}. This argument is ignored when \code{name} is \code{NULL}.} 48 | 49 | \item{quiet}{A logical value. If \code{TRUE}, suppresses any informational messages. 50 | Defaults to \code{FALSE}.} 51 | } 52 | \value{ 53 | an \code{sf} object or \code{TRUE} (invisibly) for table creation 54 | } 55 | \description{ 56 | Returns the concave hull enclosing the geometry from an \code{sf} object or 57 | from a DuckDB table using the spatial extension. Returns the result as an 58 | \code{sf} object or creates a new table in the database. 59 | } 60 | \examples{ 61 | \dontrun{ 62 | ## load packages 63 | library(duckdb) 64 | library(duckspatial) 65 | library(sf) 66 | 67 | # create points data 68 | n <- 5 69 | points_sf <- data.frame( 70 | id = 1, 71 | x = runif(n, min = -180, max = 180), 72 | y = runif(n, min = -90, max = 90) 73 | ) |> 74 | sf::st_as_sf(coords = c("x", "y"), crs = 4326) |> 75 | st_geometry() |> 76 | st_combine() |> 77 | st_cast("MULTIPOINT") |> 78 | st_as_sf() 79 | 80 | # option 1: passing sf objects 81 | output1 <- duckspatial::ddbs_concave_hull(x = points_sf) 82 | 83 | plot(output1) 84 | 85 | 86 | # option 2: passing the name of a table in a duckdb db 87 | 88 | # creates a duckdb 89 | conn <- duckspatial::ddbs_create_conn() 90 | 91 | # write sf to duckdb 92 | ddbs_write_vector(conn, points_sf, "points_tbl") 93 | 94 | # spatial join 95 | output2 <- duckspatial::ddbs_concave_hull( 96 | conn = conn, 97 | x = "points_tbl" 98 | ) 99 | 100 | plot(output2) 101 | 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /R/ddbs_boundary.R: -------------------------------------------------------------------------------- 1 | #' Returns the boundary of geometries 2 | #' 3 | #' Returns the boundary of geometries from a DuckDB table using the spatial extension. 4 | #' Returns the result as an \code{sf} object or creates a new table in the database. 5 | #' 6 | #' @template x 7 | #' @template conn_null 8 | #' @template name 9 | #' @template crs 10 | #' @template overwrite 11 | #' @template quiet 12 | #' 13 | #' @returns an \code{sf} object or \code{TRUE} (invisibly) for table creation 14 | #' @export 15 | #' 16 | #' @examples 17 | #' \dontrun{ 18 | #' ## load packages 19 | #' library(duckdb) 20 | #' library(duckspatial) 21 | #' library(sf) 22 | #' 23 | #' # create a duckdb database in memory (with spatial extension) 24 | #' conn <- ddbs_create_conn(dbdir = "memory") 25 | #' 26 | #' # read data 27 | #' argentina_sf <- st_read(system.file("spatial/argentina.geojson", package = "duckspatial")) 28 | #' 29 | #' # store in duckdb 30 | #' ddbs_write_vector(conn, argentina_sf, "argentina") 31 | #' 32 | #' # boundary 33 | #' b <- ddbs_boundary("argentina", conn) 34 | #' } 35 | ddbs_boundary <- function( 36 | x, 37 | conn = NULL, 38 | name = NULL, 39 | crs = NULL, 40 | crs_column = "crs_duckspatial", 41 | overwrite = FALSE, 42 | quiet = FALSE) { 43 | 44 | ## 0. Handle errors 45 | assert_xy(x, "x") 46 | assert_name(name) 47 | assert_logic(overwrite, "overwrite") 48 | assert_logic(quiet, "quiet") 49 | assert_conn_character(conn, x) 50 | 51 | # 1. Manage connection to DB 52 | ## 1.1. check if connection is provided, otherwise create a temporary connection 53 | is_duckdb_conn <- dbConnCheck(conn) 54 | if (isFALSE(is_duckdb_conn)) { 55 | conn <- duckspatial::ddbs_create_conn() 56 | on.exit(duckdb::dbDisconnect(conn), add = TRUE) 57 | } 58 | ## 1.2. get query list of table names 59 | x_list <- get_query_list(x, conn) 60 | 61 | ## 2. get name of geometry column 62 | x_geom <- get_geom_name(conn, x_list$query_name) 63 | x_rest <- get_geom_name(conn, x_list$query_name, rest = TRUE) 64 | assert_geometry_column(x_geom, x_list) 65 | 66 | ## 3. if name is not NULL (i.e. no SF returned) 67 | if (!is.null(name)) { 68 | 69 | ## convenient names of table and/or schema.table 70 | name_list <- get_query_name(name) 71 | 72 | ## handle overwrite 73 | overwrite_table(name_list$query_name, conn, quiet, overwrite) 74 | 75 | ## create query (no st_as_text) 76 | if (length(x_rest) == 0) { 77 | tmp.query <- glue::glue(" 78 | SELECT ST_Boundary({x_geom}}) as {x_geom} FROM {x_list$query_name}; 79 | ") 80 | } else { 81 | tmp.query <- glue::glue(" 82 | SELECT {paste0(x_rest, collapse = ', ')}, ST_Boundary({x_geom}) as {x_geom} FROM {x_list$query_name}; 83 | ") 84 | } 85 | ## execute intersection query 86 | DBI::dbExecute(conn, glue::glue("CREATE TABLE {name_list$query_name} AS {tmp.query}")) 87 | feedback_query(quiet) 88 | return(invisible(TRUE)) 89 | } 90 | 91 | ## 4. create the base query 92 | if (length(x_rest) == 0) { 93 | tmp.query <- glue::glue(" 94 | SELECT ST_AsText(ST_Boundary({x_geom})) as {x_geom} FROM {x_list$query_name}; 95 | ") 96 | } else { 97 | tmp.query <- glue::glue(" 98 | SELECT {paste0(x_rest, collapse = ', ')}, ST_AsText(ST_Boundary({x_geom})) as {x_geom} FROM {x_list$query_name}; 99 | ") 100 | } 101 | ## send the query 102 | data_tbl <- DBI::dbGetQuery(conn, tmp.query) 103 | 104 | ## 5. convert to SF and return result 105 | data_sf <- convert_to_sf( 106 | data = data_tbl, 107 | crs = crs, 108 | crs_column = crs_column, 109 | x_geom = x_geom 110 | ) 111 | 112 | feedback_query(quiet) 113 | return(data_sf) 114 | } 115 | -------------------------------------------------------------------------------- /man/ddbs_filter.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/ddbs_filter.R 3 | \name{ddbs_filter} 4 | \alias{ddbs_filter} 5 | \title{Performs spatial filter of two geometries} 6 | \usage{ 7 | ddbs_filter( 8 | x, 9 | y, 10 | predicate = "intersects", 11 | conn = NULL, 12 | name = NULL, 13 | crs = NULL, 14 | crs_column = "crs_duckspatial", 15 | overwrite = FALSE, 16 | quiet = FALSE 17 | ) 18 | } 19 | \arguments{ 20 | \item{x}{An \code{sf} spatial object. Alternatively, it can be a string with the 21 | name of a table with geometry column within the DuckDB database \code{conn}. 22 | Data is returned from this object.} 23 | 24 | \item{y}{Y table with geometry column within the DuckDB database} 25 | 26 | \item{predicate}{A geometry predicate function. Defaults to \code{intersects}, 27 | a wrapper of \code{ST_Intersects}. See details for other options.} 28 | 29 | \item{conn}{A connection object to a DuckDB database. If \code{NULL}, the function 30 | runs on a temporary DuckDB database.} 31 | 32 | \item{name}{A character string of length one specifying the name of the table, 33 | or a character string of length two specifying the schema and table 34 | names. If \code{NULL} (the default), the function returns the result as an 35 | \code{sf} object} 36 | 37 | \item{crs}{The coordinates reference system of the data. Specify if the data 38 | doesn't have a \code{crs_column}, and you know the CRS.} 39 | 40 | \item{crs_column}{a character string of length one specifying the column 41 | storing the CRS (created automatically by \code{\link{ddbs_write_vector}}). 42 | Set to \code{NULL} if absent.} 43 | 44 | \item{overwrite}{Boolean. whether to overwrite the existing table if it exists. Defaults 45 | to \code{FALSE}. This argument is ignored when \code{name} is \code{NULL}.} 46 | 47 | \item{quiet}{A logical value. If \code{TRUE}, suppresses any informational messages. 48 | Defaults to \code{FALSE}.} 49 | } 50 | \value{ 51 | An sf object or TRUE (invisibly) for table creation 52 | } 53 | \description{ 54 | Filters data spatially based on a spatial predicate 55 | } 56 | \details{ 57 | Spatial Join Predicates: 58 | 59 | A spatial predicate is really just a function that evaluates some spatial 60 | relation between two geometries and returns true or false, e.g., “does a 61 | contain b” or “is a within distance x of b”. Here is a quick overview of the 62 | most commonly used ones, taking two geometries a and b: 63 | \itemize{ 64 | \item \code{"ST_Intersects"}: Whether a intersects b 65 | \item \code{"ST_Contains"}: Whether a contains b 66 | \item \code{"ST_ContainsProperly"}: Whether a contains b without b touching a's boundary 67 | \item \code{"ST_Within"}: Whether a is within b 68 | \item \code{"ST_Overlaps"}: Whether a overlaps b 69 | \item \code{"ST_Touches"}: Whether a touches b 70 | \item \code{"ST_Equals"}: Whether a is equal to b 71 | \item \code{"ST_Crosses"}: Whether a crosses b 72 | \item \code{"ST_Covers"}: Whether a covers b 73 | \item \code{"ST_CoveredBy"}: Whether a is covered by b 74 | \item \code{"ST_DWithin"}: x) Whether a is within distance x of b 75 | } 76 | } 77 | \examples{ 78 | \dontrun{ 79 | ## load packages 80 | library(duckdb) 81 | library(duckspatial) 82 | library(sf) 83 | 84 | # create a duckdb database in memory (with spatial extension) 85 | conn <- ddbs_create_conn(dbdir = "memory") 86 | 87 | ## read data 88 | countries_sf <- st_read(system.file("spatial/countries.geojson", package = "duckspatial")) 89 | argentina_sf <- st_read(system.file("spatial/argentina.geojson", package = "duckspatial")) 90 | 91 | ## store in duckdb 92 | ddbs_write_vector(conn, countries_sf, "countries") 93 | ddbs_write_vector(conn, argentina_sf, "argentina") 94 | 95 | ## filter countries touching argentina 96 | ddbs_filter(conn = conn, "countries", "argentina", predicate = "touches") 97 | 98 | ## filter without using a connection 99 | ddbs_filter(countries_sf, argentina_sf, predicate = "touches") 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /vignettes/benchmark.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Benchmark" 3 | date: "`r Sys.Date()`" 4 | output: rmarkdown::html_vignette 5 | code-annotations: hover 6 | urlcolor: blue 7 | vignette: > 8 | %\VignetteIndexEntry{Benchmark} 9 | %\VignetteEngine{knitr::rmarkdown} 10 | \usepackage[utf8]{inputenc} 11 | --- 12 | 13 | ```{r, include = FALSE} 14 | knitr::opts_chunk$set( 15 | collapse = TRUE, 16 | comment = "#>", 17 | eval = identical(tolower(Sys.getenv("NOT_CRAN")), "true"), 18 | out.width = "100%" 19 | ) 20 | 21 | # Initialize variables to prevent "object not found" error when eval=FALSE 22 | time_diff <- "XX" 23 | memo_diff <- "XX" 24 | 25 | # CRAN OMP THREAD LIMIT to avoid CRAN NOTE 26 | Sys.setenv(OMP_THREAD_LIMIT = 2) 27 | ``` 28 | 29 | This vignette shows a few benchmarks comparing **{duckspatial}** vs **{sf}**. We look 30 | at how both packages compare in terms of computation time and memory use when 31 | performing different spatial operations with increasingly large data sets. We plan 32 | to extend this vignette in the future to benchmark other types of spatial operations. 33 | 34 | # Spatial Join 35 | 36 | Here we analyze how {duckspatial} and {sf} compare when performing a spatial join 37 | between points and polygons with increasingly large numbers of points. 38 | 39 | ## TL;DR 40 | 41 | - {sf} is faster for small data sets, when the time and memory differences really 42 | don't matter that much. However, for large data sets (e.g. above 100K points), 43 | {duckspatial} is much faster and uses way less memory. 44 | 45 | ```{r, message = FALSE} 46 | library(duckspatial) 47 | library(bench) 48 | library(dplyr) 49 | library(ggplot2) 50 | 51 | # read polygons data 52 | countries_sf <- sf::st_read(system.file("spatial/countries.geojson", package = "duckspatial")) 53 | 54 | run_benchmark <- function(n){ 55 | 56 | set.seed(42) 57 | 58 | ## create points data 59 | points_sf <- data.frame( 60 | id = 1:n, 61 | x = runif(n, min = -180, max = 180), 62 | y = runif(n, min = -90, max = 90) 63 | ) |> 64 | sf::st_as_sf(coords = c("x", "y"), crs = 4326) 65 | 66 | temp_bench <- bench::mark( 67 | iterations = 1, 68 | check = FALSE, 69 | duckspatial = duckspatial::ddbs_join( 70 | x = points_sf, 71 | y = countries_sf, 72 | join = "within"), 73 | 74 | sf = sf::st_join( 75 | x = points_sf, 76 | y = countries_sf, 77 | join = sf::st_within) 78 | ) 79 | 80 | temp_bench$n <- n 81 | temp_bench$pkg <- c("duckspatial", "sf") 82 | 83 | return(temp_bench) 84 | } 85 | 86 | 87 | # From 10K points to 10 million points 88 | df_bench <- lapply( 89 | X = c(10e3, 10e4, 10e5), 90 | FUN = run_benchmark 91 | ) |> 92 | dplyr::bind_rows() 93 | 94 | ``` 95 | 96 | ```{r, echo=FALSE} 97 | # calculate difference in performance 98 | temp <- df_bench |> 99 | filter(n == 10e5) 100 | 101 | memo_diff <- round(as.numeric(temp$mem_alloc[2] / temp$mem_alloc[1]),1) 102 | time_diff <- (1 - round(as.numeric(temp$median[1] / temp$median[2]),1))*100 103 | ``` 104 | 105 | Now let's have a look at the results. 106 | 107 | 108 | As one would expect, {sf} is faster for small data sets, when when the time 109 | difference is less than a couple seconds. For larger data sets, though, 110 | {duckspatial} gets much more efficient. In this example working with 10 million 111 | points, {duckspatial} was `r time_diff`% faster and used `r memo_diff` times less 112 | memory than {sf}. Not bad. 113 | 114 | 115 | ```{r, warning=FALSE} 116 | ggplot(data = df_bench) + 117 | geom_point(size =3, aes(x= mem_alloc, y = median, color = pkg, 118 | shape = format(n, big.mark = ".") 119 | )) + 120 | labs(color= "Package", shape = "Data size", 121 | y = "Computation time (seconds)", 122 | x = "Memory allocated") + 123 | theme_minimal() 124 | 125 | 126 | ``` 127 | -------------------------------------------------------------------------------- /tests/testthat/test-ddbs_convex_hull.R: -------------------------------------------------------------------------------- 1 | # skip tests on CRAN because they take too much time 2 | skip_if(Sys.getenv("TEST_ONE") != "") 3 | testthat::skip_on_cran() 4 | testthat::skip_if_not_installed("duckdb") 5 | 6 | 7 | argentina_sf <- sf::st_read(system.file("spatial/argentina.geojson", package = "duckspatial")) 8 | 9 | 10 | # helpers -------------------------------------------------------------- 11 | 12 | # create duckdb connection 13 | conn_test <- duckspatial::ddbs_create_conn() 14 | 15 | # helper function 16 | tester <- function(x = argentina_sf, 17 | conn = NULL, 18 | name = NULL, 19 | crs = NULL, 20 | crs_column = "crs_duckspatial", 21 | overwrite = FALSE, 22 | quiet = FALSE) { 23 | ddbs_convex_hull( 24 | x, 25 | conn, 26 | name, 27 | crs, 28 | crs_column, 29 | overwrite, 30 | quiet 31 | ) 32 | } 33 | 34 | 35 | # expected behavior -------------------------------------------------------------- 36 | 37 | 38 | testthat::test_that("expected behavior", { 39 | 40 | # option 1: passing sf objects 41 | output1 <- tester( 42 | x = argentina_sf 43 | ) 44 | 45 | testthat::expect_true(is(output1 , 'sf')) 46 | 47 | # option 2: passing the names of tables in a duckdb db, returing sf 48 | # write sf to duckdb 49 | ddbs_write_vector(conn_test, argentina_sf, "argentina_tbl", overwrite = TRUE) 50 | 51 | # spatial join 52 | output2 <- tester( 53 | conn_test, 54 | x = "argentina_tbl" 55 | ) 56 | 57 | testthat::expect_true(is(output2 , 'sf')) 58 | 59 | # option 3: passing the names of tables in a duckdb db, creating new table in db 60 | output3 <- tester( 61 | conn_test, 62 | x = "argentina_tbl", 63 | name = "test_result", 64 | overwrite = TRUE 65 | ) 66 | 67 | testthat::expect_true(output3) 68 | 69 | # TODO - Review this because it fails 70 | # output3 <- DBI::dbReadTable(conn_test, "test_result") |> 71 | # sf::st_as_sf(wkt = 'geometry') 72 | 73 | # testthat::expect_true(is(output3 , 'sf')) 74 | 75 | testthat::expect_true( 76 | is(ddbs_read_vector(conn_test, name = "test_result", crs = 4326) , 77 | 'sf' 78 | ) 79 | ) 80 | 81 | 82 | 83 | # show and suppress messages 84 | testthat::expect_message( tester() ) 85 | testthat::expect_no_message( tester(quiet = TRUE)) 86 | 87 | 88 | }) 89 | 90 | 91 | testthat::test_that("error if table already exists", { 92 | 93 | # write table for the 1st time 94 | testthat::expect_true(tester(x = "argentina_tbl", 95 | conn = conn_test, 96 | name = 'banana', 97 | overwrite = FALSE) 98 | ) 99 | 100 | # expected error if overwrite = FALSE 101 | testthat::expect_error(tester(x = "argentina_tbl", 102 | conn = conn_test, 103 | name = 'banana', 104 | overwrite = FALSE)) 105 | 106 | # overwrite table 107 | testthat::expect_true(tester(x = "argentina_tbl", 108 | conn = conn_test, 109 | name = 'banana', 110 | overwrite = TRUE)) 111 | 112 | 113 | }) 114 | 115 | # expected errors -------------------------------------------------------------- 116 | 117 | testthat::test_that("errors with incorrect input", { 118 | 119 | testthat::expect_error(tester(x = 999)) 120 | testthat::expect_error(tester(conn = 999)) 121 | testthat::expect_error(tester(overwrite = 999)) 122 | testthat::expect_error(tester(quiet = 999)) 123 | 124 | testthat::expect_error(tester(x = "999", conn = conn_test)) 125 | 126 | testthat::expect_error(tester(conn = conn_test, name = c('banana', 'banana'))) 127 | 128 | 129 | }) 130 | 131 | -------------------------------------------------------------------------------- /tests/testthat/test-ddbs_bbox.R: -------------------------------------------------------------------------------- 1 | # skip tests on CRAN because they take too much time 2 | skip_if(Sys.getenv("TEST_ONE") != "") 3 | testthat::skip_on_cran() 4 | testthat::skip_if_not_installed("duckdb") 5 | 6 | 7 | rivers_sf <- sf::st_read(system.file("spatial/rivers.geojson", package = "duckspatial")) 8 | 9 | 10 | # helpers -------------------------------------------------------------- 11 | 12 | # create duckdb connection 13 | conn_test <- duckspatial::ddbs_create_conn() 14 | 15 | # helper function 16 | tester <- function(x = rivers_sf, 17 | by_feature = FALSE, 18 | conn = NULL, 19 | name = NULL, 20 | crs = NULL, 21 | crs_column = "crs_duckspatial", 22 | overwrite = FALSE, 23 | quiet = FALSE) { 24 | ddbs_bbox( 25 | x, 26 | by_feature, 27 | conn, 28 | name, 29 | crs, 30 | crs_column, 31 | overwrite, 32 | quiet 33 | ) 34 | } 35 | 36 | 37 | # expected behavior -------------------------------------------------------------- 38 | 39 | 40 | testthat::test_that("expected behavior", { 41 | 42 | # option 1: passing sf objects 43 | output1 <- tester( 44 | x = rivers_sf 45 | ) 46 | 47 | testthat::expect_true(is(output1 , 'data.frame')) 48 | 49 | # option 2: passing the names of tables in a duckdb db, returing sf 50 | # write sf to duckdb 51 | ddbs_write_vector(conn_test, rivers_sf, "rivers_tbl", overwrite = TRUE) 52 | 53 | # spatial join 54 | output2 <- tester( 55 | conn = conn_test, 56 | x = "rivers_tbl" 57 | ) 58 | 59 | testthat::expect_true(is(output2 , 'data.frame')) 60 | 61 | # option 3: passing the names of tables in a duckdb db, creating new table in db 62 | output3 <- tester( 63 | conn = conn_test, 64 | x = "rivers_tbl", 65 | name = "test_result", 66 | overwrite = TRUE 67 | ) 68 | 69 | testthat::expect_true(output3) 70 | 71 | # read table from db 72 | output3 <- DBI::dbReadTable(conn_test, "test_result") 73 | testthat::expect_true(is(output3 , 'data.frame')) 74 | 75 | 76 | # show and suppress messages 77 | testthat::expect_message( tester() ) 78 | testthat::expect_no_message( tester(quiet = TRUE)) 79 | 80 | 81 | }) 82 | 83 | 84 | testthat::test_that("expected behavior of by_feature", { 85 | 86 | output1 <- tester( 87 | x = rivers_sf, 88 | by_feature = FALSE 89 | ) 90 | 91 | testthat::expect_true(nrow(output1)==1) 92 | 93 | output2 <- tester( 94 | x = rivers_sf, 95 | by_feature = TRUE 96 | ) 97 | 98 | testthat::expect_true(nrow(output2)==nrow(rivers_sf)) 99 | 100 | 101 | }) 102 | 103 | 104 | testthat::test_that("error if table already exists", { 105 | 106 | # write table for the 1st time 107 | testthat::expect_true(tester(x = "rivers_tbl", 108 | conn = conn_test, 109 | name = 'banana', 110 | overwrite = FALSE) 111 | ) 112 | 113 | # expected error if overwrite = FALSE 114 | testthat::expect_error(tester(x = "rivers_tbl", 115 | conn = conn_test, 116 | name = 'banana', 117 | overwrite = FALSE)) 118 | 119 | # overwrite table 120 | testthat::expect_true(tester(x = "rivers_tbl", 121 | conn = conn_test, 122 | name = 'banana', 123 | overwrite = TRUE)) 124 | 125 | 126 | }) 127 | 128 | # expected errors -------------------------------------------------------------- 129 | 130 | testthat::test_that("errors with incorrect input", { 131 | 132 | testthat::expect_error(tester(x = 999)) 133 | testthat::expect_error(tester(conn = 999)) 134 | testthat::expect_error(tester(by_feature = 999)) 135 | testthat::expect_error(tester(overwrite = 999)) 136 | testthat::expect_error(tester(quiet = 999)) 137 | 138 | testthat::expect_error(tester(x = "999", conn = conn_test)) 139 | 140 | testthat::expect_error(tester(conn = conn_test, name = c('banana', 'banana'))) 141 | 142 | 143 | }) 144 | 145 | -------------------------------------------------------------------------------- /docs/deps/headroom-0.11.0/headroom.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * headroom.js v0.11.0 - Give your page some headroom. Hide your header until you need it 3 | * Copyright (c) 2020 Nick Williams - http://wicky.nillia.ms/headroom.js 4 | * License: MIT 5 | */ 6 | 7 | !function(t,n){"object"==typeof exports&&"undefined"!=typeof module?module.exports=n():"function"==typeof define&&define.amd?define(n):(t=t||self).Headroom=n()}(this,function(){"use strict";function t(){return"undefined"!=typeof window}function d(t){return function(t){return t&&t.document&&function(t){return 9===t.nodeType}(t.document)}(t)?function(t){var n=t.document,o=n.body,s=n.documentElement;return{scrollHeight:function(){return Math.max(o.scrollHeight,s.scrollHeight,o.offsetHeight,s.offsetHeight,o.clientHeight,s.clientHeight)},height:function(){return t.innerHeight||s.clientHeight||o.clientHeight},scrollY:function(){return void 0!==t.pageYOffset?t.pageYOffset:(s||o.parentNode||o).scrollTop}}}(t):function(t){return{scrollHeight:function(){return Math.max(t.scrollHeight,t.offsetHeight,t.clientHeight)},height:function(){return Math.max(t.offsetHeight,t.clientHeight)},scrollY:function(){return t.scrollTop}}}(t)}function n(t,s,e){var n,o=function(){var n=!1;try{var t={get passive(){n=!0}};window.addEventListener("test",t,t),window.removeEventListener("test",t,t)}catch(t){n=!1}return n}(),i=!1,r=d(t),l=r.scrollY(),a={};function c(){var t=Math.round(r.scrollY()),n=r.height(),o=r.scrollHeight();a.scrollY=t,a.lastScrollY=l,a.direction=ls.tolerance[a.direction],e(a),l=t,i=!1}function h(){i||(i=!0,n=requestAnimationFrame(c))}var u=!!o&&{passive:!0,capture:!1};return t.addEventListener("scroll",h,u),c(),{destroy:function(){cancelAnimationFrame(n),t.removeEventListener("scroll",h,u)}}}function o(t,n){n=n||{},Object.assign(this,o.options,n),this.classes=Object.assign({},o.options.classes,n.classes),this.elem=t,this.tolerance=function(t){return t===Object(t)?t:{down:t,up:t}}(this.tolerance),this.initialised=!1,this.frozen=!1}return o.prototype={constructor:o,init:function(){return o.cutsTheMustard&&!this.initialised&&(this.addClass("initial"),this.initialised=!0,setTimeout(function(t){t.scrollTracker=n(t.scroller,{offset:t.offset,tolerance:t.tolerance},t.update.bind(t))},100,this)),this},destroy:function(){this.initialised=!1,Object.keys(this.classes).forEach(this.removeClass,this),this.scrollTracker.destroy()},unpin:function(){!this.hasClass("pinned")&&this.hasClass("unpinned")||(this.addClass("unpinned"),this.removeClass("pinned"),this.onUnpin&&this.onUnpin.call(this))},pin:function(){this.hasClass("unpinned")&&(this.addClass("pinned"),this.removeClass("unpinned"),this.onPin&&this.onPin.call(this))},freeze:function(){this.frozen=!0,this.addClass("frozen")},unfreeze:function(){this.frozen=!1,this.removeClass("frozen")},top:function(){this.hasClass("top")||(this.addClass("top"),this.removeClass("notTop"),this.onTop&&this.onTop.call(this))},notTop:function(){this.hasClass("notTop")||(this.addClass("notTop"),this.removeClass("top"),this.onNotTop&&this.onNotTop.call(this))},bottom:function(){this.hasClass("bottom")||(this.addClass("bottom"),this.removeClass("notBottom"),this.onBottom&&this.onBottom.call(this))},notBottom:function(){this.hasClass("notBottom")||(this.addClass("notBottom"),this.removeClass("bottom"),this.onNotBottom&&this.onNotBottom.call(this))},shouldUnpin:function(t){return"down"===t.direction&&!t.top&&t.toleranceExceeded},shouldPin:function(t){return"up"===t.direction&&t.toleranceExceeded||t.top},addClass:function(t){this.elem.classList.add.apply(this.elem.classList,this.classes[t].split(" "))},removeClass:function(t){this.elem.classList.remove.apply(this.elem.classList,this.classes[t].split(" "))},hasClass:function(t){return this.classes[t].split(" ").every(function(t){return this.classList.contains(t)},this.elem)},update:function(t){t.isOutOfBounds||!0!==this.frozen&&(t.top?this.top():this.notTop(),t.bottom?this.bottom():this.notBottom(),this.shouldUnpin(t)?this.unpin():this.shouldPin(t)&&this.pin())}},o.options={tolerance:{up:0,down:0},offset:0,scroller:t()?window:null,classes:{frozen:"headroom--frozen",pinned:"headroom--pinned",unpinned:"headroom--unpinned",top:"headroom--top",notTop:"headroom--not-top",bottom:"headroom--bottom",notBottom:"headroom--not-bottom",initial:"headroom"}},o.cutsTheMustard=!!(t()&&function(){}.bind&&"classList"in document.documentElement&&Object.assign&&Object.keys&&requestAnimationFrame),o}); -------------------------------------------------------------------------------- /tests/testthat/test-db_read.R: -------------------------------------------------------------------------------- 1 | # skip tests on CRAN 2 | skip_on_cran() 3 | skip_if_not_installed("duckdb") 4 | skip_if_not_installed("sf") 5 | 6 | # Setup: connection and data 7 | conn_test <- duckspatial::ddbs_create_conn() 8 | 9 | # Write some data to test against 10 | ddbs_write_vector(conn_test, points_sf, "test_points_read", overwrite = TRUE) 11 | ddbs_write_vector(conn_test, countries_sf, "test_countries_read", overwrite = TRUE) 12 | ddbs_register_vector(conn_test, points_sf, "test_points_view_read", overwrite = TRUE) 13 | 14 | # 1. Basic reading from tables and views ---- 15 | test_that("ddbs_read_vector reads a table into an sf object", { 16 | # Read from a table created with ddbs_write_vector 17 | result <- ddbs_read_vector(conn_test, "test_points_read", crs = 4326) 18 | 19 | expect_s3_class(result, "sf") 20 | expect_equal(nrow(result), nrow(points_sf)) 21 | expect_equal(sf::st_crs(result), sf::st_crs(points_sf)) 22 | expect_true(all(c("id", "geometry") %in% names(result))) 23 | }) 24 | 25 | test_that("ddbs_read_vector reads an Arrow view into an sf object", { 26 | # Read from a view created with ddbs_register_vector 27 | result <- ddbs_read_vector(conn_test, "test_points_view_read", crs = 4326) 28 | 29 | expect_s3_class(result, "sf") 30 | expect_equal(nrow(result), nrow(points_sf)) 31 | expect_equal(sf::st_crs(result), sf::st_crs(points_sf)) 32 | }) 33 | 34 | test_that("ddbs_read_vector reads a standard SQL view into an sf object", { 35 | # Create a standard SQL view from an existing table 36 | # First ensure the base table exists 37 | ddbs_write_vector(conn_test, points_sf, "base_table_for_view", overwrite = TRUE) 38 | 39 | # Create SQL view 40 | DBI::dbExecute(conn_test, "CREATE OR REPLACE VIEW test_sql_view AS SELECT * FROM base_table_for_view") 41 | 42 | # Read from the SQL view 43 | result <- ddbs_read_vector(conn_test, "test_sql_view", crs = 4326) 44 | 45 | expect_s3_class(result, "sf") 46 | expect_equal(nrow(result), nrow(points_sf)) 47 | expect_equal(sf::st_crs(result), sf::st_crs(points_sf)) 48 | 49 | # Cleanup 50 | DBI::dbExecute(conn_test, "DROP VIEW IF EXISTS test_sql_view") 51 | }) 52 | 53 | # 2. Parameters and clauses ---- 54 | test_that("ddbs_read_vector's 'clauses' argument works", { 55 | # Use a WHERE clause to filter the data 56 | result <- ddbs_read_vector(conn_test, "test_points_read", crs = 4326, clauses = "WHERE id <= 3") 57 | 58 | expect_equal(nrow(result), 3) 59 | expect_true(all(result$id <= 3)) 60 | }) 61 | 62 | test_that("ddbs_read_vector works with different geometry types", { 63 | # Test with polygons 64 | result <- ddbs_read_vector(conn_test, "test_countries_read", crs = 4326) 65 | expect_s3_class(result, "sf") 66 | expect_true(any(grepl("POLYGON", sf::st_geometry_type(result)))) 67 | }) 68 | 69 | # 3. CRS handling ---- 70 | test_that("ddbs_read_vector infers CRS from crs_duckspatial column", { 71 | # The 'test_points_read' table has crs_duckspatial = '4326' 72 | result <- ddbs_read_vector(conn_test, "test_points_read") 73 | expect_equal(sf::st_crs(result), sf::st_crs(4326)) 74 | }) 75 | 76 | test_that("ddbs_read_vector 'crs' parameter overrides stored CRS", { 77 | # Store with 4326, read with a different one (e.g., 3857) 78 | result <- ddbs_read_vector(conn_test, "test_points_read", crs = 3857) 79 | expect_equal(sf::st_crs(result), sf::st_crs(3857)) 80 | }) 81 | 82 | test_that("ddbs_read_vector handles tables with no CRS info", { 83 | # Create a table with no CRS 84 | points_no_crs <- points_sf 85 | sf::st_crs(points_no_crs) <- NA 86 | ddbs_write_vector(conn = conn_test, data = points_no_crs, name = "test_no_crs_read", overwrite = TRUE) 87 | 88 | # Read without specifying CRS (should result in NA CRS) 89 | expect_message( 90 | result <- ddbs_read_vector(conn_test, "test_no_crs_read"), 91 | "No CRS found" 92 | ) 93 | expect_true(is.na(sf::st_crs(result))) 94 | 95 | # Read while specifying CRS 96 | result_with_crs <- ddbs_read_vector(conn_test, "test_no_crs_read", crs = 4326) 97 | expect_equal(sf::st_crs(result_with_crs), sf::st_crs(4326)) 98 | }) 99 | 100 | # 4. Errors ---- 101 | test_that("ddbs_read_vector throws an error for non-existent tables/views", { 102 | expect_error( 103 | ddbs_read_vector(conn_test, "this_table_does_not_exist"), 104 | "not present in the database" 105 | ) 106 | }) 107 | 108 | # Disconnect 109 | duckdb::dbDisconnect(conn_test, shutdown = TRUE) 110 | -------------------------------------------------------------------------------- /R/ddbs_convex_hull.R: -------------------------------------------------------------------------------- 1 | #' Returns the convex hull enclosing the geometry 2 | #' 3 | #' Returns the convex hull enclosing the geometry from an \code{sf} object or 4 | #' from a DuckDB table using the spatial extension. Returns the result as an 5 | #' \code{sf} object or creates a new table in the database. 6 | #' 7 | #' @template x 8 | #' @template conn_null 9 | #' @template name 10 | #' @template crs 11 | #' @template overwrite 12 | #' @template quiet 13 | #' 14 | #' @returns an \code{sf} object or \code{TRUE} (invisibly) for table creation 15 | #' @export 16 | #' 17 | #' @examples 18 | #' \dontrun{ 19 | #' ## load packages 20 | #' library(duckdb) 21 | #' library(duckspatial) 22 | #' library(sf) 23 | #' 24 | #' # create a duckdb database in memory (with spatial extension) 25 | #' conn <- ddbs_create_conn(dbdir = "memory") 26 | #' 27 | #' # read data 28 | #' argentina_sf <- st_read(system.file("spatial/argentina.geojson", package = "duckspatial")) 29 | #' 30 | #' # option 1: passing sf objects 31 | #' output1 <- duckspatial::ddbs_convex_hull(x = argentina_sf) 32 | #' 33 | #' plot(output1["CNTR_NAME"])#' # store in duckdb 34 | #' 35 | #' # option 2: passing the name of a table in a duckdb db 36 | #' 37 | #' # creates a duckdb 38 | #' conn <- duckspatial::ddbs_create_conn() 39 | #' 40 | #' # write sf to duckdb 41 | #' ddbs_write_vector(conn, argentina_sf, "argentina_tbl") 42 | #' 43 | #' # spatial join 44 | #' output2 <- duckspatial::ddbs_convex_hull( 45 | #' conn = conn, 46 | #' x = "argentina_tbl" 47 | #' ) 48 | #' 49 | #' plot(output2["CNTR_NAME"]) 50 | #' } 51 | ddbs_convex_hull <- function( 52 | x, 53 | conn = NULL, 54 | name = NULL, 55 | crs = NULL, 56 | crs_column = "crs_duckspatial", 57 | overwrite = FALSE, 58 | quiet = FALSE) { 59 | 60 | ## 0. Handle errors 61 | assert_xy(x, "x") 62 | assert_name(name) 63 | assert_logic(overwrite, "overwrite") 64 | assert_logic(quiet, "quiet") 65 | assert_conn_character(conn, x) 66 | 67 | # 1. Manage connection to DB 68 | ## 1.1. check if connection is provided, otherwise create a temporary connection 69 | is_duckdb_conn <- dbConnCheck(conn) 70 | if (isFALSE(is_duckdb_conn)) { 71 | conn <- duckspatial::ddbs_create_conn() 72 | on.exit(duckdb::dbDisconnect(conn), add = TRUE) 73 | } 74 | ## 1.2. get query list of table names 75 | x_list <- get_query_list(x, conn) 76 | 77 | 78 | ## 2. get name of geometry column 79 | x_geom <- get_geom_name(conn, x_list$query_name) 80 | x_rest <- get_geom_name(conn, x_list$query_name, rest = TRUE) 81 | assert_geometry_column(x_geom, x_list) 82 | 83 | ## 3. if name is not NULL (i.e. no SF returned) 84 | if (!is.null(name)) { 85 | 86 | ## convenient names of table and/or schema.table 87 | name_list <- get_query_name(name) 88 | 89 | ## handle overwrite 90 | overwrite_table(name_list$query_name, conn, quiet, overwrite) 91 | 92 | ## create query (no st_as_text) 93 | if (length(x_rest) == 0) { 94 | tmp.query <- glue::glue(" 95 | SELECT ST_ConvexHull({x_geom}}) as {x_geom} FROM {x_list$query_name}; 96 | ") 97 | } else { 98 | tmp.query <- glue::glue(" 99 | SELECT {paste0(x_rest, collapse = ', ')}, ST_ConvexHull({x_geom}) as {x_geom} FROM {x_list$query_name}; 100 | ") 101 | } 102 | ## execute intersection query 103 | DBI::dbExecute(conn, glue::glue("CREATE TABLE {name_list$query_name} AS {tmp.query}")) 104 | feedback_query(quiet) 105 | return(invisible(TRUE)) 106 | } 107 | 108 | ## 4. create the base query 109 | if (length(x_rest) == 0) { 110 | tmp.query <- glue::glue(" 111 | SELECT ST_AsText(ST_ConvexHull({x_geom})) as {x_geom} FROM {x_list$query_name}; 112 | ") 113 | } else { 114 | tmp.query <- glue::glue(" 115 | SELECT {paste0(x_rest, collapse = ', ')}, ST_AsText(ST_ConvexHull({x_geom})) as {x_geom} FROM {x_list$query_name}; 116 | ") 117 | } 118 | ## send the query 119 | data_tbl <- DBI::dbGetQuery(conn, tmp.query) 120 | 121 | ## 5. convert to SF and return result 122 | data_sf <- convert_to_sf( 123 | data = data_tbl, 124 | crs = crs, 125 | crs_column = crs_column, 126 | x_geom = x_geom 127 | ) 128 | 129 | feedback_query(quiet) 130 | return(data_sf) 131 | } 132 | -------------------------------------------------------------------------------- /man/ddbs_join.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/ddbs_join.R 3 | \name{ddbs_join} 4 | \alias{ddbs_join} 5 | \title{Performs spatial joins of two geometries} 6 | \usage{ 7 | ddbs_join( 8 | x, 9 | y, 10 | join = "intersects", 11 | conn = NULL, 12 | name = NULL, 13 | crs = NULL, 14 | crs_column = "crs_duckspatial", 15 | overwrite = FALSE, 16 | quiet = FALSE 17 | ) 18 | } 19 | \arguments{ 20 | \item{x}{An \code{sf} spatial object. Alternatively, it can be a string with the 21 | name of a table with geometry column within the DuckDB database \code{conn}. 22 | Data is returned from this object.} 23 | 24 | \item{y}{An \code{sf} spatial object. Alternatively, it can be a string with the 25 | name of a table with geometry column within the DuckDB database \code{conn}.} 26 | 27 | \item{join}{A geometry predicate function. Defaults to \code{"intersects"}. See 28 | the details for other options.} 29 | 30 | \item{conn}{A connection object to a DuckDB database. If \code{NULL}, the function 31 | runs on a temporary DuckDB database.} 32 | 33 | \item{name}{A character string of length one specifying the name of the table, 34 | or a character string of length two specifying the schema and table 35 | names. If it's \code{NULL} (the default), it will return the result as an 36 | \code{sf} object.} 37 | 38 | \item{crs}{The coordinates reference system of the data. Specify if the data 39 | doesn't have a \code{crs_column}, and you know the CRS.} 40 | 41 | \item{crs_column}{a character string of length one specifying the column 42 | storing the CRS (created automatically by \code{\link{ddbs_write_vector}}). 43 | Set to \code{NULL} if absent.} 44 | 45 | \item{overwrite}{Boolean. whether to overwrite the existing table if it exists. Defaults 46 | to \code{FALSE}. This argument is ignored when \code{name} is \code{NULL}.} 47 | 48 | \item{quiet}{A logical value. If \code{TRUE}, suppresses any informational messages. 49 | Defaults to \code{FALSE}.} 50 | } 51 | \value{ 52 | an sf object or TRUE (invisibly) for table creation 53 | } 54 | \description{ 55 | Performs spatial joins of two geometries, and returns a \code{sf} object 56 | or creates a new table in a DuckDB database. 57 | } 58 | \details{ 59 | Spatial Join Predicates: 60 | 61 | A spatial predicate is really just a function that evaluates some spatial 62 | relation between two geometries and returns true or false, e.g., “does a 63 | contain b” or “is a within distance x of b”. Here is a quick overview of the 64 | most commonly used ones, taking two geometries a and b: 65 | \itemize{ 66 | \item \code{"ST_Intersects"}: Whether a intersects b 67 | \item \code{"ST_Contains"}: Whether a contains b 68 | \item \code{"ST_ContainsProperly"}: Whether a contains b without b touching a's boundary 69 | \item \code{"ST_Within"}: Whether a is within b 70 | \item \code{"ST_Overlaps"}: Whether a overlaps b 71 | \item \code{"ST_Touches"}: Whether a touches b 72 | \item \code{"ST_Equals"}: Whether a is equal to b 73 | \item \code{"ST_Crosses"}: Whether a crosses b 74 | \item \code{"ST_Covers"}: Whether a covers b 75 | \item \code{"ST_CoveredBy"}: Whether a is covered by b 76 | \item \code{"ST_DWithin"}: x) Whether a is within distance x of b 77 | } 78 | } 79 | \examples{ 80 | \dontrun{ 81 | # load packages 82 | library(duckdb) 83 | library(duckspatial) 84 | library(sf) 85 | 86 | # read polygons data 87 | countries_sf <- sf::st_read(system.file("spatial/countries.geojson", package = "duckspatial")) 88 | 89 | # create points data 90 | n <- 100 91 | points_sf <- data.frame( 92 | id = 1:n, 93 | x = runif(n, min = -180, max = 180), 94 | y = runif(n, min = -90, max = 90) 95 | ) |> 96 | sf::st_as_sf(coords = c("x", "y"), crs = 4326) 97 | 98 | 99 | 100 | # option 1: passing sf objects 101 | output1 <- duckspatial::ddbs_join( 102 | x = points_sf, 103 | y = countries_sf, 104 | join = "within" 105 | ) 106 | 107 | plot(output1["CNTR_NAME"]) 108 | 109 | 110 | ## option 2: passing the names of tables in a duckdb db 111 | 112 | # creates a duckdb 113 | conn <- duckspatial::ddbs_create_conn() 114 | 115 | # write sf to duckdb 116 | ddbs_write_vector(conn, points_sf, "points", overwrite = TRUE) 117 | ddbs_write_vector(conn, countries_sf, "countries", overwrite = TRUE) 118 | 119 | # spatial join 120 | output2 <- ddbs_join( 121 | conn = conn, 122 | x = "points", 123 | y = "countries", 124 | join = "within" 125 | ) 126 | 127 | plot(output2["CNTR_NAME"]) 128 | 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /R/ddbs_filter.R: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | #' Performs spatial filter of two geometries 5 | #' 6 | #' Filters data spatially based on a spatial predicate 7 | #' 8 | #' @template x 9 | #' @param y Y table with geometry column within the DuckDB database 10 | #' @template predicate 11 | #' @template conn_null 12 | #' @template name 13 | #' @template crs 14 | #' @template overwrite 15 | #' @template quiet 16 | #' 17 | #' @returns An sf object or TRUE (invisibly) for table creation 18 | #' 19 | #' @template spatial_join_predicates 20 | #' 21 | #' @export 22 | #' 23 | #' @examples 24 | #' \dontrun{ 25 | #' ## load packages 26 | #' library(duckdb) 27 | #' library(duckspatial) 28 | #' library(sf) 29 | #' 30 | #' # create a duckdb database in memory (with spatial extension) 31 | #' conn <- ddbs_create_conn(dbdir = "memory") 32 | #' 33 | #' ## read data 34 | #' countries_sf <- st_read(system.file("spatial/countries.geojson", package = "duckspatial")) 35 | #' argentina_sf <- st_read(system.file("spatial/argentina.geojson", package = "duckspatial")) 36 | #' 37 | #' ## store in duckdb 38 | #' ddbs_write_vector(conn, countries_sf, "countries") 39 | #' ddbs_write_vector(conn, argentina_sf, "argentina") 40 | #' 41 | #' ## filter countries touching argentina 42 | #' ddbs_filter(conn = conn, "countries", "argentina", predicate = "touches") 43 | #' 44 | #' ## filter without using a connection 45 | #' ddbs_filter(countries_sf, argentina_sf, predicate = "touches") 46 | #' } 47 | ddbs_filter <- function( 48 | x, 49 | y, 50 | predicate = "intersects", 51 | conn = NULL, 52 | name = NULL, 53 | crs = NULL, 54 | crs_column = "crs_duckspatial", 55 | overwrite = FALSE, 56 | quiet = FALSE) { 57 | 58 | # 0. Handle errors 59 | assert_xy(x, "x") 60 | assert_xy(y, "y") 61 | assert_name(name) 62 | assert_logic(overwrite, "overwrite") 63 | assert_logic(quiet, "quiet") 64 | assert_conn_character(conn, x, y) 65 | 66 | # 1. Manage connection to DB 67 | ## 1.1. check if connection is provided, otherwise create a temporary connection 68 | is_duckdb_conn <- dbConnCheck(conn) 69 | if (isFALSE(is_duckdb_conn)) { 70 | conn <- duckspatial::ddbs_create_conn() 71 | on.exit(duckdb::dbDisconnect(conn), add = TRUE) 72 | } 73 | ## 1.2. get query list of table names 74 | x_list <- get_query_list(x, conn) 75 | y_list <- get_query_list(y, conn) 76 | assert_crs(conn, x_list$query_name, y_list$query_name) 77 | 78 | # 2. Prepare params for query 79 | ## 2.1. select predicate 80 | sel_pred <- get_st_predicate(predicate) 81 | ## 2.2. get name of geometry column 82 | x_geom <- get_geom_name(conn, x_list$query_name) 83 | x_rest <- get_geom_name(conn, x_list$query_name, rest = TRUE) 84 | y_geom <- get_geom_name(conn, y_list$query_name) 85 | assert_geometry_column(x_geom, x_list) 86 | assert_geometry_column(y_geom, y_list) 87 | ## error if crs_column not found 88 | assert_crs_column(crs_column, x_rest) 89 | 90 | ## 3. if name is not NULL (i.e. no SF returned) 91 | if (!is.null(name)) { 92 | 93 | ## convenient names of table and/or schema.table 94 | name_list <- get_query_name(name) 95 | 96 | ## handle overwrite 97 | overwrite_table(name_list$query_name, conn, quiet, overwrite) 98 | 99 | tmp.query <- glue::glue(" 100 | CREATE TABLE {name_list$query_name} AS 101 | SELECT {paste0('v1.', x_rest, collapse = ', ')}, v1.{x_geom} AS {x_geom} 102 | FROM {x_list$query_name} v1, {y_list$query_name} v2 103 | WHERE {sel_pred}(v2.{y_geom}, v1.{x_geom}) 104 | ") 105 | ## execute filter query 106 | DBI::dbExecute(conn, tmp.query) 107 | feedback_query(quiet) 108 | return(invisible(TRUE)) 109 | } 110 | 111 | ## 4. Get data frame 112 | data_tbl <- DBI::dbGetQuery( 113 | conn, glue::glue(" 114 | SELECT {paste0('v1.', x_rest, collapse = ', ')}, ST_AsText(v1.{x_geom}) AS {x_geom} 115 | FROM {x_list$query_name} v1, {y_list$query_name} v2 116 | WHERE {sel_pred}(v2.{y_geom}, v1.{x_geom}) 117 | ") 118 | ) 119 | 120 | ## 5. convert to SF and return result 121 | data_sf <- convert_to_sf( 122 | data = data_tbl, 123 | crs = crs, 124 | crs_column = crs_column, 125 | x_geom = x_geom 126 | ) 127 | 128 | feedback_query(quiet) 129 | return(data_sf) 130 | 131 | } 132 | 133 | 134 | 135 | 136 | -------------------------------------------------------------------------------- /R/db_register.R: -------------------------------------------------------------------------------- 1 | #' Register an SF Object as an Arrow Table in DuckDB 2 | #' 3 | #' This function registers a Simple Features (SF) object as a temporary Arrow-backed 4 | #' view in a DuckDB database. This is a zero-copy operation and is significantly 5 | #' faster than `ddbs_write_vector` for workflows that do not require data to be 6 | #' permanently materialized in the database. 7 | #' 8 | #' @inheritParams ddbs_write_vector 9 | #' @returns TRUE (invisibly) on successful registration. 10 | #' @export 11 | #' @examples 12 | #' \dontrun{ 13 | #' library(duckdb) 14 | #' library(duckspatial) 15 | #' library(sf) 16 | #' 17 | #' conn <- ddbs_create_conn("memory") 18 | #' 19 | #' nc <- st_read(system.file("shape/nc.shp", package="sf"), quiet = TRUE) 20 | #' 21 | #' ddbs_register_vector(conn, nc, "nc_arrow_view") 22 | #' 23 | #' dbGetQuery(conn, "SELECT COUNT(*) FROM nc_arrow_view;") 24 | #' 25 | #' ddbs_stop_conn(conn, shutdown = TRUE) 26 | #'} 27 | ddbs_register_vector <- function( 28 | conn, 29 | data, 30 | name, 31 | overwrite = FALSE, 32 | quiet = FALSE 33 | ) { 34 | # 1. Checks 35 | dbConnCheck(conn) 36 | name_list <- get_query_name(name) 37 | view_name <- name_list$query_name 38 | 39 | data_sf <- if (inherits(data, "sf")) { 40 | data 41 | } else if (is.character(data) && length(data) == 1) { 42 | sf::st_read(data, quiet = TRUE) 43 | } else { 44 | cli::cli_abort( 45 | "{.arg data} must be an {.cls sf} object or a readable file path." 46 | ) 47 | } 48 | 49 | tables_df <- ddbs_list_tables(conn) 50 | db_tables <- paste0(tables_df$table_schema, ".", tables_df$table_name) |> 51 | sub(pattern = "^main\\.", replacement = "") 52 | name_exists <- view_name %in% db_tables 53 | arrow_views <- try( 54 | duckdb::duckdb_list_arrow(conn), 55 | silent = TRUE 56 | ) 57 | arrow_exists <- if (inherits(arrow_views, "try-error")) { 58 | FALSE 59 | } else { 60 | view_name %in% arrow_views 61 | } 62 | 63 | if ((name_exists || arrow_exists) && !overwrite) { 64 | cli::cli_abort( 65 | "The provided view (or table) name is already present in the database. Please, use `overwrite = TRUE` or choose a different name." 66 | ) 67 | } 68 | 69 | if (overwrite && (name_exists || arrow_exists)) { 70 | if (name_exists) { 71 | match_idx <- which(db_tables == view_name)[1] 72 | table_type <- tables_df$table_type[match_idx] 73 | drop_stmt <- if ( 74 | !is.na(table_type) && identical(table_type, "VIEW") 75 | ) { 76 | glue::glue("DROP VIEW IF EXISTS {view_name};") 77 | } else { 78 | glue::glue("DROP TABLE IF EXISTS {view_name};") 79 | } 80 | DBI::dbExecute(conn, drop_stmt) 81 | if (isFALSE(quiet)) { 82 | cli::cli_alert_info("Existing object {view_name} dropped") 83 | } 84 | } 85 | if (arrow_exists) { 86 | try( 87 | duckdb::duckdb_unregister_arrow(conn, view_name), 88 | silent = TRUE 89 | ) 90 | } 91 | } 92 | 93 | # Try to register geoarrow extensions when available 94 | try( 95 | DBI::dbExecute(conn, "CALL register_geoarrow_extensions();"), 96 | silent = TRUE 97 | ) 98 | 99 | # 2. Register table 100 | df <- sf::st_drop_geometry(data_sf) 101 | wkb <- wk::as_wkb(sf::st_geometry(data_sf)) 102 | 103 | # Get original geometry column name 104 | geom_col_name <- attr(data_sf, "sf_column") 105 | 106 | # Use geoarrow to create a geoarrow vector from WKB 107 | # Assign to original geometry column name instead of hardcoded "geometry" 108 | df[[geom_col_name]] <- geoarrow::as_geoarrow_vctr( 109 | wkb, 110 | schema = geoarrow::geoarrow_wkb() 111 | ) 112 | 113 | # Add CRS column 114 | data_crs <- sf::st_crs(data_sf, parameters = TRUE) 115 | crs_value <- if (!is.null(data_crs$srid) && nchar(data_crs$srid) > 0) { 116 | data_crs$srid 117 | } else { 118 | data_crs$Wkt 119 | } 120 | df$crs_duckspatial <- crs_value 121 | 122 | arrow_table <- arrow::Table$create(df) 123 | 124 | duckdb::duckdb_register_arrow(conn, view_name, arrow_table) 125 | 126 | if (isFALSE(quiet)) { 127 | cli::cli_alert_success("Temporary view {view_name} registered") 128 | } 129 | 130 | invisible(TRUE) 131 | } 132 | -------------------------------------------------------------------------------- /tests/testthat/test-ddbs_join.R: -------------------------------------------------------------------------------- 1 | # skip tests on CRAN because they take too much time 2 | skip_if(Sys.getenv("TEST_ONE") != "") 3 | testthat::skip_on_cran() 4 | testthat::skip_if_not_installed("duckdb") 5 | 6 | 7 | # helpers -------------------------------------------------------------- 8 | 9 | # create duckdb connection 10 | conn_test <- duckspatial::ddbs_create_conn() 11 | 12 | # helper function 13 | tester <- function(x = points_sf, 14 | y = countries_sf, 15 | join = "intersects", 16 | conn = NULL, 17 | name = NULL, 18 | crs = NULL, 19 | crs_column = "crs_duckspatial", 20 | overwrite = FALSE, 21 | quiet = FALSE) { 22 | ddbs_join( 23 | x, 24 | y, 25 | join, 26 | conn, 27 | name, 28 | crs, 29 | crs_column, 30 | overwrite, 31 | quiet 32 | ) 33 | } 34 | 35 | 36 | # expected behavior -------------------------------------------------------------- 37 | 38 | 39 | testthat::test_that("expected behavior", { 40 | 41 | # option 1: passing sf objects 42 | output1 <- tester( 43 | x = points_sf, 44 | y = countries_sf, 45 | join = "within" 46 | ) 47 | 48 | testthat::expect_true(is(output1 , 'sf')) 49 | 50 | # option 2: passing the names of tables in a duckdb db, returing sf 51 | # write sf to duckdb 52 | ddbs_write_vector(conn_test, points_sf, "points", overwrite = TRUE) 53 | ddbs_write_vector(conn_test, countries_sf, "countries", overwrite = TRUE) 54 | 55 | # spatial join 56 | output2 <- tester( 57 | conn_test, 58 | x = "points", 59 | y = "countries", 60 | join = "within" 61 | ) 62 | 63 | testthat::expect_true(is(output2 , 'sf')) 64 | 65 | # option 3: passing the names of tables in a duckdb db, creating new table in db 66 | output3 <- tester( 67 | conn_test, 68 | x = "points", 69 | y = "countries", 70 | join = "within", 71 | name = "test_result", 72 | overwrite = TRUE 73 | ) 74 | 75 | testthat::expect_true(output3) 76 | 77 | # TODO - Review this because it fails 78 | # output3 <- DBI::dbReadTable(conn_test, "test_result") |> 79 | # sf::st_as_sf(wkt = 'geometry') 80 | 81 | # testthat::expect_true(is(output3 , 'sf')) 82 | 83 | ddbs_read_vector(conn_test, name = "test_result", crs = 4326) 84 | 85 | 86 | # show and suppress messages 87 | testthat::expect_message( tester() ) 88 | testthat::expect_no_message( tester(quiet = TRUE)) 89 | 90 | 91 | }) 92 | 93 | 94 | testthat::test_that("error if table already exists", { 95 | 96 | # write table for the 1st time 97 | testthat::expect_true(tester(x = "points", 98 | y = "countries", 99 | conn = conn_test, 100 | name = 'banana', 101 | overwrite = FALSE) 102 | ) 103 | 104 | # expected error if overwrite = FALSE 105 | testthat::expect_error(tester(x = "points", 106 | y = "countries", 107 | conn = conn_test, 108 | name = 'banana', 109 | overwrite = FALSE)) 110 | 111 | # overwrite table 112 | testthat::expect_true(tester(x = "points", 113 | y = "countries", 114 | conn = conn_test, 115 | name = 'banana', 116 | overwrite = TRUE)) 117 | 118 | 119 | }) 120 | 121 | # expected errors -------------------------------------------------------------- 122 | 123 | testthat::test_that("errors with incorrect input", { 124 | 125 | testthat::expect_error(tester(x = 999)) 126 | testthat::expect_error(tester(y = 999)) 127 | testthat::expect_error(tester(join = 999)) 128 | testthat::expect_error(tester(conn = 999)) 129 | testthat::expect_error(tester(overwrite = 999)) 130 | testthat::expect_error(tester(quiet = 999)) 131 | 132 | testthat::expect_error(tester(x = "999", conn = conn_test)) 133 | testthat::expect_error(tester(y = "999", conn = conn_test)) 134 | 135 | testthat::expect_error(tester(conn = conn_test, name = c('banana', 'banana'))) 136 | 137 | 138 | }) 139 | -------------------------------------------------------------------------------- /R/utils_assert_fun.R: -------------------------------------------------------------------------------- 1 | 2 | assert_logic <- function(arg, ref = "quiet") { 3 | 4 | if (!is.logical(arg)) { 5 | cli::cli_abort( 6 | "{.arg {ref}} must be either TRUE or FALSE.", 7 | .frame = parent.frame() 8 | ) 9 | } 10 | } 11 | 12 | 13 | assert_xy <- function(xy, ref = "x") { 14 | 15 | if (!(inherits(xy, "sf") || is.character(xy))) { 16 | cli::cli_abort( 17 | "{.arg {ref}} must be either an sf object or a string.", 18 | .frame = parent.frame() 19 | ) 20 | } 21 | } 22 | 23 | assert_name <- function(name = parent.frame()$name) { 24 | 25 | if (!any(is.character(name) | is.null(name))) { 26 | cli::cli_abort("'name' must be a string character.", 27 | .frame = parent.frame() 28 | ) 29 | } 30 | 31 | if (length(name) > 1) { 32 | cli::cli_abort("'name' must be a string character of length one", 33 | .frame = parent.frame() 34 | ) 35 | } 36 | 37 | } 38 | 39 | assert_numeric <- function(arg, ref) { 40 | 41 | if (!is.numeric(arg) || length(arg) != 1) { 42 | cli::cli_abort( 43 | "{.arg {ref}} must be a single numeric value.", 44 | .frame = parent.frame() 45 | ) 46 | } 47 | } 48 | 49 | assert_numeric_interval <- function(arg, minn, maxx, ref) { 50 | 51 | if (!is.numeric(arg) || min(arg) < minn || max(arg) > maxx) { 52 | cli::cli_abort( 53 | "{.arg {ref}} must be a single numeric value between {minn} and {maxx}.", 54 | .frame = parent.frame() 55 | ) 56 | } 57 | } 58 | 59 | 60 | # whether the function takes sf of string as xy input 61 | assert_connflict <- function(conn, xy, ref = "x") { 62 | 63 | is_duckdn_conn <- dbConnCheck(conn) 64 | 65 | 66 | if (inherits(xy, "sf") & is_duckdn_conn) { 67 | cli::cli_abort( 68 | "If you pass a {.arg {ref}}, it must be a string when {.arg conn} is provided.", 69 | .frame = parent.frame() 70 | ) 71 | } 72 | } 73 | 74 | 75 | assert_geometry_column <- function(geom, name_list) { 76 | if (length(geom) == 0) cli::cli_abort("Geometry column wasn't found in table <{name_list$query_name}>.") 77 | } 78 | 79 | 80 | 81 | ## assert crs_column (needed for ddbs_filter) 82 | assert_crs_column <- function(crs_column, cols) { 83 | if (!is.null(crs_column)) 84 | if (!crs_column %in% cols) 85 | cli::cli_abort("CRS column <{crs_column}> do not found in the table. If the data do not have CRS column, set the argument `crs_column = NULL`") 86 | 87 | } 88 | 89 | 90 | ## assert id argument in predicate functions 91 | assert_predicate_id <- function(id, conn, lst) { 92 | if (!is.null(id)) { 93 | x_rest <- get_geom_name(conn, lst, rest = TRUE) 94 | if (!id %in% x_rest) cli::cli_abort(" must be NULL or a column name of ") 95 | } 96 | } 97 | 98 | 99 | ## assert if the CRS of `x` and `y` is the same 100 | assert_crs <- function(conn, x, y) { 101 | 102 | ## get CRS 103 | crs_x <- duckspatial::ddbs_crs(conn, x) 104 | crs_y <- duckspatial::ddbs_crs(conn, y) 105 | 106 | ## abort if CRS is different 107 | if (crs_x != crs_y) cli::cli_abort("The Coordinates Reference System of `x` and `y` is different.") 108 | 109 | } 110 | 111 | 112 | 113 | 114 | ## assert that if `x` or `y` are character, connection cannot be NULL 115 | assert_conn_character <- function(conn, ...) { 116 | 117 | ## get inputs into a list 118 | inputs <- list(...) 119 | 120 | ## check if they are character 121 | inputs_check <- lapply(inputs, is.character) |> as.logical() 122 | 123 | if (any(inputs_check) & is.null(conn)) { 124 | cli::cli_abort("If a table name is provided in `x` or `y`, the connection cannot be NULL.") 125 | } 126 | 127 | } 128 | 129 | #' Assert that columns exist in a table 130 | #' 131 | #' @param conn DuckDB connection 132 | #' @param table Table name 133 | #' @param cols Vector of column names to check 134 | #' @param ref Reference name for error message 135 | #' @noRd 136 | #' @returns invisible(TRUE) 137 | assert_col_exists <- function(conn, table, cols, ref) { 138 | avail <- DBI::dbListFields(conn, table) 139 | missing <- setdiff(cols, avail) 140 | if (length(missing) > 0) { 141 | # Rephrased to put the vector first, helping cli resolve pluralization quantity 142 | cli::cli_abort( 143 | "{.val {missing}} column{?s} not found in {.arg {ref}} table." 144 | ) 145 | } 146 | invisible(TRUE) 147 | } 148 | -------------------------------------------------------------------------------- /tests/testthat/test-ddbs_concave_hull.R: -------------------------------------------------------------------------------- 1 | # skip tests on CRAN because they take too much time 2 | skip_if(Sys.getenv("TEST_ONE") != "") 3 | testthat::skip_on_cran() 4 | testthat::skip_if_not_installed("duckdb") 5 | 6 | 7 | # create points data 8 | n <- 5 9 | points_sf <- data.frame( 10 | id = 1, 11 | x = runif(n, min = -180, max = 180), 12 | y = runif(n, min = -90, max = 90) 13 | ) |> 14 | sf::st_as_sf(coords = c("x", "y"), crs = 4326) |> 15 | sf::st_geometry() |> 16 | sf::st_combine() |> 17 | sf::st_cast("MULTIPOINT") |> 18 | sf::st_as_sf() 19 | 20 | # helpers -------------------------------------------------------------- 21 | 22 | # create duckdb connection 23 | conn_test <- duckspatial::ddbs_create_conn() 24 | 25 | # helper function 26 | tester <- function(x = points_sf, 27 | ratio = 0.5, 28 | allow_holes = TRUE, 29 | conn = NULL, 30 | name = NULL, 31 | crs = NULL, 32 | crs_column = "crs_duckspatial", 33 | overwrite = FALSE, 34 | quiet = FALSE) { 35 | ddbs_concave_hull( 36 | x, 37 | ratio = ratio, 38 | allow_holes = allow_holes, 39 | conn, 40 | name, 41 | crs, 42 | crs_column, 43 | overwrite, 44 | quiet 45 | ) 46 | } 47 | 48 | 49 | # expected behavior -------------------------------------------------------------- 50 | 51 | 52 | testthat::test_that("expected behavior", { 53 | 54 | # option 1: passing sf objects 55 | output1 <- tester( 56 | x = points_sf 57 | ) 58 | 59 | testthat::expect_true(is(output1 , 'sf')) 60 | 61 | # option 2: passing the names of tables in a duckdb db, returing sf 62 | # write sf to duckdb 63 | ddbs_write_vector(conn_test, points_sf, "points_tbl", overwrite = TRUE) 64 | 65 | # spatial join 66 | output2 <- tester( 67 | conn = conn_test, 68 | x = "points_tbl" 69 | ) 70 | 71 | testthat::expect_true(is(output2 , 'sf')) 72 | 73 | # option 3: passing the names of tables in a duckdb db, creating new table in db 74 | output3 <- tester( 75 | x = "points_tbl", 76 | conn = conn_test, 77 | name = "test_result", 78 | overwrite = TRUE 79 | ) 80 | 81 | testthat::expect_true(output3) 82 | 83 | # TODO - Review this because it fails 84 | # output3 <- DBI::dbReadTable(conn_test, "test_result") |> 85 | # sf::st_as_sf(wkt = 'geometry') 86 | 87 | # testthat::expect_true(is(output3 , 'sf')) 88 | 89 | testthat::expect_true( 90 | is(ddbs_read_vector(conn_test, name = "test_result", crs = 4326) , 91 | 'sf' 92 | ) 93 | ) 94 | 95 | 96 | 97 | # show and suppress messages 98 | testthat::expect_message( tester() ) 99 | testthat::expect_no_message( tester(quiet = TRUE)) 100 | 101 | 102 | }) 103 | 104 | 105 | testthat::test_that("error if table already exists", { 106 | 107 | # write table for the 1st time 108 | testthat::expect_true(tester(x = "points_tbl", 109 | conn = conn_test, 110 | name = 'banana', 111 | overwrite = FALSE) 112 | ) 113 | 114 | # expected error if overwrite = FALSE 115 | testthat::expect_error(tester(x = "points_tbl", 116 | conn = conn_test, 117 | name = 'banana', 118 | overwrite = FALSE)) 119 | 120 | # overwrite table 121 | testthat::expect_true(tester(x = "points_tbl", 122 | conn = conn_test, 123 | name = 'banana', 124 | overwrite = TRUE)) 125 | 126 | 127 | }) 128 | 129 | # expected errors -------------------------------------------------------------- 130 | 131 | testthat::test_that("errors with incorrect input", { 132 | 133 | testthat::expect_error(tester(x = 999)) 134 | testthat::expect_error(tester(ratio = 999)) 135 | testthat::expect_error(tester(ratio = -1)) 136 | testthat::expect_error(tester(allow_holes = 999)) 137 | testthat::expect_error(tester(conn = 999)) 138 | testthat::expect_error(tester(overwrite = 999)) 139 | testthat::expect_error(tester(quiet = 999)) 140 | 141 | testthat::expect_error(tester(x = "999", conn = conn_test)) 142 | 143 | testthat::expect_error(tester(conn = conn_test, name = c('banana', 'banana'))) 144 | 145 | 146 | }) 147 | 148 | -------------------------------------------------------------------------------- /R/ddbs_bbox.R: -------------------------------------------------------------------------------- 1 | 2 | 3 | #' Returns the minimal bounding box enclosing the input geometry 4 | #' 5 | #' Returns the minimal bounding box enclosing the input geometry from a `sf` object 6 | #' or a DuckDB table. Returns the result as an \code{sf} object or creates a new 7 | #' table in the database. 8 | #' 9 | #' @template x 10 | #' @param by_feature Boolean. The function defaults to `FALSE`, and returns a 11 | #' single bounding box for `x`. If `TRUE`, it return one bounding box for 12 | #' each feature. 13 | #' @template conn_null 14 | #' @template name 15 | #' @template crs 16 | #' @template overwrite 17 | #' @template quiet 18 | #' 19 | #' @returns an \code{sf} object or \code{TRUE} (invisibly) for table creation 20 | #' @export 21 | #' 22 | #' @examples 23 | #' ## load packages 24 | #' library(duckdb) 25 | #' library(duckspatial) 26 | #' library(sf) 27 | #' 28 | #' ## read data 29 | #' argentina_sf <- st_read(system.file("spatial/argentina.geojson", package = "duckspatial")) 30 | #' 31 | #' # option 1: passing sf objects 32 | #' ddbs_bbox(argentina_sf) 33 | #' 34 | #' 35 | #' ## option 2: passing the names of tables in a duckdb db 36 | #' 37 | #' # creates a duckdb write sf to it 38 | #' conn <- duckspatial::ddbs_create_conn() 39 | #' ddbs_write_vector(conn, argentina_sf, "argentina_tbl", overwrite = TRUE) 40 | #' 41 | #' output2 <- ddbs_bbox( 42 | #' conn = conn, 43 | #' x = "argentina_tbl", 44 | #' name = "argentina_bbox" 45 | #' ) 46 | #' 47 | #' DBI::dbReadTable(conn, "argentina_bbox") 48 | #' 49 | ddbs_bbox <- function(x, 50 | by_feature = FALSE, 51 | conn = NULL, 52 | name = NULL, 53 | crs = NULL, 54 | crs_column = "crs_duckspatial", 55 | overwrite = FALSE, 56 | quiet = FALSE) { 57 | 58 | # 0. Handle errors 59 | assert_xy(x, "x") 60 | assert_name(name) 61 | assert_logic(by_feature, "by_feature") 62 | assert_logic(overwrite, "overwrite") 63 | assert_logic(quiet, "quiet") 64 | assert_connflict(conn, xy = x, ref = "x") 65 | 66 | # 1. Manage connection to DB 67 | ## 1.1. check if connection is provided 68 | is_duckdb_conn <- dbConnCheck(conn) 69 | 70 | ## 1.2. prepares info for running the function on a temporary db 71 | if (isFALSE(is_duckdb_conn)) { 72 | 73 | # create conn 74 | conn <- duckspatial::ddbs_create_conn() 75 | 76 | # write tables, and get convenient names for x 77 | duckspatial::ddbs_write_vector(conn, data = x, name = "tbl_x", quiet = TRUE, temp_view = TRUE) 78 | x_list <- get_query_name("tbl_x") 79 | 80 | } else { 81 | x_list <- get_query_name(x) 82 | } 83 | 84 | ## 2. get name of geometry column 85 | x_geom <- get_geom_name(conn, x_list$query_name) 86 | x_rest <- get_geom_name(conn, x_list$query_name, rest = TRUE) 87 | assert_geometry_column(x_geom, x_list) 88 | 89 | 90 | # 3. Build base query 91 | 92 | # set the extent_clause 93 | if (isTRUE(by_feature)) { 94 | st_extent_clause <- glue::glue("ST_Extent({x_geom})") 95 | } else { 96 | st_extent_clause <- glue::glue("ST_Extent(ST_Collect(LIST({x_geom})))") 97 | } 98 | 99 | tmp.query <- glue::glue( 100 | "SELECT 101 | ST_XMin(ext) AS min_x, 102 | ST_YMin(ext) AS min_y, 103 | ST_XMax(ext) AS max_x, 104 | ST_YMax(ext) AS max_y 105 | FROM ( 106 | SELECT {st_extent_clause} AS ext 107 | FROM {x_list$query_name} 108 | );" 109 | ) 110 | 111 | 112 | 113 | ## 3. if name is not NULL (i.e. no data frame returned) 114 | if (!is.null(name)) { 115 | 116 | ## convenient names of table and/or schema.table 117 | name_list <- get_query_name(name) 118 | 119 | ## handle overwrite 120 | if (overwrite) { 121 | DBI::dbExecute(conn, glue::glue("DROP TABLE IF EXISTS {name_list$query_name};")) 122 | 123 | if (isFALSE(quiet)) { 124 | cli::cli_alert_info("Table <{name_list$query_name}> dropped") 125 | } 126 | } 127 | 128 | ## execute area query 129 | DBI::dbExecute(conn, glue::glue("CREATE TABLE {name_list$query_name} AS {tmp.query}")) 130 | 131 | if (isFALSE(quiet)) { 132 | cli::cli_alert_success("Query successful") 133 | } 134 | 135 | return(invisible(TRUE)) 136 | } 137 | 138 | # 4. Get data frame 139 | data_tbl <- DBI::dbGetQuery(conn, tmp.query) 140 | 141 | # class(data_tbl) <- "bbox" 142 | 143 | if (isFALSE(quiet)) cli::cli_alert_success("Query successful") 144 | return(data_tbl) 145 | } 146 | 147 | 148 | 149 | --------------------------------------------------------------------------------