As you can see, this returns a igraph object instead of a sfnetwork object. To preserve the class, you can use the wrap_igraph() function of sfnetworks for each igraph function that accepts a network as first input and returns another network. This function will check if the returned network is still spatial.
The sfnetworks contains the sfnetwork class to represent spatial networks in R. There are several ways in which you can create instances of this class. This vignette describes these ways, and provides more detail on the ins and outs of the data structure.
+
The sfnetworks package contains the sfnetwork class to represent spatial networks in R. There are several ways in which you can create instances of this class. This vignette describes these ways, and provides more detail on the ins and outs of the data structure.
# Create a directed network.dnet=as_sfnetwork(streets)
@@ -294,7 +294,7 @@
# This equals the number of oneway streets ...# ... plus twice the number of twoway streets.n_edges(mnet)
-#> [1] 1455
+#> [1] 1451
Geometries
@@ -978,39 +978,38 @@
# igraph object.inet=igraph::sample_grg(5, 0.5, coords =TRUE)inet
-#> IGRAPH c92c8b1 U--- 5 3 -- Geometric random graph
+#> IGRAPH 037109b U--- 5 2 -- Geometric random graph#> + attr: name (g/c), radius (g/n), torus (g/l), x (v/n), y (v/n)
-#> + edges from c92c8b1:
-#> [1] 2--3 2--4 3--4
The integration with sf and addition of several spatial network specific functions in sfnetworks allow to easily filter information from a network based on spatial relationships, and to join new information into a network based on spatial relationships. This vignette presents several ways to do that.
+
The integration with sf and addition of several spatial network specific functions in sfnetworks allow to easily filter information from a network based on spatial relationships, and to join new information into a network based on spatial relationships. This vignette presents several ways to do that.
Both spatial filters and spatial joins use spatial predicate functions to examine spatial relationships. Spatial predicates are mathematically defined binary spatial relations between two simple feature geometries. Often used examples include the predicate equals (geometry x is equal to geometry y) and the predicate intersects (geometry x has at least one point in common with geometry y). For an overview of all available spatial predicate functions in sf and links to detailed explanations of the underlying algorithms, see here.
As mentioned, {sfnetwork} does not implement the routing algorithms themselves. For that, it relies on other packages, which we call “routing backends” or “routers” for short. The default routing backend is igraph. The st_network_paths() function wraps, depending on argument settings, igraph::shortest_paths(), igraph::all_shortest_paths() and igraph::k_shortest_paths(). The st_network_cost() function wraps igraph::distances(). The benefits of this routing backend are: 1) it can compute all shortest paths, if there exists more than one; 2) it can compute the shortest paths with Yen’s algorithm; 3) no internal conversion between data structures is needed. However, routing is only supported from a single origin. Hence, many-to-many routing is not possible.
+
As mentioned, sfnetworks does not implement the routing algorithms themselves. For that, it relies on other packages, which we call “routing backends” or “routers” for short. The default routing backend is igraph. The st_network_paths() function wraps, depending on argument settings, igraph::shortest_paths(), igraph::all_shortest_paths() and igraph::k_shortest_paths(). The st_network_cost() function wraps igraph::distances(). The benefits of this routing backend are: 1) it can compute all shortest paths, if there exists more than one; 2) it can compute the shortest paths with Yen’s algorithm; 3) no internal conversion between data structures is needed. However, routing is only supported from a single origin. Hence, many-to-many routing is not possible.
The second routing backend that is currently supported is dodgr. This package implements a very fast routing algorithm in C++. This is exposed in sfnetworks by wrapping dodgr::dodgr_paths() in st_network_paths() and dodgr::dodgr_dists() in st_network_cost(). The benefits of this routing backend are: 1) it can route from multiple origins to multiple destinations, i.e. many-to-many routing; 2) it supports dual-weighted routing (see here); 3) it is very fast also on large networks. However, there is currently no support for shortest paths routing, and some internal conversions are needed to bridge between the different data structures.
You can specify which routing backend to use through the router argument. If you want to change the default routing backend, update the global options: options(sfn_default_router = "dodgr").
diff --git a/articles/sfn05_routing_files/figure-html/unnamed-chunk-25-1.png b/articles/sfn05_routing_files/figure-html/unnamed-chunk-25-1.png
index b20ef7b..f7aa5bf 100644
Binary files a/articles/sfn05_routing_files/figure-html/unnamed-chunk-25-1.png and b/articles/sfn05_routing_files/figure-html/unnamed-chunk-25-1.png differ
diff --git a/articles/sfn05_routing_files/figure-html/unnamed-chunk-27-1.png b/articles/sfn05_routing_files/figure-html/unnamed-chunk-27-1.png
index 21649ef..b1919a4 100644
Binary files a/articles/sfn05_routing_files/figure-html/unnamed-chunk-27-1.png and b/articles/sfn05_routing_files/figure-html/unnamed-chunk-27-1.png differ
diff --git a/articles/sfn05_routing_files/figure-html/unnamed-chunk-29-1.png b/articles/sfn05_routing_files/figure-html/unnamed-chunk-29-1.png
index 777b429..34dff45 100644
Binary files a/articles/sfn05_routing_files/figure-html/unnamed-chunk-29-1.png and b/articles/sfn05_routing_files/figure-html/unnamed-chunk-29-1.png differ
diff --git a/articles/sfn05_routing_files/figure-html/unnamed-chunk-31-1.png b/articles/sfn05_routing_files/figure-html/unnamed-chunk-31-1.png
index b317985..474b4f6 100644
Binary files a/articles/sfn05_routing_files/figure-html/unnamed-chunk-31-1.png and b/articles/sfn05_routing_files/figure-html/unnamed-chunk-31-1.png differ
diff --git a/articles/sfn05_routing_files/figure-html/unnamed-chunk-33-1.png b/articles/sfn05_routing_files/figure-html/unnamed-chunk-33-1.png
index 6f65d87..77b1fde 100644
Binary files a/articles/sfn05_routing_files/figure-html/unnamed-chunk-33-1.png and b/articles/sfn05_routing_files/figure-html/unnamed-chunk-33-1.png differ
diff --git a/articles/sfn05_routing_files/figure-html/unnamed-chunk-36-1.png b/articles/sfn05_routing_files/figure-html/unnamed-chunk-36-1.png
index bb90a78..f536ccd 100644
Binary files a/articles/sfn05_routing_files/figure-html/unnamed-chunk-36-1.png and b/articles/sfn05_routing_files/figure-html/unnamed-chunk-36-1.png differ
diff --git a/articles/sfn05_routing_files/figure-html/unnamed-chunk-36-2.png b/articles/sfn05_routing_files/figure-html/unnamed-chunk-36-2.png
index aebc8e4..41a2071 100644
Binary files a/articles/sfn05_routing_files/figure-html/unnamed-chunk-36-2.png and b/articles/sfn05_routing_files/figure-html/unnamed-chunk-36-2.png differ
diff --git a/index.html b/index.html
index 8e0fcc7..dbc465f 100644
--- a/index.html
+++ b/index.html
@@ -79,7 +79,7 @@
Backgroundsf} for spatial data science and {tidygraph} for standard graph analysis. The core of the package is a dedicated data structure for geospatial networks, that can be provided as input to both the graph analytical functions of {tidygraph} as well as the spatial analytical functions of {sf}, without the need for conversion. Additionally, we implemented a set of geospatial network specific functions, such as routines for shortest path calculation, network cleaning and topology modification. {sfnetworks} is designed as a general-purpose package suitable for usage across different application domains, and can be seamlessly integrated in tidyverse workflows.
-
+
Installation
diff --git a/pkgdown.yml b/pkgdown.yml
index ba4cc37..714fda6 100644
--- a/pkgdown.yml
+++ b/pkgdown.yml
@@ -7,7 +7,7 @@ articles:
sfn03_cleaning: sfn03_cleaning.html
sfn04_join_filter: sfn04_join_filter.html
sfn05_routing: sfn05_routing.html
-last_built: 2024-11-17T20:26Z
+last_built: 2024-11-17T20:49Z
urls:
reference: https://luukvdmeer.github.io/sfnetworks/reference
article: https://luukvdmeer.github.io/sfnetworks/articles
diff --git a/search.json b/search.json
index 335af2a..ca6115a 100644
--- a/search.json
+++ b/search.json
@@ -1 +1 @@
-[{"path":[]},{"path":"https://luukvdmeer.github.io/sfnetworks/CODE_OF_CONDUCT.html","id":"our-pledge","dir":"","previous_headings":"","what":"Our Pledge","title":"Contributor Covenant Code of Conduct","text":"members, contributors, leaders pledge make participation community harassment-free experience everyone, regardless age, body size, visible invisible disability, ethnicity, sex characteristics, gender identity expression, level experience, education, socio-economic status, nationality, personal appearance, race, caste, color, religion, sexual identity orientation. pledge act interact ways contribute open, welcoming, diverse, inclusive, healthy community.","code":""},{"path":"https://luukvdmeer.github.io/sfnetworks/CODE_OF_CONDUCT.html","id":"our-standards","dir":"","previous_headings":"","what":"Our Standards","title":"Contributor Covenant Code of Conduct","text":"Examples behavior contributes positive environment community include: Demonstrating empathy kindness toward people respectful differing opinions, viewpoints, experiences Giving gracefully accepting constructive feedback Accepting responsibility apologizing affected mistakes, learning experience Focusing best just us individuals, overall community Examples unacceptable behavior include: use sexualized language imagery, sexual attention advances kind Trolling, insulting derogatory comments, personal political attacks Public private harassment Publishing others’ private information, physical email address, without explicit permission conduct reasonably considered inappropriate professional setting","code":""},{"path":"https://luukvdmeer.github.io/sfnetworks/CODE_OF_CONDUCT.html","id":"enforcement-responsibilities","dir":"","previous_headings":"","what":"Enforcement Responsibilities","title":"Contributor Covenant Code of Conduct","text":"Community leaders responsible clarifying enforcing standards acceptable behavior take appropriate fair corrective action response behavior deem inappropriate, threatening, offensive, harmful. Community leaders right responsibility remove, edit, reject comments, commits, code, wiki edits, issues, contributions aligned Code Conduct, communicate reasons moderation decisions appropriate.","code":""},{"path":"https://luukvdmeer.github.io/sfnetworks/CODE_OF_CONDUCT.html","id":"scope","dir":"","previous_headings":"","what":"Scope","title":"Contributor Covenant Code of Conduct","text":"Code Conduct applies within community spaces, also applies individual officially representing community public spaces. Examples representing community include using official e-mail address, posting via official social media account, acting appointed representative online offline event.","code":""},{"path":"https://luukvdmeer.github.io/sfnetworks/CODE_OF_CONDUCT.html","id":"enforcement","dir":"","previous_headings":"","what":"Enforcement","title":"Contributor Covenant Code of Conduct","text":"Instances abusive, harassing, otherwise unacceptable behavior may reported community leaders responsible enforcement lucas.vandermeer@sbg.ac.. complaints reviewed investigated promptly fairly. community leaders obligated respect privacy security reporter incident.","code":""},{"path":"https://luukvdmeer.github.io/sfnetworks/CODE_OF_CONDUCT.html","id":"enforcement-guidelines","dir":"","previous_headings":"","what":"Enforcement Guidelines","title":"Contributor Covenant Code of Conduct","text":"Community leaders follow Community Impact Guidelines determining consequences action deem violation Code Conduct:","code":""},{"path":"https://luukvdmeer.github.io/sfnetworks/CODE_OF_CONDUCT.html","id":"id_1-correction","dir":"","previous_headings":"Enforcement Guidelines","what":"1. Correction","title":"Contributor Covenant Code of Conduct","text":"Community Impact: Use inappropriate language behavior deemed unprofessional unwelcome community. Consequence: private, written warning community leaders, providing clarity around nature violation explanation behavior inappropriate. public apology may requested.","code":""},{"path":"https://luukvdmeer.github.io/sfnetworks/CODE_OF_CONDUCT.html","id":"id_2-warning","dir":"","previous_headings":"Enforcement Guidelines","what":"2. Warning","title":"Contributor Covenant Code of Conduct","text":"Community Impact: violation single incident series actions. Consequence: warning consequences continued behavior. interaction people involved, including unsolicited interaction enforcing Code Conduct, specified period time. includes avoiding interactions community spaces well external channels like social media. Violating terms may lead temporary permanent ban.","code":""},{"path":"https://luukvdmeer.github.io/sfnetworks/CODE_OF_CONDUCT.html","id":"id_3-temporary-ban","dir":"","previous_headings":"Enforcement Guidelines","what":"3. Temporary Ban","title":"Contributor Covenant Code of Conduct","text":"Community Impact: serious violation community standards, including sustained inappropriate behavior. Consequence: temporary ban sort interaction public communication community specified period time. public private interaction people involved, including unsolicited interaction enforcing Code Conduct, allowed period. Violating terms may lead permanent ban.","code":""},{"path":"https://luukvdmeer.github.io/sfnetworks/CODE_OF_CONDUCT.html","id":"id_4-permanent-ban","dir":"","previous_headings":"Enforcement Guidelines","what":"4. Permanent Ban","title":"Contributor Covenant Code of Conduct","text":"Community Impact: Demonstrating pattern violation community standards, including sustained inappropriate behavior, harassment individual, aggression toward disparagement classes individuals. Consequence: permanent ban sort public interaction within community.","code":""},{"path":"https://luukvdmeer.github.io/sfnetworks/CODE_OF_CONDUCT.html","id":"attribution","dir":"","previous_headings":"","what":"Attribution","title":"Contributor Covenant Code of Conduct","text":"Code Conduct adapted Contributor Covenant, version 2.1, available https://www.contributor-covenant.org/version/2/1/code_of_conduct.html. Community Impact Guidelines inspired Mozilla’s code conduct enforcement ladder. answers common questions code conduct, see FAQ https://www.contributor-covenant.org/faq. Translations available https://www.contributor-covenant.org/translations.","code":""},{"path":"https://luukvdmeer.github.io/sfnetworks/CONTRIBUTING.html","id":null,"dir":"","previous_headings":"","what":"How to contribute?","title":"How to contribute?","text":"look much forward contributions package. can done several ways: Create pull request specific feature implementation bug fix. Please direct develop branch. Open issue issue tracker request specific feature report bug. Please use respective issue templates . Share general ideas package starting new discussion discussion room, using ideas category. Share experiences using package work starting new discussion discussion room, using show tell category. Sharing help package developers see package used improve things accordingly, users learn package get inspiration work! Ask questions starting new discussion discussion room, using Q&category, StackOverflow sfnetwork tag. Asking questions openly helps users struggle problems!","code":""},{"path":"https://luukvdmeer.github.io/sfnetworks/CONTRIBUTING.html","id":"code-style","dir":"","previous_headings":"","what":"Code style","title":"How to contribute?","text":"strive follow tidyverse styleguide source code package. exception assignment operator: use = instead <- (see reasons ).","code":""},{"path":"https://luukvdmeer.github.io/sfnetworks/CONTRIBUTING.html","id":"structured-commit-messages","dir":"","previous_headings":"","what":"Structured commit messages","title":"How to contribute?","text":"commiting changes git commit try use structured commit messages, adapted https://www.conventionalcommits.org/. first line commit message following format: summary short (preferably < 50 characters), starting upper case, written present tense. commit references specific issue, include Refs # summary. issue bug report, may also use Fix # issue gets closed automatically. type one defined types listed . feel artistic, can end commit message emoji belonging type 😎. feat: Implementation new feature. :gift: 🎁 fix: bug fix. :wrench: 🔧 style: Changes code formatting. change program logic. :art: 🎨 refactor: Changes existing functionality change behaviour. :construction: 🚧 breaking: Changes existing functionality backwards compatible. :warning: ⚠️ docs: Adding, removing updating user documentation. :books: 📚 logs: Adding, removing updating log messages. :sound: 🔉 test: Adding, removing updating tests. changes user code. :test_tube: 🧪 cicd: Adding, removing updating CI/CD workflows. changes user code. :robot: 🤖 deps: Adding, removing updating dependencies. :couple: 👫 release: Preparing release, e.g. updating version numbers. :bookmark: 🔖 repo: Changes repository involve code/documentation, e.g. adding templates community files. :package: 📦 Example commit messages :","code":": git commit -m 'feat: Add bar parameter to foo(). Refs #10 :gift:' git commit -m 'fix: Include type checking in foo(). Fix #12 :wrench:'"},{"path":"https://luukvdmeer.github.io/sfnetworks/CONTRIBUTING.html","id":"code-of-conduct","dir":"","previous_headings":"","what":"Code of conduct","title":"How to contribute?","text":"project released Contributor Code Conduct. participating project agree abide terms.","code":""},{"path":"https://luukvdmeer.github.io/sfnetworks/LICENSE.html","id":null,"dir":"","previous_headings":"","what":"Apache License","title":"Apache License","text":"Version 2.0, January 2004 ","code":""},{"path":[]},{"path":"https://luukvdmeer.github.io/sfnetworks/LICENSE.html","id":"id_1-definitions","dir":"","previous_headings":"Terms and Conditions for use, reproduction, and distribution","what":"1. Definitions","title":"Apache License","text":"“License” shall mean terms conditions use, reproduction, distribution defined Sections 1 9 document. “Licensor” shall mean copyright owner entity authorized copyright owner granting License. “Legal Entity” shall mean union acting entity entities control, controlled , common control entity. purposes definition, “control” means () power, direct indirect, cause direction management entity, whether contract otherwise, (ii) ownership fifty percent (50%) outstanding shares, (iii) beneficial ownership entity. “” (“”) shall mean individual Legal Entity exercising permissions granted License. “Source” form shall mean preferred form making modifications, including limited software source code, documentation source, configuration files. “Object” form shall mean form resulting mechanical transformation translation Source form, including limited compiled object code, generated documentation, conversions media types. “Work” shall mean work authorship, whether Source Object form, made available License, indicated copyright notice included attached work (example provided Appendix ). “Derivative Works” shall mean work, whether Source Object form, based (derived ) Work editorial revisions, annotations, elaborations, modifications represent, whole, original work authorship. purposes License, Derivative Works shall include works remain separable , merely link (bind name) interfaces , Work Derivative Works thereof. “Contribution” shall mean work authorship, including original version Work modifications additions Work Derivative Works thereof, intentionally submitted Licensor inclusion Work copyright owner individual Legal Entity authorized submit behalf copyright owner. purposes definition, “submitted” means form electronic, verbal, written communication sent Licensor representatives, including limited communication electronic mailing lists, source code control systems, issue tracking systems managed , behalf , Licensor purpose discussing improving Work, excluding communication conspicuously marked otherwise designated writing copyright owner “Contribution.” “Contributor” shall mean Licensor individual Legal Entity behalf Contribution received Licensor subsequently incorporated within Work.","code":""},{"path":"https://luukvdmeer.github.io/sfnetworks/LICENSE.html","id":"id_2-grant-of-copyright-license","dir":"","previous_headings":"Terms and Conditions for use, reproduction, and distribution","what":"2. Grant of Copyright License","title":"Apache License","text":"Subject terms conditions License, Contributor hereby grants perpetual, worldwide, non-exclusive, -charge, royalty-free, irrevocable copyright license reproduce, prepare Derivative Works , publicly display, publicly perform, sublicense, distribute Work Derivative Works Source Object form.","code":""},{"path":"https://luukvdmeer.github.io/sfnetworks/LICENSE.html","id":"id_3-grant-of-patent-license","dir":"","previous_headings":"Terms and Conditions for use, reproduction, and distribution","what":"3. Grant of Patent License","title":"Apache License","text":"Subject terms conditions License, Contributor hereby grants perpetual, worldwide, non-exclusive, -charge, royalty-free, irrevocable (except stated section) patent license make, made, use, offer sell, sell, import, otherwise transfer Work, license applies patent claims licensable Contributor necessarily infringed Contribution(s) alone combination Contribution(s) Work Contribution(s) submitted. institute patent litigation entity (including cross-claim counterclaim lawsuit) alleging Work Contribution incorporated within Work constitutes direct contributory patent infringement, patent licenses granted License Work shall terminate date litigation filed.","code":""},{"path":"https://luukvdmeer.github.io/sfnetworks/LICENSE.html","id":"id_4-redistribution","dir":"","previous_headings":"Terms and Conditions for use, reproduction, and distribution","what":"4. Redistribution","title":"Apache License","text":"may reproduce distribute copies Work Derivative Works thereof medium, without modifications, Source Object form, provided meet following conditions: () must give recipients Work Derivative Works copy License; (b) must cause modified files carry prominent notices stating changed files; (c) must retain, Source form Derivative Works distribute, copyright, patent, trademark, attribution notices Source form Work, excluding notices pertain part Derivative Works; (d) Work includes “NOTICE” text file part distribution, Derivative Works distribute must include readable copy attribution notices contained within NOTICE file, excluding notices pertain part Derivative Works, least one following places: within NOTICE text file distributed part Derivative Works; within Source form documentation, provided along Derivative Works; , within display generated Derivative Works, wherever third-party notices normally appear. contents NOTICE file informational purposes modify License. may add attribution notices within Derivative Works distribute, alongside addendum NOTICE text Work, provided additional attribution notices construed modifying License. may add copyright statement modifications may provide additional different license terms conditions use, reproduction, distribution modifications, Derivative Works whole, provided use, reproduction, distribution Work otherwise complies conditions stated License.","code":""},{"path":"https://luukvdmeer.github.io/sfnetworks/LICENSE.html","id":"id_5-submission-of-contributions","dir":"","previous_headings":"Terms and Conditions for use, reproduction, and distribution","what":"5. Submission of Contributions","title":"Apache License","text":"Unless explicitly state otherwise, Contribution intentionally submitted inclusion Work Licensor shall terms conditions License, without additional terms conditions. Notwithstanding , nothing herein shall supersede modify terms separate license agreement may executed Licensor regarding Contributions.","code":""},{"path":"https://luukvdmeer.github.io/sfnetworks/LICENSE.html","id":"id_6-trademarks","dir":"","previous_headings":"Terms and Conditions for use, reproduction, and distribution","what":"6. Trademarks","title":"Apache License","text":"License grant permission use trade names, trademarks, service marks, product names Licensor, except required reasonable customary use describing origin Work reproducing content NOTICE file.","code":""},{"path":"https://luukvdmeer.github.io/sfnetworks/LICENSE.html","id":"id_7-disclaimer-of-warranty","dir":"","previous_headings":"Terms and Conditions for use, reproduction, and distribution","what":"7. Disclaimer of Warranty","title":"Apache License","text":"Unless required applicable law agreed writing, Licensor provides Work (Contributor provides Contributions) “” BASIS, WITHOUT WARRANTIES CONDITIONS KIND, either express implied, including, without limitation, warranties conditions TITLE, NON-INFRINGEMENT, MERCHANTABILITY, FITNESS PARTICULAR PURPOSE. solely responsible determining appropriateness using redistributing Work assume risks associated exercise permissions License.","code":""},{"path":"https://luukvdmeer.github.io/sfnetworks/LICENSE.html","id":"id_8-limitation-of-liability","dir":"","previous_headings":"Terms and Conditions for use, reproduction, and distribution","what":"8. Limitation of Liability","title":"Apache License","text":"event legal theory, whether tort (including negligence), contract, otherwise, unless required applicable law (deliberate grossly negligent acts) agreed writing, shall Contributor liable damages, including direct, indirect, special, incidental, consequential damages character arising result License use inability use Work (including limited damages loss goodwill, work stoppage, computer failure malfunction, commercial damages losses), even Contributor advised possibility damages.","code":""},{"path":"https://luukvdmeer.github.io/sfnetworks/LICENSE.html","id":"id_9-accepting-warranty-or-additional-liability","dir":"","previous_headings":"Terms and Conditions for use, reproduction, and distribution","what":"9. Accepting Warranty or Additional Liability","title":"Apache License","text":"redistributing Work Derivative Works thereof, may choose offer, charge fee , acceptance support, warranty, indemnity, liability obligations /rights consistent License. However, accepting obligations, may act behalf sole responsibility, behalf Contributor, agree indemnify, defend, hold Contributor harmless liability incurred , claims asserted , Contributor reason accepting warranty additional liability. END TERMS CONDITIONS","code":""},{"path":"https://luukvdmeer.github.io/sfnetworks/LICENSE.html","id":"appendix-how-to-apply-the-apache-license-to-your-work","dir":"","previous_headings":"","what":"APPENDIX: How to apply the Apache License to your work","title":"Apache License","text":"apply Apache License work, attach following boilerplate notice, fields enclosed brackets [] replaced identifying information. (Don’t include brackets!) text enclosed appropriate comment syntax file format. also recommend file class name description purpose included “printed page” copyright notice easier identification within third-party archives.","code":"Copyright 2020 sfnetworks authors Licensed under the Apache License, Version 2.0 (the \"License\"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License."},{"path":"https://luukvdmeer.github.io/sfnetworks/articles/sfn01_intro.html","id":"rationale","dir":"Articles","previous_headings":"","what":"Rationale","title":"Introduction to sfnetworks","text":"R good packages respectively geospatial analysis standard network analysis: sf package brings simple features standard R provides interface low-level geospatial system libraries GDAL, GEOS, s2, allowing represent analyze spatial vector data points, lines polygons. tidygraph package provides tidy interface large network analysis library igraph, written C also R API. packages great purposes. However, sf know networks, tidygraph know space. combining forces, sfnetworks enables integrated workflows connecting network analysis spatial analysis. addition, offers functions specific spatial network analysis, found either two “parent packages”. , often utilizes additional building blocks within R world.","code":""},{"path":"https://luukvdmeer.github.io/sfnetworks/articles/sfn01_intro.html","id":"representing-spatial-networks","dir":"Articles","previous_headings":"","what":"Representing spatial networks","title":"Introduction to sfnetworks","text":"Spatial networks sfnetworks represented objects class sfnetwork. objects inherit tbl_graph class tidygraph, turn inherit igraph class igraph. means core designed store graph structures. However, thanks design tidygraph, look like collection two flat tables: one nodes, one edges. tidygraph tables can treated tibbles, sfnetworks sf data frames list column containing geometry feature. sfnetworks, edges can either directed (default) undirected. Mixed networks contain types edges, e.g. road networks oneway streets, can represented duplicating reversing edges can traveled ways. nodes spatial networks need explicitly store geometries, edges always required. edges straight lines, spatial embedding can also inferred spatial locations nodes connect. sfnetworks refer two approaches spatially explicit edges spatially implicit edges, respectively. details representation spatial networks sfnetwork class can found vignette Creating representing spatial networks. many different ways create sfnetwork object, explained detail vignette Creating representing spatial networks. commonly start set spatial features, stored object class sf. features linestrings, considered edges network, nodes created endpoints. multiple linestrings share endpoint, becomes single node network, hence, edges adjacent. features points, considered nodes network, connected edges according given adjacency matrix. adjacency matrix can also created internally according specified method.","code":"net = as_sfnetwork(roxel) net #> # A sfnetwork: 987 nodes and 1215 edges #> # #> # A directed multigraph with 9 components and spatially explicit edges #> # #> # Dimension: XY #> # Bounding box: xmin: 7.522595 ymin: 51.94151 xmax: 7.546705 ymax: 51.96119 #> # Geodetic CRS: WGS 84 #> # #> # Node data: 987 × 1 (active) #> geometry #> #> 1 (7.538109 51.95286) #> 2 (7.537867 51.95282) #> 3 (7.537815 51.95867) #> 4 (7.537015 51.95848) #> 5 (7.533441 51.95578) #> 6 (7.533415 51.95561) #> # ℹ 981 more rows #> # #> # Edge data: 1,215 × 5 #> from to name type geometry #> #> 1 1 2 Hagemanns Kämpken residential (7.538109 51.95286, 7.537867 51.95… #> 2 3 4 Stiegkamp residential (7.537815 51.95867, 7.537015 51.95… #> 3 5 6 Havixbecker Straße residential (7.533441 51.95578, 7.533467 51.95… #> # ℹ 1,212 more rows plot(net) net = as_sfnetwork(mozart, connections = \"gabriel\", directed = FALSE) net #> # A sfnetwork: 17 nodes and 25 edges #> # #> # A bipartite simple graph with 1 component and spatially explicit edges #> # #> # Dimension: XY #> # Bounding box: xmin: 4548664 ymin: 2747309 xmax: 4549589 ymax: 2748537 #> # Projected CRS: ETRS89-extended / LAEA Europe #> # #> # Node data: 17 × 4 (active) #> name type website geometry #> #> 1 Mozartkino cinema https://www.mozartki… (4549504 2747309) #> 2 Haus für Mozart theatre NA (4549003 2747376) #> 3 Mozartsteg/Rudolfskai bus_stop NA (4549589 2747507) #> 4 Mozart Denkmal artwork NA (4549387 2747514) #> 5 Mozartsteg/Rudolfskai bus_stop NA (4549491 2747551) #> 6 Mozartsteg bridge NA (4549473 2747624) #> # ℹ 11 more rows #> # #> # Edge data: 25 × 3 #> from to geometry #> #> 1 1 3 (4549504 2747309, 4549589 2747507) #> 2 1 4 (4549504 2747309, 4549387 2747514) #> 3 2 4 (4549003 2747376, 4549387 2747514) #> # ℹ 22 more rows plot(net)"},{"path":"https://luukvdmeer.github.io/sfnetworks/articles/sfn01_intro.html","id":"analyzing-spatial-networks","dir":"Articles","previous_headings":"","what":"Analyzing spatial networks","title":"Introduction to sfnetworks","text":"Thanks design sf tidygraph, spatial network analysis sfnetworks can fitted seamlessly tidy data analysis workflows using tidyverse family packages. Since sfnetwork object can treated collection two tables, rather one, just need specify want apply function. , tidygraph invented activate() verb, allowing set either nodes edges target analysis. done , can apply favorite tidyverse verb just ’re used . can see activation network element also changes order printed. Obviously network just list two distinct elements. Nodes edges related . Therefore, operations applied nodes may also affect edges, vice versa. good example filtering. Whenever nodes removed network, edges terminating nodes removed . behavior symmetric: removing edges, endpoints edges remain, even endpoint edge. definition edges can never exist without nodes ends, nodes can peacefully exist isolation. Another consequence working relational data operations defined single tables applicable networks. example, common groupby-apply-combine workflows supported, since break relational structure. cases, however, can always extract active element network either sf object tibble, proceed analysis single table. allow performing common network analysis tasks, sfnetworks builds upon tidygraph. Since sfnetwork objects inherit tbl_graph class, analytical functions tidygraph can directly used. lot functions available, tidy wrappers around functions igraph library. complete overview, check tidygraph documentation. important note case spatial networks often makes sense use geographic length edge weight. Since tidygraph know space, never set automatically, explicitly specify every time call function can consider edge weights. Read specifying edge weights vignette Routing spatial networks. large set functions tidygraph dedicated computation quantitative measures nodes, edges, network whole. known centrality measures, define importance node network. names implemented centrality measure functions formatted centrality_*. implemented measure functions names formatted node_* (node measures) edge_* (edge measures) graph_* (network measures). special group measure functions logical measures, return either TRUE FALSE, indicating node, edge network specified type. None functions meant called directly, used inside tidyverse-verbs dplyr::mutate() dplyr::filter(), analyzed network know thus needed input function. tidygraph::with_graph() can used evaluate measure context specific network, outside tidyverse framework. Another set functions tidygraph deals community detection networks. functions group nodes edges based clustering algorithm. names formatted group_*, always return vector group indices, one feature. implemented algorithms try create groups nodes number edges within groups relatively high compared number edges groups, example . note algorithms generally designed account spatial factors, may limited use working spatial networks. Finally, tidygraph introduced new set network analysis functions call morphers. Morphers change structure input graph, example subsetting splitting , combining multiple features one, converting nodes edges vice versa. different struture needed computations, can set temporarily providing morphers subsequently tidygraph::morph() tidygraph::unmorph() verbs. different structure meant last, morpher can provided tidygraph::convert() verb instead. example convert network minimum spanning tree, contains minimum set edges need nodes still connected like . writing methods many spatial analytical functions sf package, sfnetworks allows functions called directly sfnetwork objects, without need conversion. See overview sf functions method sfnetwork objects. complete overview functionalities sf, check sf documentation. One many tasks sf covers specification coordinate reference systems, CRS short, transformation spatial coordinates systems. sfnetwork object nodes edges always CRS, matter elements active retrieve CRS, transform coordinates different CRS. sf also multiple functions implement evaluation spatial predicate. spatial predicate describes spatial relation two geometries. example, point may located within polygon B. example show evaluate node spatial network located within one two given polygons. using spatial predicates, sf offers ability perform spatial joins spatial filters. Spatial joins join information spatial feature features specified spatial relation . Spatial filters keep features specified spatial relation, removes . details spatial joins filters spatial networks, see vignette Spatial joins filters. Finally, sf contains group functions known geometric unary operations. functions change structure individual geometries. usage context spatial networks limited, since many break network structure endpoints edges spatially equal respective nodes. Hence, geometric unary operations change type, shape, position geometries method sfnetwork objects. include sf::st_reverse() reverse edge geometries, sf::st_segmentize() add interior points edge geometries. However, just unsupported tidyverse-verbs, can still apply unsupported geometric unary operations first extracting active element sf object, proceed analysis single table. mentioned, sfnetworks extends functionalities tidygraph sf offering functions specific spatial network analysis, well functions allow smoother integration sf design tidygraph workflows. contradiction tidygraph, functions sfnetworks consider edge weights always use geographic edge length default weight. first family functions sfnetworks names formatted st_network_*, adopting naming conventions sf. functions take spatial network first input implement analysis task involves network set regular spatial simple features (points, lines, polygons). returned object can either set spatial simple features computed network, network spatial features merged , another object (e.g., matrix) result computation relating network spatial features. covers large range use-cases. Examples include drawing isochrone isodistance polygons around nodes, finding geographic shortest paths pairs nodes, computing cost matrices travel nodes, extracting faces network, adding external point data new nodes network. vignettes find details functions. also functions sfnetworks start st_*, end *_network. contradiction st_network_* functions, functions take set spatial features first input, network additional argument. example st_project_on_network, projects points onto network. Shortest path Isodistance polygon Network faces Blended points extension measure functions tidygraph, several spatial measure functions nodes edges found sfnetworks. Just tidygraph, functions named style node_* edge_*, centrality measure, centrality_*. Edge measures can computed include example geographic length edge, azimuth, circuity (.e. ratio geographic length shortest euclidean distance source target node). nodes, example possible compute straightness centrality (.e. average ratio euclidean distance network distance node nodes network). better integrate spatial predicate functions sf design tidygraph, applicable predicates also implemented node edge measure function. functions return TRUE node edge specified spatial relation least one given spatial features, FALSE otherwise. makes easy use predicates directly inside functions dplyr::filter() dplyr::mutate(). extension community detection functions tidygraph, sfnetworks contains group_spatial_dbscan() function find spatial clusters nodes. idea offer multiple spatial clustering algorithms choose , currently one implemented DBSCAN algorithm (require dbscan package installed). algorithm executed network distance matrix nodes, euclidean distance matrix. extension morpher functions tidygraph, many different spatial morpher functions implemented sfnetworks. Just tidygraph, function change structure input network, example subsetting splitting , combining multiple features one, splitting single features. Common examples include subdividing network interior points edge geometries, smoothing pseudo nodes degree 2, contracting multiple nodes one preserving network connectivity. vignettes find details functions. Many morphers used network cleaning operations, described detail vignette Cleaning spatial networks. Smooth network Subdivision smooth network Contracted groups nodes single path Finally, sfnetworks exports kind utility functions make working spatial networks less cumbersome. example finding nearest node nearest edge given spatial feature. overview exported functions package, see function reference. Nearest node Nearest edge Also fan tidyverse style data analysis, sfnetworks can . Since sfnetwork objects inherit igraph class, can apply functions large igraph package . means, example, instead using dplyr::mutate() dplyr::filter(), proceed follows (note igraph, term vertex used instead node). can see, returns igraph object instead sfnetwork object. preserve class, can use wrap_igraph() function sfnetworks igraph function accepts network first input returns another network. function check returned network still spatial. spatial measure functions can evaluated outside tidygraph framework using with_graph(), works similar base R’s () function. spatial morpher functions implement larger workflow internal workers exported, meaning can called directly outside tidygraph::morph() tidygraph::convert() verbs. morphers easy replicate using sf sfnetworks functions directly.","code":"net |> activate(nodes) |> mutate(label = letters[1:n()]) |> select(name, label) |> activate(edges) |> filter(sample(c(TRUE, FALSE), n(), replace = TRUE)) #> # A sfnetwork: 17 nodes and 13 edges #> # #> # An unrooted forest with 4 trees and spatially explicit edges #> # #> # Dimension: XY #> # Bounding box: xmin: 4548664 ymin: 2747309 xmax: 4549589 ymax: 2748537 #> # Projected CRS: ETRS89-extended / LAEA Europe #> # #> # Edge data: 13 × 3 (active) #> from to geometry #> #> 1 1 4 (4549504 2747309, 4549387 2747514) #> 2 3 5 (4549589 2747507, 4549491 2747551) #> 3 4 5 (4549387 2747514, 4549491 2747551) #> 4 4 9 (4549387 2747514, 4549120 2747654) #> 5 6 10 (4549473 2747624, 4549418 2747723) #> 6 7 9 (4549064 2747619, 4549120 2747654) #> # ℹ 7 more rows #> # #> # Node data: 17 × 3 #> name label geometry #> #> 1 Mozartkino a (4549504 2747309) #> 2 Haus für Mozart b (4549003 2747376) #> 3 Mozartsteg/Rudolfskai c (4549589 2747507) #> # ℹ 14 more rows # Filtering nodes also reduces the number of edges. net |> activate(nodes) |> filter(type == \"artwork\") #> # A sfnetwork: 3 nodes and 0 edges #> # #> # An unrooted forest with 3 trees and spatially implicit edges #> # #> # Dimension: XY #> # Bounding box: xmin: 4548664 ymin: 2747514 xmax: 4549387 ymax: 2747868 #> # Projected CRS: ETRS89-extended / LAEA Europe #> # #> # Node data: 3 × 4 (active) #> name type website geometry #> #> 1 Mozart Denkmal artwork NA (4549387 2747514) #> 2 Spirit of Mozart artwork https://salzburgfoundat… (4549119 2747790) #> 3 Mozart-Eine Hommage artwork https://salzburgfoundat… (4548664 2747868) #> # #> # Edge data: 0 × 3 #> # ℹ 3 variables: from , to , geometry net |> activate(nodes) |> st_as_sf() |> group_by(type) |> summarize(n = n()) #> Simple feature collection with 13 features and 2 fields #> Geometry type: GEOMETRY #> Dimension: XY #> Bounding box: xmin: 4548664 ymin: 2747309 xmax: 4549589 ymax: 2748537 #> Projected CRS: ETRS89-extended / LAEA Europe #> # A tibble: 13 × 3 #> type n geometry #> #> 1 apartments 1 POINT (4549073 2747916) #> 2 artwork 3 MULTIPOINT ((4548664 2747868), (4549119 2747790), (45493… #> 3 bridge 1 POINT (4549473 2747624) #> 4 bus_stop 3 MULTIPOINT ((4549418 2747723), (4549491 2747551), (45495… #> 5 cafe 1 POINT (4548994 2747632) #> 6 cinema 1 POINT (4549504 2747309) #> 7 concert_hall 1 POINT (4548897 2748037) #> 8 confectionery 1 POINT (4549120 2747654) #> 9 dormitory 1 POINT (4548984 2748537) #> 10 hotel 1 POINT (4549378 2748391) #> 11 museum 1 POINT (4549064 2747619) #> 12 theatre 1 POINT (4549003 2747376) #> 13 university 1 POINT (4549059 2748042) net = net |> activate(edges) |> mutate(length = edge_length()) net #> # A sfnetwork: 17 nodes and 25 edges #> # #> # A bipartite simple graph with 1 component and spatially explicit edges #> # #> # Dimension: XY #> # Bounding box: xmin: 4548664 ymin: 2747309 xmax: 4549589 ymax: 2748537 #> # Projected CRS: ETRS89-extended / LAEA Europe #> # #> # Edge data: 25 × 4 (active) #> from to geometry length #> [m] #> 1 1 3 (4549504 2747309, 4549589 2747507) 216. #> 2 1 4 (4549504 2747309, 4549387 2747514) 236. #> 3 2 4 (4549003 2747376, 4549387 2747514) 409. #> 4 2 7 (4549003 2747376, 4549064 2747619) 250. #> 5 2 8 (4549003 2747376, 4548994 2747632) 256. #> 6 3 5 (4549589 2747507, 4549491 2747551) 107. #> # ℹ 19 more rows #> # #> # Node data: 17 × 4 #> name type website geometry #> #> 1 Mozartkino cinema https://www.mozartki… (4549504 2747309) #> 2 Haus für Mozart theatre NA (4549003 2747376) #> 3 Mozartsteg/Rudolfskai bus_stop NA (4549589 2747507) #> # ℹ 14 more rows new_net = net |> activate(edges) |> filter(!edge_is_incident(13)) |> activate(nodes) |> mutate(bc = centrality_betweenness(weights = length)) new_net #> # A sfnetwork: 17 nodes and 23 edges #> # #> # A bipartite simple graph with 2 components and spatially explicit edges #> # #> # Dimension: XY #> # Bounding box: xmin: 4548664 ymin: 2747309 xmax: 4549589 ymax: 2748537 #> # Projected CRS: ETRS89-extended / LAEA Europe #> # #> # Node data: 17 × 5 (active) #> name type website geometry bc #> #> 1 Mozartkino cinema https://www.mo… (4549504 2747309) 0 #> 2 Haus für Mozart theatre NA (4549003 2747376) 0 #> 3 Mozartsteg/Rudolfskai bus_stop NA (4549589 2747507) 5 #> 4 Mozart Denkmal artwork NA (4549387 2747514) 21 #> 5 Mozartsteg/Rudolfskai bus_stop NA (4549491 2747551) 22 #> 6 Mozartsteg bridge NA (4549473 2747624) 16 #> # ℹ 11 more rows #> # #> # Edge data: 23 × 4 #> from to geometry length #> [m] #> 1 1 3 (4549504 2747309, 4549589 2747507) 216. #> 2 1 4 (4549504 2747309, 4549387 2747514) 236. #> 3 2 4 (4549003 2747376, 4549387 2747514) 409. #> # ℹ 20 more rows ggraph(new_net, \"sf\") + geom_edge_sf() + geom_node_sf(aes(size = bc)) + theme_void() with_graph(net, centrality_degree()) |> setNames(NULL) #> [1] 2 3 2 4 3 2 3 3 4 4 3 2 2 4 3 3 3 new_net = net |> activate(nodes) |> mutate(group = group_optimal()) ggraph(new_net, \"sf\") + geom_edge_sf() + geom_node_sf(aes(color = as.factor(group)), size = 4) + scale_colour_discrete(\"group\") + theme_void() new_net = net |> convert(to_minimum_spanning_tree, weights = length) ggraph(new_net, \"sf\") + geom_edge_sf() + geom_node_sf(size = 4) + theme_void() st_crs(net)$epsg #> [1] 3035 st_transform(net, 4326) #> # A sfnetwork: 17 nodes and 25 edges #> # #> # A bipartite simple graph with 1 component and spatially explicit edges #> # #> # Dimension: XY #> # Bounding box: xmin: 13.03835 ymin: 47.79698 xmax: 13.05049 ymax: 47.80822 #> # Geodetic CRS: WGS 84 #> # #> # Edge data: 25 × 4 (active) #> from to geometry length #> [m] #> 1 1 3 (13.04925 47.79698, 13.05049 47.79874) 216. #> 2 1 4 (13.04925 47.79698, 13.04781 47.79887) 236. #> 3 2 4 (13.0426 47.79778, 13.04781 47.79887) 409. #> 4 2 7 (13.0426 47.79778, 13.04355 47.79993) 250. #> 5 2 8 (13.0426 47.79778, 13.04263 47.80008) 256. #> 6 3 5 (13.05049 47.79874, 13.04921 47.79917) 107. #> # ℹ 19 more rows #> # #> # Node data: 17 × 4 #> name type website geometry #> #> 1 Mozartkino cinema https://www.mozartki… (13.04925 47.79698) #> 2 Haus für Mozart theatre NA (13.0426 47.79778) #> 3 Mozartsteg/Rudolfskai bus_stop NA (13.05049 47.79874) #> # ℹ 14 more rows polys = mozart |> slice(4, 15) |> st_buffer(325) |> mutate(label = c(\"A\", \"B\")) |> select(label) ggraph(net, \"sf\") + geom_sf(data = polys, linewidth = 1, color = \"orange\") + geom_edge_sf() + geom_node_sf(size = 4) + theme_void() net |> activate(nodes) |> st_within(polys) #> Sparse geometry binary predicate list of length 17, where the predicate #> was `within' #> first 10 elements: #> 1: 1 #> 2: (empty) #> 3: 1 #> 4: 1 #> 5: 1 #> 6: 1 #> 7: (empty) #> 8: (empty) #> 9: 1 #> 10: 1 new_net = net |> activate(nodes) |> st_join(polys, join = st_within) ggraph(new_net, \"sf\") + geom_sf(data = polys, linewidth = 1, color = \"orange\") + geom_edge_sf() + geom_node_sf(aes(color = as.factor(label)), size = 4) + scale_colour_discrete(\"label\") + theme_void() new_net = net |> activate(nodes) |> st_filter(polys, .predicate = st_within) ggraph(new_net, \"sf\") + geom_sf(data = polys, linewidth = 1, color = \"orange\") + geom_edge_sf() + geom_node_sf(size = 4) + theme_void() net |> activate(nodes) |> st_as_sf() |> st_buffer(250) #> Simple feature collection with 17 features and 3 fields #> Attribute-geometry relationships: constant (3) #> Geometry type: POLYGON #> Dimension: XY #> Bounding box: xmin: 4548414 ymin: 2747059 xmax: 4549839 ymax: 2748787 #> Projected CRS: ETRS89-extended / LAEA Europe #> # A tibble: 17 × 4 #> name type website geometry #> * #> 1 Mozartkino cinema https://www.… ((4549754 2747309, 45497… #> 2 Haus für Mozart theatre NA ((4549253 2747376, 45492… #> 3 Mozartsteg/Rudolfskai bus_stop NA ((4549839 2747507, 45498… #> 4 Mozart Denkmal artwork NA ((4549637 2747514, 45496… #> 5 Mozartsteg/Rudolfskai bus_stop NA ((4549741 2747551, 45497… #> 6 Mozartsteg bridge NA ((4549723 2747624, 45497… #> 7 Mozarts Geburtshaus museum http://www.m… ((4549314 2747619, 45493… #> 8 Café Mozart cafe https://www.… ((4549244 2747632, 45492… #> 9 Mozartkugel confectionery NA ((4549370 2747654, 45493… #> 10 Mozartsteg/Imbergstraße bus_stop NA ((4549668 2747723, 45496… #> 11 Spirit of Mozart artwork https://salz… ((4549369 2747790, 45493… #> 12 Mozart-Eine Hommage artwork https://salz… ((4548914 2747868, 45489… #> 13 Mozarts Wohnhaus apartments NA ((4549323 2747916, 45493… #> 14 Universität Mozarteum university NA ((4549309 2748042, 45493… #> 15 Stiftung Mozarteum concert_hall NA ((4549147 2748037, 45491… #> 16 Hotel Mozart hotel http://www.h… ((4549628 2748391, 45496… #> 17 Mozart Studentenheim dormitory NA ((4549234 2748537, 45492… # Find shortest path between node 1 and node 17. path = st_network_paths(net, 1, 17) # Draw an isodistance polygon with 500m threshold around node 13. iso = st_network_iso(net, 13, 500) # Extract the faces of the network. faces = st_network_faces(net) # Blend external points as new nodes into the network. feats = st_sample(st_bbox(mozart), 10) blend = st_network_blend(net, feats) ggraph(net, \"sf\") + geom_edge_sf() + geom_sf(data = path, color = \"orange\", linewidth = 2) + geom_node_sf(size = 4) + geom_sf(data = st_geometry(net, \"nodes\")[c(1, 17)], size = 6) + theme_void() ggraph(net, \"sf\") + geom_sf(data = iso, fill = \"orange\", alpha = 0.7) + geom_edge_sf() + geom_node_sf(size = 4) + geom_sf(data = st_geometry(net, \"nodes\")[13], size = 6) + theme_void() faces_sf = st_sf(id = c(1:length(faces)), geometry = faces) ggraph(net, \"sf\") + geom_sf(data = faces_sf, aes(fill = as.factor(id)), show.legend = FALSE) + geom_edge_sf() + geom_node_sf(size = 4) + theme_void() ggraph(blend, \"sf\") + geom_edge_sf() + geom_node_sf(size = 4) + geom_sf(data = feats, color = \"orange\", size = 4) + geom_sf( data = st_nearest_points(feats, st_combine(st_geometry(blend, \"nodes\"))), color = \"grey\", linetype = 2 ) + theme_void() new_net = net |> activate(edges) |> filter(edge_intersects(polys)) |> mutate(circuity = edge_circuity()) |> activate(nodes) |> mutate( sc = centrality_straightness(), in_poly = node_is_within(polys) ) new_net #> # A sfnetwork: 17 nodes and 21 edges #> # #> # A bipartite simple graph with 1 component and spatially explicit edges #> # #> # Dimension: XY #> # Bounding box: xmin: 4548664 ymin: 2747309 xmax: 4549589 ymax: 2748537 #> # Projected CRS: ETRS89-extended / LAEA Europe #> # #> # Node data: 17 × 6 (active) #> name type website geometry sc in_poly #> #> 1 Mozartkino cinema https:… (4549504 2747309) 0.847 TRUE #> 2 Haus für Mozart theatre NA (4549003 2747376) 0.648 FALSE #> 3 Mozartsteg/Rudolfskai bus_stop NA (4549589 2747507) 0.878 TRUE #> 4 Mozart Denkmal artwork NA (4549387 2747514) 0.850 TRUE #> 5 Mozartsteg/Rudolfskai bus_stop NA (4549491 2747551) 0.874 TRUE #> 6 Mozartsteg bridge NA (4549473 2747624) 0.843 TRUE #> # ℹ 11 more rows #> # #> # Edge data: 21 × 5 #> from to geometry length circuity #> [m] #> 1 1 3 (4549504 2747309, 4549589 2747507) 216. 1 #> 2 1 4 (4549504 2747309, 4549387 2747514) 236. 1 #> 3 2 4 (4549003 2747376, 4549387 2747514) 409. 1 #> # ℹ 18 more rows new_net = net |> activate(nodes) |> mutate(group = group_spatial_dbscan(300)) ggraph(new_net, \"sf\") + geom_edge_sf() + geom_node_sf(aes(color = as.factor(group)), size = 4) + scale_colour_discrete(\"group\") + theme_void() # Smooth nodes of degree 2. smooth = convert(net, to_spatial_smooth) # Subdivide edges at each interior point in the smoothed network. # In this case this is the opposite of smoothing, it adds back the degree 2 nodes. division = convert(smooth, to_spatial_subdivision, all = TRUE) # Contract nodes that are in the same spatial cluster. contraction = net |> activate(nodes) |> mutate(group = group_spatial_dbscan(300)) |> convert(to_spatial_contracted, group) # Subset the graph to only those edges in a shortest path. path = convert(net, to_spatial_shortest_paths, 1, 17) ggraph(smooth, \"sf\") + geom_edge_sf() + geom_node_sf(size = 4) + theme_void() ggraph(division, \"sf\") + geom_edge_sf() + geom_node_sf(size = 4) + theme_void() ggraph(contraction, \"sf\") + geom_edge_sf() + geom_node_sf(size = 4) + theme_void() ggraph(path, \"sf\") + geom_edge_sf() + geom_node_sf(size = 4) + theme_void() p = st_centroid(st_combine(mozart)) nn = nearest_nodes(net, p) nn #> Simple feature collection with 1 feature and 3 fields #> Attribute-geometry relationships: constant (3) #> Geometry type: POINT #> Dimension: XY #> Bounding box: xmin: 4549119 ymin: 2747790 xmax: 4549119 ymax: 2747790 #> Projected CRS: ETRS89-extended / LAEA Europe #> # A tibble: 1 × 4 #> name type website geometry #> #> 1 Spirit of Mozart artwork https://salzburgfoundation… (4549119 2747790) ne = nearest_edges(net, p) ne #> Simple feature collection with 1 feature and 3 fields #> Geometry type: LINESTRING #> Dimension: XY #> Bounding box: xmin: 4549119 ymin: 2747723 xmax: 4549418 ymax: 2747790 #> Projected CRS: ETRS89-extended / LAEA Europe #> # A tibble: 1 × 4 #> from to geometry length #> [m] #> 1 10 11 (4549418 2747723, 4549119 2747790) 306. ggraph(net, \"sf\") + geom_sf(data = p, size = 6, pch = 8) + geom_edge_sf(color = \"grey\") + geom_node_sf(color = \"grey\", size = 4) + geom_sf(data = nn, color = \"orange\", size = 6) + theme_void() ggraph(net, \"sf\") + geom_sf(data = p, size = 6, pch = 8) + geom_edge_sf(color = \"grey\") + geom_sf(data = ne, color = \"orange\", linewidth = 2) + geom_node_sf(color = \"grey\", size = 4) + theme_void() # Mutate. vertex_attr(net, \"label\") = letters[1:vcount(net)] # Filter. drop = which(!sample(c(TRUE, FALSE), ecount(net), replace = TRUE)) new_net = delete_edges(net, drop) new_net #> IGRAPH f481e4e UN-B 17 12 -- #> + attr: name (v/c), type (v/c), website (v/c), geometry (v/x), label #> | (v/c), geometry (e/x), length (e/n) #> + edges from f481e4e (vertex names): #> [1] Mozartkino --Mozartsteg/Rudolfskai #> [2] Haus für Mozart --Café Mozart #> [3] Mozart Denkmal --Mozartsteg/Rudolfskai #> [4] Mozarts Geburtshaus --Café Mozart #> [5] Mozartkugel --Mozartsteg/Imbergstraße #> [6] Mozartkugel --Spirit of Mozart #> [7] Mozartsteg/Imbergstraße--Spirit of Mozart #> + ... omitted several edges wrap_igraph(net, delete_edges, drop) #> # A sfnetwork: 17 nodes and 12 edges #> # #> # A bipartite simple graph with 6 components and spatially explicit edges #> # #> # Dimension: XY #> # Bounding box: xmin: 4548664 ymin: 2747309 xmax: 4549589 ymax: 2748537 #> # Projected CRS: ETRS89-extended / LAEA Europe #> # #> # Edge data: 12 × 4 (active) #> from to geometry length #> [m] #> 1 1 3 (4549504 2747309, 4549589 2747507) 216. #> 2 2 8 (4549003 2747376, 4548994 2747632) 256. #> 3 4 5 (4549387 2747514, 4549491 2747551) 110. #> 4 7 8 (4549064 2747619, 4548994 2747632) 71.1 #> 5 9 10 (4549120 2747654, 4549418 2747723) 305. #> 6 9 11 (4549120 2747654, 4549119 2747790) 136. #> # ℹ 6 more rows #> # #> # Node data: 17 × 5 #> name type website geometry label #> #> 1 Mozartkino cinema https://www.mo… (4549504 2747309) a #> 2 Haus für Mozart theatre NA (4549003 2747376) b #> 3 Mozartsteg/Rudolfskai bus_stop NA (4549589 2747507) c #> # ℹ 14 more rows mst = wrap_igraph(net, mst, weights = edge_attr(net, \"length\")) ggraph(mst, \"sf\") + geom_edge_sf() + geom_node_sf(size = 4) + theme_void() with_graph(net, edge_circuity()) #> [1] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1"},{"path":"https://luukvdmeer.github.io/sfnetworks/articles/sfn01_intro.html","id":"network-analysis-with-tidygraph","dir":"Articles","previous_headings":"","what":"Network analysis with tidygraph","title":"Introduction to sfnetworks","text":"allow performing common network analysis tasks, sfnetworks builds upon tidygraph. Since sfnetwork objects inherit tbl_graph class, analytical functions tidygraph can directly used. lot functions available, tidy wrappers around functions igraph library. complete overview, check tidygraph documentation. important note case spatial networks often makes sense use geographic length edge weight. Since tidygraph know space, never set automatically, explicitly specify every time call function can consider edge weights. Read specifying edge weights vignette Routing spatial networks. large set functions tidygraph dedicated computation quantitative measures nodes, edges, network whole. known centrality measures, define importance node network. names implemented centrality measure functions formatted centrality_*. implemented measure functions names formatted node_* (node measures) edge_* (edge measures) graph_* (network measures). special group measure functions logical measures, return either TRUE FALSE, indicating node, edge network specified type. None functions meant called directly, used inside tidyverse-verbs dplyr::mutate() dplyr::filter(), analyzed network know thus needed input function. tidygraph::with_graph() can used evaluate measure context specific network, outside tidyverse framework. Another set functions tidygraph deals community detection networks. functions group nodes edges based clustering algorithm. names formatted group_*, always return vector group indices, one feature. implemented algorithms try create groups nodes number edges within groups relatively high compared number edges groups, example . note algorithms generally designed account spatial factors, may limited use working spatial networks. Finally, tidygraph introduced new set network analysis functions call morphers. Morphers change structure input graph, example subsetting splitting , combining multiple features one, converting nodes edges vice versa. different struture needed computations, can set temporarily providing morphers subsequently tidygraph::morph() tidygraph::unmorph() verbs. different structure meant last, morpher can provided tidygraph::convert() verb instead. example convert network minimum spanning tree, contains minimum set edges need nodes still connected like .","code":"net = net |> activate(edges) |> mutate(length = edge_length()) net #> # A sfnetwork: 17 nodes and 25 edges #> # #> # A bipartite simple graph with 1 component and spatially explicit edges #> # #> # Dimension: XY #> # Bounding box: xmin: 4548664 ymin: 2747309 xmax: 4549589 ymax: 2748537 #> # Projected CRS: ETRS89-extended / LAEA Europe #> # #> # Edge data: 25 × 4 (active) #> from to geometry length #> [m] #> 1 1 3 (4549504 2747309, 4549589 2747507) 216. #> 2 1 4 (4549504 2747309, 4549387 2747514) 236. #> 3 2 4 (4549003 2747376, 4549387 2747514) 409. #> 4 2 7 (4549003 2747376, 4549064 2747619) 250. #> 5 2 8 (4549003 2747376, 4548994 2747632) 256. #> 6 3 5 (4549589 2747507, 4549491 2747551) 107. #> # ℹ 19 more rows #> # #> # Node data: 17 × 4 #> name type website geometry #> #> 1 Mozartkino cinema https://www.mozartki… (4549504 2747309) #> 2 Haus für Mozart theatre NA (4549003 2747376) #> 3 Mozartsteg/Rudolfskai bus_stop NA (4549589 2747507) #> # ℹ 14 more rows new_net = net |> activate(edges) |> filter(!edge_is_incident(13)) |> activate(nodes) |> mutate(bc = centrality_betweenness(weights = length)) new_net #> # A sfnetwork: 17 nodes and 23 edges #> # #> # A bipartite simple graph with 2 components and spatially explicit edges #> # #> # Dimension: XY #> # Bounding box: xmin: 4548664 ymin: 2747309 xmax: 4549589 ymax: 2748537 #> # Projected CRS: ETRS89-extended / LAEA Europe #> # #> # Node data: 17 × 5 (active) #> name type website geometry bc #> #> 1 Mozartkino cinema https://www.mo… (4549504 2747309) 0 #> 2 Haus für Mozart theatre NA (4549003 2747376) 0 #> 3 Mozartsteg/Rudolfskai bus_stop NA (4549589 2747507) 5 #> 4 Mozart Denkmal artwork NA (4549387 2747514) 21 #> 5 Mozartsteg/Rudolfskai bus_stop NA (4549491 2747551) 22 #> 6 Mozartsteg bridge NA (4549473 2747624) 16 #> # ℹ 11 more rows #> # #> # Edge data: 23 × 4 #> from to geometry length #> [m] #> 1 1 3 (4549504 2747309, 4549589 2747507) 216. #> 2 1 4 (4549504 2747309, 4549387 2747514) 236. #> 3 2 4 (4549003 2747376, 4549387 2747514) 409. #> # ℹ 20 more rows ggraph(new_net, \"sf\") + geom_edge_sf() + geom_node_sf(aes(size = bc)) + theme_void() with_graph(net, centrality_degree()) |> setNames(NULL) #> [1] 2 3 2 4 3 2 3 3 4 4 3 2 2 4 3 3 3 new_net = net |> activate(nodes) |> mutate(group = group_optimal()) ggraph(new_net, \"sf\") + geom_edge_sf() + geom_node_sf(aes(color = as.factor(group)), size = 4) + scale_colour_discrete(\"group\") + theme_void() new_net = net |> convert(to_minimum_spanning_tree, weights = length) ggraph(new_net, \"sf\") + geom_edge_sf() + geom_node_sf(size = 4) + theme_void()"},{"path":"https://luukvdmeer.github.io/sfnetworks/articles/sfn01_intro.html","id":"measures","dir":"Articles","previous_headings":"","what":"Measures","title":"Introduction to sfnetworks","text":"large set functions tidygraph dedicated computation quantitative measures nodes, edges, network whole. known centrality measures, define importance node network. names implemented centrality measure functions formatted centrality_*. implemented measure functions names formatted node_* (node measures) edge_* (edge measures) graph_* (network measures). special group measure functions logical measures, return either TRUE FALSE, indicating node, edge network specified type. None functions meant called directly, used inside tidyverse-verbs dplyr::mutate() dplyr::filter(), analyzed network know thus needed input function. tidygraph::with_graph() can used evaluate measure context specific network, outside tidyverse framework.","code":"new_net = net |> activate(edges) |> filter(!edge_is_incident(13)) |> activate(nodes) |> mutate(bc = centrality_betweenness(weights = length)) new_net #> # A sfnetwork: 17 nodes and 23 edges #> # #> # A bipartite simple graph with 2 components and spatially explicit edges #> # #> # Dimension: XY #> # Bounding box: xmin: 4548664 ymin: 2747309 xmax: 4549589 ymax: 2748537 #> # Projected CRS: ETRS89-extended / LAEA Europe #> # #> # Node data: 17 × 5 (active) #> name type website geometry bc #> #> 1 Mozartkino cinema https://www.mo… (4549504 2747309) 0 #> 2 Haus für Mozart theatre NA (4549003 2747376) 0 #> 3 Mozartsteg/Rudolfskai bus_stop NA (4549589 2747507) 5 #> 4 Mozart Denkmal artwork NA (4549387 2747514) 21 #> 5 Mozartsteg/Rudolfskai bus_stop NA (4549491 2747551) 22 #> 6 Mozartsteg bridge NA (4549473 2747624) 16 #> # ℹ 11 more rows #> # #> # Edge data: 23 × 4 #> from to geometry length #> [m] #> 1 1 3 (4549504 2747309, 4549589 2747507) 216. #> 2 1 4 (4549504 2747309, 4549387 2747514) 236. #> 3 2 4 (4549003 2747376, 4549387 2747514) 409. #> # ℹ 20 more rows ggraph(new_net, \"sf\") + geom_edge_sf() + geom_node_sf(aes(size = bc)) + theme_void() with_graph(net, centrality_degree()) |> setNames(NULL) #> [1] 2 3 2 4 3 2 3 3 4 4 3 2 2 4 3 3 3"},{"path":"https://luukvdmeer.github.io/sfnetworks/articles/sfn01_intro.html","id":"community-detection","dir":"Articles","previous_headings":"","what":"Community detection","title":"Introduction to sfnetworks","text":"Another set functions tidygraph deals community detection networks. functions group nodes edges based clustering algorithm. names formatted group_*, always return vector group indices, one feature. implemented algorithms try create groups nodes number edges within groups relatively high compared number edges groups, example . note algorithms generally designed account spatial factors, may limited use working spatial networks.","code":"new_net = net |> activate(nodes) |> mutate(group = group_optimal()) ggraph(new_net, \"sf\") + geom_edge_sf() + geom_node_sf(aes(color = as.factor(group)), size = 4) + scale_colour_discrete(\"group\") + theme_void()"},{"path":"https://luukvdmeer.github.io/sfnetworks/articles/sfn01_intro.html","id":"morphers","dir":"Articles","previous_headings":"","what":"Morphers","title":"Introduction to sfnetworks","text":"Finally, tidygraph introduced new set network analysis functions call morphers. Morphers change structure input graph, example subsetting splitting , combining multiple features one, converting nodes edges vice versa. different struture needed computations, can set temporarily providing morphers subsequently tidygraph::morph() tidygraph::unmorph() verbs. different structure meant last, morpher can provided tidygraph::convert() verb instead. example convert network minimum spanning tree, contains minimum set edges need nodes still connected like .","code":"new_net = net |> convert(to_minimum_spanning_tree, weights = length) ggraph(new_net, \"sf\") + geom_edge_sf() + geom_node_sf(size = 4) + theme_void()"},{"path":"https://luukvdmeer.github.io/sfnetworks/articles/sfn01_intro.html","id":"spatial-analysis-with-sf","dir":"Articles","previous_headings":"","what":"Spatial analysis with sf","title":"Introduction to sfnetworks","text":"writing methods many spatial analytical functions sf package, sfnetworks allows functions called directly sfnetwork objects, without need conversion. See overview sf functions method sfnetwork objects. complete overview functionalities sf, check sf documentation. One many tasks sf covers specification coordinate reference systems, CRS short, transformation spatial coordinates systems. sfnetwork object nodes edges always CRS, matter elements active retrieve CRS, transform coordinates different CRS. sf also multiple functions implement evaluation spatial predicate. spatial predicate describes spatial relation two geometries. example, point may located within polygon B. example show evaluate node spatial network located within one two given polygons. using spatial predicates, sf offers ability perform spatial joins spatial filters. Spatial joins join information spatial feature features specified spatial relation . Spatial filters keep features specified spatial relation, removes . details spatial joins filters spatial networks, see vignette Spatial joins filters. Finally, sf contains group functions known geometric unary operations. functions change structure individual geometries. usage context spatial networks limited, since many break network structure endpoints edges spatially equal respective nodes. Hence, geometric unary operations change type, shape, position geometries method sfnetwork objects. include sf::st_reverse() reverse edge geometries, sf::st_segmentize() add interior points edge geometries. However, just unsupported tidyverse-verbs, can still apply unsupported geometric unary operations first extracting active element sf object, proceed analysis single table.","code":"st_crs(net)$epsg #> [1] 3035 st_transform(net, 4326) #> # A sfnetwork: 17 nodes and 25 edges #> # #> # A bipartite simple graph with 1 component and spatially explicit edges #> # #> # Dimension: XY #> # Bounding box: xmin: 13.03835 ymin: 47.79698 xmax: 13.05049 ymax: 47.80822 #> # Geodetic CRS: WGS 84 #> # #> # Edge data: 25 × 4 (active) #> from to geometry length #> [m] #> 1 1 3 (13.04925 47.79698, 13.05049 47.79874) 216. #> 2 1 4 (13.04925 47.79698, 13.04781 47.79887) 236. #> 3 2 4 (13.0426 47.79778, 13.04781 47.79887) 409. #> 4 2 7 (13.0426 47.79778, 13.04355 47.79993) 250. #> 5 2 8 (13.0426 47.79778, 13.04263 47.80008) 256. #> 6 3 5 (13.05049 47.79874, 13.04921 47.79917) 107. #> # ℹ 19 more rows #> # #> # Node data: 17 × 4 #> name type website geometry #> #> 1 Mozartkino cinema https://www.mozartki… (13.04925 47.79698) #> 2 Haus für Mozart theatre NA (13.0426 47.79778) #> 3 Mozartsteg/Rudolfskai bus_stop NA (13.05049 47.79874) #> # ℹ 14 more rows polys = mozart |> slice(4, 15) |> st_buffer(325) |> mutate(label = c(\"A\", \"B\")) |> select(label) ggraph(net, \"sf\") + geom_sf(data = polys, linewidth = 1, color = \"orange\") + geom_edge_sf() + geom_node_sf(size = 4) + theme_void() net |> activate(nodes) |> st_within(polys) #> Sparse geometry binary predicate list of length 17, where the predicate #> was `within' #> first 10 elements: #> 1: 1 #> 2: (empty) #> 3: 1 #> 4: 1 #> 5: 1 #> 6: 1 #> 7: (empty) #> 8: (empty) #> 9: 1 #> 10: 1 new_net = net |> activate(nodes) |> st_join(polys, join = st_within) ggraph(new_net, \"sf\") + geom_sf(data = polys, linewidth = 1, color = \"orange\") + geom_edge_sf() + geom_node_sf(aes(color = as.factor(label)), size = 4) + scale_colour_discrete(\"label\") + theme_void() new_net = net |> activate(nodes) |> st_filter(polys, .predicate = st_within) ggraph(new_net, \"sf\") + geom_sf(data = polys, linewidth = 1, color = \"orange\") + geom_edge_sf() + geom_node_sf(size = 4) + theme_void() net |> activate(nodes) |> st_as_sf() |> st_buffer(250) #> Simple feature collection with 17 features and 3 fields #> Attribute-geometry relationships: constant (3) #> Geometry type: POLYGON #> Dimension: XY #> Bounding box: xmin: 4548414 ymin: 2747059 xmax: 4549839 ymax: 2748787 #> Projected CRS: ETRS89-extended / LAEA Europe #> # A tibble: 17 × 4 #> name type website geometry #> * #> 1 Mozartkino cinema https://www.… ((4549754 2747309, 45497… #> 2 Haus für Mozart theatre NA ((4549253 2747376, 45492… #> 3 Mozartsteg/Rudolfskai bus_stop NA ((4549839 2747507, 45498… #> 4 Mozart Denkmal artwork NA ((4549637 2747514, 45496… #> 5 Mozartsteg/Rudolfskai bus_stop NA ((4549741 2747551, 45497… #> 6 Mozartsteg bridge NA ((4549723 2747624, 45497… #> 7 Mozarts Geburtshaus museum http://www.m… ((4549314 2747619, 45493… #> 8 Café Mozart cafe https://www.… ((4549244 2747632, 45492… #> 9 Mozartkugel confectionery NA ((4549370 2747654, 45493… #> 10 Mozartsteg/Imbergstraße bus_stop NA ((4549668 2747723, 45496… #> 11 Spirit of Mozart artwork https://salz… ((4549369 2747790, 45493… #> 12 Mozart-Eine Hommage artwork https://salz… ((4548914 2747868, 45489… #> 13 Mozarts Wohnhaus apartments NA ((4549323 2747916, 45493… #> 14 Universität Mozarteum university NA ((4549309 2748042, 45493… #> 15 Stiftung Mozarteum concert_hall NA ((4549147 2748037, 45491… #> 16 Hotel Mozart hotel http://www.h… ((4549628 2748391, 45496… #> 17 Mozart Studentenheim dormitory NA ((4549234 2748537, 45492…"},{"path":"https://luukvdmeer.github.io/sfnetworks/articles/sfn01_intro.html","id":"coordinate-reference-systems","dir":"Articles","previous_headings":"","what":"Coordinate reference systems","title":"Introduction to sfnetworks","text":"One many tasks sf covers specification coordinate reference systems, CRS short, transformation spatial coordinates systems. sfnetwork object nodes edges always CRS, matter elements active retrieve CRS, transform coordinates different CRS.","code":"st_crs(net)$epsg #> [1] 3035 st_transform(net, 4326) #> # A sfnetwork: 17 nodes and 25 edges #> # #> # A bipartite simple graph with 1 component and spatially explicit edges #> # #> # Dimension: XY #> # Bounding box: xmin: 13.03835 ymin: 47.79698 xmax: 13.05049 ymax: 47.80822 #> # Geodetic CRS: WGS 84 #> # #> # Edge data: 25 × 4 (active) #> from to geometry length #> [m] #> 1 1 3 (13.04925 47.79698, 13.05049 47.79874) 216. #> 2 1 4 (13.04925 47.79698, 13.04781 47.79887) 236. #> 3 2 4 (13.0426 47.79778, 13.04781 47.79887) 409. #> 4 2 7 (13.0426 47.79778, 13.04355 47.79993) 250. #> 5 2 8 (13.0426 47.79778, 13.04263 47.80008) 256. #> 6 3 5 (13.05049 47.79874, 13.04921 47.79917) 107. #> # ℹ 19 more rows #> # #> # Node data: 17 × 4 #> name type website geometry #> #> 1 Mozartkino cinema https://www.mozartki… (13.04925 47.79698) #> 2 Haus für Mozart theatre NA (13.0426 47.79778) #> 3 Mozartsteg/Rudolfskai bus_stop NA (13.05049 47.79874) #> # ℹ 14 more rows"},{"path":"https://luukvdmeer.github.io/sfnetworks/articles/sfn01_intro.html","id":"spatial-predicates","dir":"Articles","previous_headings":"","what":"Spatial predicates","title":"Introduction to sfnetworks","text":"sf also multiple functions implement evaluation spatial predicate. spatial predicate describes spatial relation two geometries. example, point may located within polygon B. example show evaluate node spatial network located within one two given polygons.","code":"polys = mozart |> slice(4, 15) |> st_buffer(325) |> mutate(label = c(\"A\", \"B\")) |> select(label) ggraph(net, \"sf\") + geom_sf(data = polys, linewidth = 1, color = \"orange\") + geom_edge_sf() + geom_node_sf(size = 4) + theme_void() net |> activate(nodes) |> st_within(polys) #> Sparse geometry binary predicate list of length 17, where the predicate #> was `within' #> first 10 elements: #> 1: 1 #> 2: (empty) #> 3: 1 #> 4: 1 #> 5: 1 #> 6: 1 #> 7: (empty) #> 8: (empty) #> 9: 1 #> 10: 1"},{"path":"https://luukvdmeer.github.io/sfnetworks/articles/sfn01_intro.html","id":"spatial-joins-and-filters","dir":"Articles","previous_headings":"","what":"Spatial joins and filters","title":"Introduction to sfnetworks","text":"using spatial predicates, sf offers ability perform spatial joins spatial filters. Spatial joins join information spatial feature features specified spatial relation . Spatial filters keep features specified spatial relation, removes . details spatial joins filters spatial networks, see vignette Spatial joins filters.","code":"new_net = net |> activate(nodes) |> st_join(polys, join = st_within) ggraph(new_net, \"sf\") + geom_sf(data = polys, linewidth = 1, color = \"orange\") + geom_edge_sf() + geom_node_sf(aes(color = as.factor(label)), size = 4) + scale_colour_discrete(\"label\") + theme_void() new_net = net |> activate(nodes) |> st_filter(polys, .predicate = st_within) ggraph(new_net, \"sf\") + geom_sf(data = polys, linewidth = 1, color = \"orange\") + geom_edge_sf() + geom_node_sf(size = 4) + theme_void()"},{"path":"https://luukvdmeer.github.io/sfnetworks/articles/sfn01_intro.html","id":"geometric-unary-operations","dir":"Articles","previous_headings":"","what":"Geometric unary operations","title":"Introduction to sfnetworks","text":"Finally, sf contains group functions known geometric unary operations. functions change structure individual geometries. usage context spatial networks limited, since many break network structure endpoints edges spatially equal respective nodes. Hence, geometric unary operations change type, shape, position geometries method sfnetwork objects. include sf::st_reverse() reverse edge geometries, sf::st_segmentize() add interior points edge geometries. However, just unsupported tidyverse-verbs, can still apply unsupported geometric unary operations first extracting active element sf object, proceed analysis single table.","code":"net |> activate(nodes) |> st_as_sf() |> st_buffer(250) #> Simple feature collection with 17 features and 3 fields #> Attribute-geometry relationships: constant (3) #> Geometry type: POLYGON #> Dimension: XY #> Bounding box: xmin: 4548414 ymin: 2747059 xmax: 4549839 ymax: 2748787 #> Projected CRS: ETRS89-extended / LAEA Europe #> # A tibble: 17 × 4 #> name type website geometry #> * #> 1 Mozartkino cinema https://www.… ((4549754 2747309, 45497… #> 2 Haus für Mozart theatre NA ((4549253 2747376, 45492… #> 3 Mozartsteg/Rudolfskai bus_stop NA ((4549839 2747507, 45498… #> 4 Mozart Denkmal artwork NA ((4549637 2747514, 45496… #> 5 Mozartsteg/Rudolfskai bus_stop NA ((4549741 2747551, 45497… #> 6 Mozartsteg bridge NA ((4549723 2747624, 45497… #> 7 Mozarts Geburtshaus museum http://www.m… ((4549314 2747619, 45493… #> 8 Café Mozart cafe https://www.… ((4549244 2747632, 45492… #> 9 Mozartkugel confectionery NA ((4549370 2747654, 45493… #> 10 Mozartsteg/Imbergstraße bus_stop NA ((4549668 2747723, 45496… #> 11 Spirit of Mozart artwork https://salz… ((4549369 2747790, 45493… #> 12 Mozart-Eine Hommage artwork https://salz… ((4548914 2747868, 45489… #> 13 Mozarts Wohnhaus apartments NA ((4549323 2747916, 45493… #> 14 Universität Mozarteum university NA ((4549309 2748042, 45493… #> 15 Stiftung Mozarteum concert_hall NA ((4549147 2748037, 45491… #> 16 Hotel Mozart hotel http://www.h… ((4549628 2748391, 45496… #> 17 Mozart Studentenheim dormitory NA ((4549234 2748537, 45492…"},{"path":"https://luukvdmeer.github.io/sfnetworks/articles/sfn01_intro.html","id":"spatial-network-specific-additions","dir":"Articles","previous_headings":"","what":"Spatial network specific additions","title":"Introduction to sfnetworks","text":"mentioned, sfnetworks extends functionalities tidygraph sf offering functions specific spatial network analysis, well functions allow smoother integration sf design tidygraph workflows. contradiction tidygraph, functions sfnetworks consider edge weights always use geographic edge length default weight. first family functions sfnetworks names formatted st_network_*, adopting naming conventions sf. functions take spatial network first input implement analysis task involves network set regular spatial simple features (points, lines, polygons). returned object can either set spatial simple features computed network, network spatial features merged , another object (e.g., matrix) result computation relating network spatial features. covers large range use-cases. Examples include drawing isochrone isodistance polygons around nodes, finding geographic shortest paths pairs nodes, computing cost matrices travel nodes, extracting faces network, adding external point data new nodes network. vignettes find details functions. also functions sfnetworks start st_*, end *_network. contradiction st_network_* functions, functions take set spatial features first input, network additional argument. example st_project_on_network, projects points onto network. Shortest path Isodistance polygon Network faces Blended points extension measure functions tidygraph, several spatial measure functions nodes edges found sfnetworks. Just tidygraph, functions named style node_* edge_*, centrality measure, centrality_*. Edge measures can computed include example geographic length edge, azimuth, circuity (.e. ratio geographic length shortest euclidean distance source target node). nodes, example possible compute straightness centrality (.e. average ratio euclidean distance network distance node nodes network). better integrate spatial predicate functions sf design tidygraph, applicable predicates also implemented node edge measure function. functions return TRUE node edge specified spatial relation least one given spatial features, FALSE otherwise. makes easy use predicates directly inside functions dplyr::filter() dplyr::mutate(). extension community detection functions tidygraph, sfnetworks contains group_spatial_dbscan() function find spatial clusters nodes. idea offer multiple spatial clustering algorithms choose , currently one implemented DBSCAN algorithm (require dbscan package installed). algorithm executed network distance matrix nodes, euclidean distance matrix. extension morpher functions tidygraph, many different spatial morpher functions implemented sfnetworks. Just tidygraph, function change structure input network, example subsetting splitting , combining multiple features one, splitting single features. Common examples include subdividing network interior points edge geometries, smoothing pseudo nodes degree 2, contracting multiple nodes one preserving network connectivity. vignettes find details functions. Many morphers used network cleaning operations, described detail vignette Cleaning spatial networks. Smooth network Subdivision smooth network Contracted groups nodes single path Finally, sfnetworks exports kind utility functions make working spatial networks less cumbersome. example finding nearest node nearest edge given spatial feature. overview exported functions package, see function reference. Nearest node Nearest edge","code":"# Find shortest path between node 1 and node 17. path = st_network_paths(net, 1, 17) # Draw an isodistance polygon with 500m threshold around node 13. iso = st_network_iso(net, 13, 500) # Extract the faces of the network. faces = st_network_faces(net) # Blend external points as new nodes into the network. feats = st_sample(st_bbox(mozart), 10) blend = st_network_blend(net, feats) ggraph(net, \"sf\") + geom_edge_sf() + geom_sf(data = path, color = \"orange\", linewidth = 2) + geom_node_sf(size = 4) + geom_sf(data = st_geometry(net, \"nodes\")[c(1, 17)], size = 6) + theme_void() ggraph(net, \"sf\") + geom_sf(data = iso, fill = \"orange\", alpha = 0.7) + geom_edge_sf() + geom_node_sf(size = 4) + geom_sf(data = st_geometry(net, \"nodes\")[13], size = 6) + theme_void() faces_sf = st_sf(id = c(1:length(faces)), geometry = faces) ggraph(net, \"sf\") + geom_sf(data = faces_sf, aes(fill = as.factor(id)), show.legend = FALSE) + geom_edge_sf() + geom_node_sf(size = 4) + theme_void() ggraph(blend, \"sf\") + geom_edge_sf() + geom_node_sf(size = 4) + geom_sf(data = feats, color = \"orange\", size = 4) + geom_sf( data = st_nearest_points(feats, st_combine(st_geometry(blend, \"nodes\"))), color = \"grey\", linetype = 2 ) + theme_void() new_net = net |> activate(edges) |> filter(edge_intersects(polys)) |> mutate(circuity = edge_circuity()) |> activate(nodes) |> mutate( sc = centrality_straightness(), in_poly = node_is_within(polys) ) new_net #> # A sfnetwork: 17 nodes and 21 edges #> # #> # A bipartite simple graph with 1 component and spatially explicit edges #> # #> # Dimension: XY #> # Bounding box: xmin: 4548664 ymin: 2747309 xmax: 4549589 ymax: 2748537 #> # Projected CRS: ETRS89-extended / LAEA Europe #> # #> # Node data: 17 × 6 (active) #> name type website geometry sc in_poly #> #> 1 Mozartkino cinema https:… (4549504 2747309) 0.847 TRUE #> 2 Haus für Mozart theatre NA (4549003 2747376) 0.648 FALSE #> 3 Mozartsteg/Rudolfskai bus_stop NA (4549589 2747507) 0.878 TRUE #> 4 Mozart Denkmal artwork NA (4549387 2747514) 0.850 TRUE #> 5 Mozartsteg/Rudolfskai bus_stop NA (4549491 2747551) 0.874 TRUE #> 6 Mozartsteg bridge NA (4549473 2747624) 0.843 TRUE #> # ℹ 11 more rows #> # #> # Edge data: 21 × 5 #> from to geometry length circuity #> [m] #> 1 1 3 (4549504 2747309, 4549589 2747507) 216. 1 #> 2 1 4 (4549504 2747309, 4549387 2747514) 236. 1 #> 3 2 4 (4549003 2747376, 4549387 2747514) 409. 1 #> # ℹ 18 more rows new_net = net |> activate(nodes) |> mutate(group = group_spatial_dbscan(300)) ggraph(new_net, \"sf\") + geom_edge_sf() + geom_node_sf(aes(color = as.factor(group)), size = 4) + scale_colour_discrete(\"group\") + theme_void() # Smooth nodes of degree 2. smooth = convert(net, to_spatial_smooth) # Subdivide edges at each interior point in the smoothed network. # In this case this is the opposite of smoothing, it adds back the degree 2 nodes. division = convert(smooth, to_spatial_subdivision, all = TRUE) # Contract nodes that are in the same spatial cluster. contraction = net |> activate(nodes) |> mutate(group = group_spatial_dbscan(300)) |> convert(to_spatial_contracted, group) # Subset the graph to only those edges in a shortest path. path = convert(net, to_spatial_shortest_paths, 1, 17) ggraph(smooth, \"sf\") + geom_edge_sf() + geom_node_sf(size = 4) + theme_void() ggraph(division, \"sf\") + geom_edge_sf() + geom_node_sf(size = 4) + theme_void() ggraph(contraction, \"sf\") + geom_edge_sf() + geom_node_sf(size = 4) + theme_void() ggraph(path, \"sf\") + geom_edge_sf() + geom_node_sf(size = 4) + theme_void() p = st_centroid(st_combine(mozart)) nn = nearest_nodes(net, p) nn #> Simple feature collection with 1 feature and 3 fields #> Attribute-geometry relationships: constant (3) #> Geometry type: POINT #> Dimension: XY #> Bounding box: xmin: 4549119 ymin: 2747790 xmax: 4549119 ymax: 2747790 #> Projected CRS: ETRS89-extended / LAEA Europe #> # A tibble: 1 × 4 #> name type website geometry #> #> 1 Spirit of Mozart artwork https://salzburgfoundation… (4549119 2747790) ne = nearest_edges(net, p) ne #> Simple feature collection with 1 feature and 3 fields #> Geometry type: LINESTRING #> Dimension: XY #> Bounding box: xmin: 4549119 ymin: 2747723 xmax: 4549418 ymax: 2747790 #> Projected CRS: ETRS89-extended / LAEA Europe #> # A tibble: 1 × 4 #> from to geometry length #> [m] #> 1 10 11 (4549418 2747723, 4549119 2747790) 306. ggraph(net, \"sf\") + geom_sf(data = p, size = 6, pch = 8) + geom_edge_sf(color = \"grey\") + geom_node_sf(color = \"grey\", size = 4) + geom_sf(data = nn, color = \"orange\", size = 6) + theme_void() ggraph(net, \"sf\") + geom_sf(data = p, size = 6, pch = 8) + geom_edge_sf(color = \"grey\") + geom_sf(data = ne, color = \"orange\", linewidth = 2) + geom_node_sf(color = \"grey\", size = 4) + theme_void()"},{"path":"https://luukvdmeer.github.io/sfnetworks/articles/sfn01_intro.html","id":"relating-networks-and-spatial-simple-features","dir":"Articles","previous_headings":"","what":"Relating networks and spatial simple features","title":"Introduction to sfnetworks","text":"first family functions sfnetworks names formatted st_network_*, adopting naming conventions sf. functions take spatial network first input implement analysis task involves network set regular spatial simple features (points, lines, polygons). returned object can either set spatial simple features computed network, network spatial features merged , another object (e.g., matrix) result computation relating network spatial features. covers large range use-cases. Examples include drawing isochrone isodistance polygons around nodes, finding geographic shortest paths pairs nodes, computing cost matrices travel nodes, extracting faces network, adding external point data new nodes network. vignettes find details functions. also functions sfnetworks start st_*, end *_network. contradiction st_network_* functions, functions take set spatial features first input, network additional argument. example st_project_on_network, projects points onto network. Shortest path Isodistance polygon Network faces Blended points","code":"# Find shortest path between node 1 and node 17. path = st_network_paths(net, 1, 17) # Draw an isodistance polygon with 500m threshold around node 13. iso = st_network_iso(net, 13, 500) # Extract the faces of the network. faces = st_network_faces(net) # Blend external points as new nodes into the network. feats = st_sample(st_bbox(mozart), 10) blend = st_network_blend(net, feats) ggraph(net, \"sf\") + geom_edge_sf() + geom_sf(data = path, color = \"orange\", linewidth = 2) + geom_node_sf(size = 4) + geom_sf(data = st_geometry(net, \"nodes\")[c(1, 17)], size = 6) + theme_void() ggraph(net, \"sf\") + geom_sf(data = iso, fill = \"orange\", alpha = 0.7) + geom_edge_sf() + geom_node_sf(size = 4) + geom_sf(data = st_geometry(net, \"nodes\")[13], size = 6) + theme_void() faces_sf = st_sf(id = c(1:length(faces)), geometry = faces) ggraph(net, \"sf\") + geom_sf(data = faces_sf, aes(fill = as.factor(id)), show.legend = FALSE) + geom_edge_sf() + geom_node_sf(size = 4) + theme_void() ggraph(blend, \"sf\") + geom_edge_sf() + geom_node_sf(size = 4) + geom_sf(data = feats, color = \"orange\", size = 4) + geom_sf( data = st_nearest_points(feats, st_combine(st_geometry(blend, \"nodes\"))), color = \"grey\", linetype = 2 ) + theme_void()"},{"path":"https://luukvdmeer.github.io/sfnetworks/articles/sfn01_intro.html","id":"spatial-measures","dir":"Articles","previous_headings":"","what":"Spatial measures","title":"Introduction to sfnetworks","text":"extension measure functions tidygraph, several spatial measure functions nodes edges found sfnetworks. Just tidygraph, functions named style node_* edge_*, centrality measure, centrality_*. Edge measures can computed include example geographic length edge, azimuth, circuity (.e. ratio geographic length shortest euclidean distance source target node). nodes, example possible compute straightness centrality (.e. average ratio euclidean distance network distance node nodes network). better integrate spatial predicate functions sf design tidygraph, applicable predicates also implemented node edge measure function. functions return TRUE node edge specified spatial relation least one given spatial features, FALSE otherwise. makes easy use predicates directly inside functions dplyr::filter() dplyr::mutate().","code":"new_net = net |> activate(edges) |> filter(edge_intersects(polys)) |> mutate(circuity = edge_circuity()) |> activate(nodes) |> mutate( sc = centrality_straightness(), in_poly = node_is_within(polys) ) new_net #> # A sfnetwork: 17 nodes and 21 edges #> # #> # A bipartite simple graph with 1 component and spatially explicit edges #> # #> # Dimension: XY #> # Bounding box: xmin: 4548664 ymin: 2747309 xmax: 4549589 ymax: 2748537 #> # Projected CRS: ETRS89-extended / LAEA Europe #> # #> # Node data: 17 × 6 (active) #> name type website geometry sc in_poly #> #> 1 Mozartkino cinema https:… (4549504 2747309) 0.847 TRUE #> 2 Haus für Mozart theatre NA (4549003 2747376) 0.648 FALSE #> 3 Mozartsteg/Rudolfskai bus_stop NA (4549589 2747507) 0.878 TRUE #> 4 Mozart Denkmal artwork NA (4549387 2747514) 0.850 TRUE #> 5 Mozartsteg/Rudolfskai bus_stop NA (4549491 2747551) 0.874 TRUE #> 6 Mozartsteg bridge NA (4549473 2747624) 0.843 TRUE #> # ℹ 11 more rows #> # #> # Edge data: 21 × 5 #> from to geometry length circuity #> [m] #> 1 1 3 (4549504 2747309, 4549589 2747507) 216. 1 #> 2 1 4 (4549504 2747309, 4549387 2747514) 236. 1 #> 3 2 4 (4549003 2747376, 4549387 2747514) 409. 1 #> # ℹ 18 more rows"},{"path":"https://luukvdmeer.github.io/sfnetworks/articles/sfn01_intro.html","id":"spatial-clustering","dir":"Articles","previous_headings":"","what":"Spatial clustering","title":"Introduction to sfnetworks","text":"extension community detection functions tidygraph, sfnetworks contains group_spatial_dbscan() function find spatial clusters nodes. idea offer multiple spatial clustering algorithms choose , currently one implemented DBSCAN algorithm (require dbscan package installed). algorithm executed network distance matrix nodes, euclidean distance matrix.","code":"new_net = net |> activate(nodes) |> mutate(group = group_spatial_dbscan(300)) ggraph(new_net, \"sf\") + geom_edge_sf() + geom_node_sf(aes(color = as.factor(group)), size = 4) + scale_colour_discrete(\"group\") + theme_void()"},{"path":"https://luukvdmeer.github.io/sfnetworks/articles/sfn01_intro.html","id":"spatial-morphers","dir":"Articles","previous_headings":"","what":"Spatial morphers","title":"Introduction to sfnetworks","text":"extension morpher functions tidygraph, many different spatial morpher functions implemented sfnetworks. Just tidygraph, function change structure input network, example subsetting splitting , combining multiple features one, splitting single features. Common examples include subdividing network interior points edge geometries, smoothing pseudo nodes degree 2, contracting multiple nodes one preserving network connectivity. vignettes find details functions. Many morphers used network cleaning operations, described detail vignette Cleaning spatial networks. Smooth network Subdivision smooth network Contracted groups nodes single path","code":"# Smooth nodes of degree 2. smooth = convert(net, to_spatial_smooth) # Subdivide edges at each interior point in the smoothed network. # In this case this is the opposite of smoothing, it adds back the degree 2 nodes. division = convert(smooth, to_spatial_subdivision, all = TRUE) # Contract nodes that are in the same spatial cluster. contraction = net |> activate(nodes) |> mutate(group = group_spatial_dbscan(300)) |> convert(to_spatial_contracted, group) # Subset the graph to only those edges in a shortest path. path = convert(net, to_spatial_shortest_paths, 1, 17) ggraph(smooth, \"sf\") + geom_edge_sf() + geom_node_sf(size = 4) + theme_void() ggraph(division, \"sf\") + geom_edge_sf() + geom_node_sf(size = 4) + theme_void() ggraph(contraction, \"sf\") + geom_edge_sf() + geom_node_sf(size = 4) + theme_void() ggraph(path, \"sf\") + geom_edge_sf() + geom_node_sf(size = 4) + theme_void()"},{"path":"https://luukvdmeer.github.io/sfnetworks/articles/sfn01_intro.html","id":"utilities","dir":"Articles","previous_headings":"","what":"Utilities","title":"Introduction to sfnetworks","text":"Finally, sfnetworks exports kind utility functions make working spatial networks less cumbersome. example finding nearest node nearest edge given spatial feature. overview exported functions package, see function reference. Nearest node Nearest edge","code":"p = st_centroid(st_combine(mozart)) nn = nearest_nodes(net, p) nn #> Simple feature collection with 1 feature and 3 fields #> Attribute-geometry relationships: constant (3) #> Geometry type: POINT #> Dimension: XY #> Bounding box: xmin: 4549119 ymin: 2747790 xmax: 4549119 ymax: 2747790 #> Projected CRS: ETRS89-extended / LAEA Europe #> # A tibble: 1 × 4 #> name type website geometry #> #> 1 Spirit of Mozart artwork https://salzburgfoundation… (4549119 2747790) ne = nearest_edges(net, p) ne #> Simple feature collection with 1 feature and 3 fields #> Geometry type: LINESTRING #> Dimension: XY #> Bounding box: xmin: 4549119 ymin: 2747723 xmax: 4549418 ymax: 2747790 #> Projected CRS: ETRS89-extended / LAEA Europe #> # A tibble: 1 × 4 #> from to geometry length #> [m] #> 1 10 11 (4549418 2747723, 4549119 2747790) 306. ggraph(net, \"sf\") + geom_sf(data = p, size = 6, pch = 8) + geom_edge_sf(color = \"grey\") + geom_node_sf(color = \"grey\", size = 4) + geom_sf(data = nn, color = \"orange\", size = 6) + theme_void() ggraph(net, \"sf\") + geom_sf(data = p, size = 6, pch = 8) + geom_edge_sf(color = \"grey\") + geom_sf(data = ne, color = \"orange\", linewidth = 2) + geom_node_sf(color = \"grey\", size = 4) + theme_void()"},{"path":"https://luukvdmeer.github.io/sfnetworks/articles/sfn01_intro.html","id":"non-tidyverse-workflows","dir":"Articles","previous_headings":"","what":"Non-tidyverse workflows","title":"Introduction to sfnetworks","text":"Also fan tidyverse style data analysis, sfnetworks can . Since sfnetwork objects inherit igraph class, can apply functions large igraph package . means, example, instead using dplyr::mutate() dplyr::filter(), proceed follows (note igraph, term vertex used instead node). can see, returns igraph object instead sfnetwork object. preserve class, can use wrap_igraph() function sfnetworks igraph function accepts network first input returns another network. function check returned network still spatial. spatial measure functions can evaluated outside tidygraph framework using with_graph(), works similar base R’s () function. spatial morpher functions implement larger workflow internal workers exported, meaning can called directly outside tidygraph::morph() tidygraph::convert() verbs. morphers easy replicate using sf sfnetworks functions directly.","code":"# Mutate. vertex_attr(net, \"label\") = letters[1:vcount(net)] # Filter. drop = which(!sample(c(TRUE, FALSE), ecount(net), replace = TRUE)) new_net = delete_edges(net, drop) new_net #> IGRAPH f481e4e UN-B 17 12 -- #> + attr: name (v/c), type (v/c), website (v/c), geometry (v/x), label #> | (v/c), geometry (e/x), length (e/n) #> + edges from f481e4e (vertex names): #> [1] Mozartkino --Mozartsteg/Rudolfskai #> [2] Haus für Mozart --Café Mozart #> [3] Mozart Denkmal --Mozartsteg/Rudolfskai #> [4] Mozarts Geburtshaus --Café Mozart #> [5] Mozartkugel --Mozartsteg/Imbergstraße #> [6] Mozartkugel --Spirit of Mozart #> [7] Mozartsteg/Imbergstraße--Spirit of Mozart #> + ... omitted several edges wrap_igraph(net, delete_edges, drop) #> # A sfnetwork: 17 nodes and 12 edges #> # #> # A bipartite simple graph with 6 components and spatially explicit edges #> # #> # Dimension: XY #> # Bounding box: xmin: 4548664 ymin: 2747309 xmax: 4549589 ymax: 2748537 #> # Projected CRS: ETRS89-extended / LAEA Europe #> # #> # Edge data: 12 × 4 (active) #> from to geometry length #> [m] #> 1 1 3 (4549504 2747309, 4549589 2747507) 216. #> 2 2 8 (4549003 2747376, 4548994 2747632) 256. #> 3 4 5 (4549387 2747514, 4549491 2747551) 110. #> 4 7 8 (4549064 2747619, 4548994 2747632) 71.1 #> 5 9 10 (4549120 2747654, 4549418 2747723) 305. #> 6 9 11 (4549120 2747654, 4549119 2747790) 136. #> # ℹ 6 more rows #> # #> # Node data: 17 × 5 #> name type website geometry label #> #> 1 Mozartkino cinema https://www.mo… (4549504 2747309) a #> 2 Haus für Mozart theatre NA (4549003 2747376) b #> 3 Mozartsteg/Rudolfskai bus_stop NA (4549589 2747507) c #> # ℹ 14 more rows mst = wrap_igraph(net, mst, weights = edge_attr(net, \"length\")) ggraph(mst, \"sf\") + geom_edge_sf() + geom_node_sf(size = 4) + theme_void() with_graph(net, edge_circuity()) #> [1] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1"},{"path":"https://luukvdmeer.github.io/sfnetworks/articles/sfn01_intro.html","id":"visualizing-spatial-networks","dir":"Articles","previous_headings":"","what":"Visualizing spatial networks","title":"Introduction to sfnetworks","text":"quickly visualize network can use plot() method sfnetwork objects. use sf plot geometries nodes edges one view. Using regular arguments plot(), can change style plot whole. Arguments node_args edge_args added can also provide style settings nodes edges separately, list-format. Default settings Custom settings Custom settings advanced visualizations, recommend use ggraph. extension {ggplot} network data works seamlessly tbl_graph data structures. fact, tidygraph initially developed idea provide suitable data structure ggraph visualizations. now also native support sfnetworks sf layout ggraph::geom_node_sf() ggraph::geom_edge_sf() geoms aware spatial nature data. Edges can also plotted without spatial embedding, using one many geoms offerend ggraph. plot additional spatial layers networks, can simply use ggplot::geom_sf(). details, check ggraph documentation. Default settings Custom settings Custom settings Additional layers want create Leaflet-based interactive maps, take look packages mapview tmap. well integrated sf, can extract nodes edges network, plot two separate layers.","code":"plot(mst) plot(mst, col = \"orange\", pch = 8, cex = 4) plot( mst, node_args = list(col = \"orange\", cex = 3), edge_args = list(col = \"grey\", lwd = 2) ) ggraph(mst, \"sf\") + geom_edge_sf() + geom_node_sf() + theme_void() ggraph(mst, \"sf\") + geom_edge_sf() + geom_node_sf(aes(color = as.factor(type)), size = 4) + scale_color_discrete(\"type\") + theme_void() ggraph(mst, \"sf\") + geom_edge_fan(aes(alpha = after_stat(index)), show.legend = FALSE) + geom_node_sf(aes(size = centrality_degree()), color = \"orange\") + theme_void() ggraph(mst, \"sf\") + geom_edge_sf(color = \"grey\") + geom_node_sf(color = \"orange\", size = 4) + geom_sf( data = st_buffer(st_centroid(st_combine(mozart)), 300), fill = \"skyblue\", alpha = 0.5, linewidth = 0.8 ) + theme_void()"},{"path":"https://luukvdmeer.github.io/sfnetworks/articles/sfn01_intro.html","id":"learning-more","dir":"Articles","previous_headings":"","what":"Learning more","title":"Introduction to sfnetworks","text":"vignette provided introduction sfnetworks. documentation contains several vignettes dive detail: Creating representing spatial networks Cleaning spatial networks Spatial joins filters Routing spatial networks","code":""},{"path":"https://luukvdmeer.github.io/sfnetworks/articles/sfn02_create_represent.html","id":"the-sfnetwork-class","dir":"Articles","previous_headings":"","what":"The sfnetwork class","title":"Creating and representing spatial networks","text":"Spatial networks sfnetworks represented objects class sfnetwork. objects inherit tbl_graph class tidygraph, turn inherit igraph class igraph. means core designed store graph structures. However, thanks design tidygraph, look like collection two flat tables: one nodes, one edges. documentation tidygraph, design choice explained follows. Relational data meaningful way encoded single tidy data frame. hand, node edge data fits well within tidy concept node edge , sense, single observation. Thus, close approximation tidyness relational data two tidy data frames, one describing node data one describing edge data. Since sfnetwork class inherits tbl_graph class, shares philosophy. However, extends domain geospatial data analysis, observation location geographical space. , brings sf game. object class sf stores geographical coordinates observation standardized format geometry list-column, coordinate reference system (CRS) associated . Thus, sfnetworks, re-formulate last sentence paragraph following. close approximation tidyness relational geospatial data two sf objects, one describing node data one describing edge data. Obviously network just list two distinct elements. Nodes edges related . first two columns edges table always named contain integer indices source target node edge. integer indices correspond rownumbers nodes table. , nodes filtered, order changes, indices updated. geometries nodes edges also match. sfnetworks, following requirements specified valid geospatial network: Nodes geometries type POINT. Edges geometries type LINESTRING. endpoints edge geometries spatially equal corresponding node geometries. Nodes edge geometries coordinate reference system coordinate precision. need make note . geospatial network, nodes always coordinates geographic space, thus, can always described sf object. edges, however, can also described indices nodes ends. still makes geospatial, connect two specific points space, spatial information explicitly attached . representations can useful. geolocated social networks, example, often explicit spatial embedding edges. road networks, however, edges usually straight lines, geometries stored explicitly. sfnetworks variants supported: edges can described sf object geometries, also regular tibble without geometry column. refer spatially explicit edges spatially implicit edges, respectively. documentation, however, focus first type. figure summarizes structure sfnetwork objects. Just like tbl_graph objects, always one element (nodes edges) sfnetwork object active. means element main target analysis. default, nodes active element creating network. active element can changed using activate() verb, also change order elements printed. practice, looks follows. Note create network set spatial lines, creating nodes endpoints. See section Creating sfnetwork objects many examples create spatial network. Spatially explicit edges Spatially implicit edges sfnetwork objects possible represent networks directed edges, undirected edges. also possible mimic mixed representations edge types exist. default instance sfnetwork class initialized directed network. means edge can traveled source node target node, vice versa. case, geometry edge always matches direction, startpoint line location source node, endpoint line location target node. sfnetwork data structure also supports undirected networks. networks edge can traveled directions. Since clear source target, node lowest index referenced column, node highest index column. linestring geometry, however, remains unchanged. , undirected networks specified source node may always correspond startpoint edge geometry, instead endpoint. behavior ordering indices comes igraph might confusing, remember undirected networks terms meaning can thus used interchangeably. computation really need edge geometries match specified node indices, can use utility function make_edges_follow_indices(). function reverse edge geometries needed. sfnetworks native support represent mixed networks, .e. networks edges can traveled ways, others one way. However, type networks quite common applications spatial network analysis. example, road networks streets oneway streets. creating directed network, duplicating reversing edges undirected, can mimic mixed network structure. morpher to_spatial_mixed() exactly . Since network cleaning functions work well duplicated reversed edges, usually good idea first create directed network, clean , mimic mixed representation. makes sfnetwork objects different tbl_graph objects nodes (optionally) edges geometries. geometries stored geometry list-column, following design sf. also means just sf, columns “sticky”, survive column subsetting operations. Like sf, can always extract geometries active network element using sf::st_geometry(). shortcuts st_geometry(x, \"nodes\") st_geometry(net, \"edges\") can used extract geometries network element, regardless active . way around, can also replace geometries using setter function sf::set_set_geometry() (alternatively: st_geometry(x) = new). New node geometries required geometry type POINT, new edge geometries geometry type LINESTRING. preserve valid spatial network structure, following done: replacing node geometries, endpoints edge geometries replaced well match new node geometries. replacing edge geometries, endpoints geometries added new nodes network whenever don’t equal original location. original nodes remain network even now isolated. Original network New network can drop geometries using sf::st_drop_geometry() (alternatively: st_geometry(x) = NULL). already shown previous section, dropping edge geometries still return sfnetwork object, now spatially implicit instead spatially explicit edges. Dropping node geometries, however, return tbl_graph. area geometries occupy bounded bounding box. can use sf::st_bbox() compute bounding box active element sfnetwork object. compute bounding box full network, use st_network_bbox(). cases, network bounding box may different bounding box nodes . Element bounding boxes Network bounding box coordinates geometries always expressed specified coordinate reference system (CRS). sfnetwork object, CRS node edge geometries required equal. can extract CRS using sf::st_crs(). transform coordinates different CRS, use sf::st_transform(), specifying example EPSG code new CRS (ways specifying possible well, see documentation sf). Geometries also coordinate precision associated . precision round coordinate values, applied spatial operations. Just CRS, nodes edges sfnetwork object required precision. can extract precision using sf::st_precision(), set using sf::st_set_precision(). Precision values specified scale factor. example, specify 3 decimal places precision, use scale factor 1000. precision specified, defaults machine precision. However, sfnetworks, functions assess spatial equality nodes use default precision 1e12 (.e. 12 decimal places) speed processing. Thanks sf, also possible explicitly specify attribute-geometry relations. define attribute column attribute constant, aggregate, identity. See information. can get set attribute-geometry relations active network element function sf::st_agr(). setter, can also use pipe-friendly version sf::st_set_agr(). Note columns really attributes edges seen network analysis perspective, included attribute-geometry relation specification ensure smooth interaction sf.","code":"# Spatially explicit edges. net = as_sfnetwork(roxel) net #> # A sfnetwork: 987 nodes and 1215 edges #> # #> # A directed multigraph with 9 components and spatially explicit edges #> # #> # Dimension: XY #> # Bounding box: xmin: 7.522595 ymin: 51.94151 xmax: 7.546705 ymax: 51.96119 #> # Geodetic CRS: WGS 84 #> # #> # Node data: 987 × 1 (active) #> geometry #> #> 1 (7.538109 51.95286) #> 2 (7.537867 51.95282) #> 3 (7.537815 51.95867) #> 4 (7.537015 51.95848) #> 5 (7.533441 51.95578) #> 6 (7.533415 51.95561) #> # ℹ 981 more rows #> # #> # Edge data: 1,215 × 5 #> from to name type geometry #> #> 1 1 2 Hagemanns Kämpken residential (7.538109 51.95286, 7.537867 51.95… #> 2 3 4 Stiegkamp residential (7.537815 51.95867, 7.537015 51.95… #> 3 5 6 Havixbecker Straße residential (7.533441 51.95578, 7.533467 51.95… #> # ℹ 1,212 more rows # Make edges spatially implicit. inet = net |> activate(edges) |> st_drop_geometry() inet #> # A sfnetwork: 987 nodes and 1215 edges #> # #> # A directed multigraph with 9 components and spatially implicit edges #> # #> # Dimension: XY #> # Bounding box: xmin: 7.522595 ymin: 51.94151 xmax: 7.546705 ymax: 51.96119 #> # Geodetic CRS: WGS 84 #> # #> # Edge data: 1,215 × 4 (active) #> from to name type #> #> 1 1 2 Hagemanns Kämpken residential #> 2 3 4 Stiegkamp residential #> 3 5 6 Havixbecker Straße residential #> 4 7 8 Holzschuhmacherweg residential #> 5 9 10 Annette-von-Droste-Hülshoff-Straße secondary #> 6 11 12 NA footway #> # ℹ 1,209 more rows #> # #> # Node data: 987 × 1 #> geometry #> #> 1 (7.538109 51.95286) #> 2 (7.537867 51.95282) #> 3 (7.537815 51.95867) #> # ℹ 984 more rows ggraph(net, \"sf\") + geom_edge_sf() + geom_node_sf() + theme_void() ggraph(inet, \"sf\") + geom_edge_link(linetype = 2) + geom_node_sf() + theme_void() as_sfnetwork(roxel, directed = FALSE) #> # A sfnetwork: 987 nodes and 1215 edges #> # #> # An undirected multigraph with 9 components and spatially explicit edges #> # #> # Dimension: XY #> # Bounding box: xmin: 7.522595 ymin: 51.94151 xmax: 7.546705 ymax: 51.96119 #> # Geodetic CRS: WGS 84 #> # #> # Node data: 987 × 1 (active) #> geometry #> #> 1 (7.538109 51.95286) #> 2 (7.537867 51.95282) #> 3 (7.537815 51.95867) #> 4 (7.537015 51.95848) #> 5 (7.533441 51.95578) #> 6 (7.533415 51.95561) #> # ℹ 981 more rows #> # #> # Edge data: 1,215 × 5 #> from to name type geometry #> #> 1 1 2 Hagemanns Kämpken residential (7.538109 51.95286, 7.537867 51.95… #> 2 3 4 Stiegkamp residential (7.537815 51.95867, 7.537015 51.95… #> 3 5 6 Havixbecker Straße residential (7.533441 51.95578, 7.533467 51.95… #> # ℹ 1,212 more rows # First we mark some streets as oneway. streets = roxel |> mutate(oneway = sample(c(TRUE, FALSE), n(), replace = TRUE, prob = c(0.8, 0.2))) # Check the distribution of oneway vs twoway streets. streets |> st_drop_geometry() |> count(oneway) #> # A tibble: 2 × 2 #> oneway n #> #> 1 FALSE 240 #> 2 TRUE 975 # Create a directed network. dnet = as_sfnetwork(streets) # Check the number of edges in the directed network. # This equals the total number of streets. n_edges(dnet) #> [1] 1215 # Convert it into a mixed network. # Oneway streets remain directed. # Twoway streets are duplicated and reversed. mnet = dnet |> convert(to_spatial_mixed, directed = oneway) # Check number of edges in the mixed network. # This equals the number of oneway streets ... # ... plus twice the number of twoway streets. n_edges(mnet) #> [1] 1455 net |> activate(edges) |> st_geometry() #> Geometry set for 1215 features #> Geometry type: LINESTRING #> Dimension: XY #> Bounding box: xmin: 7.522595 ymin: 51.94151 xmax: 7.546705 ymax: 51.96119 #> Geodetic CRS: WGS 84 #> First 5 geometries: #> LINESTRING (7.538109 51.95286, 7.537867 51.95282) #> LINESTRING (7.537815 51.95867, 7.537015 51.95848) #> LINESTRING (7.533441 51.95578, 7.533467 51.9557... #> LINESTRING (7.525977 51.95283, 7.526581 51.95293) #> LINESTRING (7.532301 51.95559, 7.532214 51.9557... orig_net = as_sfnetwork(mozart, \"gabriel\") orig_nodes = st_geometry(orig_net, \"nodes\") new_nodes = st_jitter(orig_nodes, 250) new_net = orig_net |> st_set_geometry(new_nodes) ggraph(orig_net, \"sf\") + geom_sf(data = new_nodes, color = \"orange\") + geom_edge_sf() + geom_node_sf(color = \"darkgrey\", size = 4) + theme_void() ggraph(new_net, \"sf\") + geom_sf(data = orig_nodes, color = \"darkgrey\") + geom_edge_sf() + geom_node_sf(color = \"orange\", size = 4) + theme_void() net |> activate(nodes) |> st_drop_geometry() #> # A tbl_graph: 987 nodes and 1215 edges #> # #> # A directed multigraph with 9 components #> # #> # Node Data: 987 × 0 (active) #> # #> # Edge Data: 1,215 × 5 #> from to name type geometry #> #> 1 1 2 Hagemanns Kämpken residential (7.538109 51.95286, 7.537867 51.95… #> 2 3 4 Stiegkamp residential (7.537815 51.95867, 7.537015 51.95… #> 3 5 6 Havixbecker Straße residential (7.533441 51.95578, 7.533467 51.95… #> # ℹ 1,212 more rows p1 = st_point(c(1, 0)) p2 = st_point(c(0, 0.5)) p3 = st_point(c(1, 1)) p4 = st_point(c(2, 0.5)) nodes = st_sf(geometry = c(st_sfc(p1), st_sfc(p3), st_sfc(p4))) edges = st_sf(geometry = st_sfc(st_linestring(c(p1, p2, p3)))) edges$from = 1 edges$to = 2 G = sfnetwork(nodes, edges) node_bbox = G |> st_bbox() |> st_as_sfc() edge_bbox = G |> activate(edges) |> st_bbox() |> st_as_sfc() net_bbox = G |> st_network_bbox() |> st_as_sfc() ggraph(G, \"sf\") + geom_sf( data = node_bbox, color = \"#F8766D\", fill = NA, linewidth = 1.5, linetype = 4 ) + geom_sf( data = edge_bbox, color = \"#619CFF\", fill = NA, linewidth = 1.5, linetype = 4 ) + geom_edge_sf() + geom_node_sf(size = 4) + theme_void() ggraph(G, \"sf\") + geom_sf( data = net_bbox, color = \"orange\", fill = NA, linewidth = 1.5, linetype = 4 ) + geom_edge_sf() + geom_node_sf(size = 4) + theme_void() st_transform(net, 3035) #> # A sfnetwork: 987 nodes and 1215 edges #> # #> # A directed multigraph with 9 components and spatially explicit edges #> # #> # Dimension: XY #> # Bounding box: xmin: 4150707 ymin: 3206375 xmax: 4152366 ymax: 3208564 #> # Projected CRS: ETRS89-extended / LAEA Europe #> # #> # Node data: 987 × 1 (active) #> geometry #> #> 1 (4151782 3207612) #> 2 (4151765 3207609) #> 3 (4151784 3208259) #> 4 (4151728 3208240) #> 5 (4151472 3207948) #> 6 (4151470 3207929) #> # ℹ 981 more rows #> # #> # Edge data: 1,215 × 5 #> from to name type geometry #> #> 1 1 2 Hagemanns Kämpken residential (4151782 3207612, 4151765 3207609) #> 2 3 4 Stiegkamp residential (4151784 3208259, 4151728 3208240) #> 3 5 6 Havixbecker Straße residential (4151472 3207948, 4151474 3207941,… #> # ℹ 1,212 more rows # With unspecified precision, no node is equal to another node. any(lengths(st_equals(net)) > 1) #> [1] FALSE # With an extremely low precision, all nodes are equal to each other. all(lengths(st_equals(st_set_precision(net, 1))) == n_nodes(net)) #> [1] TRUE net |> activate(edges) |> st_agr() #> from to name type #> constant constant #> Levels: constant aggregate identity net |> activate(edges) |> st_set_agr(c(type = \"aggregate\")) |> st_agr() #> from to name type #> constant aggregate #> Levels: constant aggregate identity"},{"path":"https://luukvdmeer.github.io/sfnetworks/articles/sfn02_create_represent.html","id":"structure","dir":"Articles","previous_headings":"","what":"Structure","title":"Creating and representing spatial networks","text":"Obviously network just list two distinct elements. Nodes edges related . first two columns edges table always named contain integer indices source target node edge. integer indices correspond rownumbers nodes table. , nodes filtered, order changes, indices updated. geometries nodes edges also match. sfnetworks, following requirements specified valid geospatial network: Nodes geometries type POINT. Edges geometries type LINESTRING. endpoints edge geometries spatially equal corresponding node geometries. Nodes edge geometries coordinate reference system coordinate precision. need make note . geospatial network, nodes always coordinates geographic space, thus, can always described sf object. edges, however, can also described indices nodes ends. still makes geospatial, connect two specific points space, spatial information explicitly attached . representations can useful. geolocated social networks, example, often explicit spatial embedding edges. road networks, however, edges usually straight lines, geometries stored explicitly. sfnetworks variants supported: edges can described sf object geometries, also regular tibble without geometry column. refer spatially explicit edges spatially implicit edges, respectively. documentation, however, focus first type. figure summarizes structure sfnetwork objects. Just like tbl_graph objects, always one element (nodes edges) sfnetwork object active. means element main target analysis. default, nodes active element creating network. active element can changed using activate() verb, also change order elements printed. practice, looks follows. Note create network set spatial lines, creating nodes endpoints. See section Creating sfnetwork objects many examples create spatial network. Spatially explicit edges Spatially implicit edges","code":"# Spatially explicit edges. net = as_sfnetwork(roxel) net #> # A sfnetwork: 987 nodes and 1215 edges #> # #> # A directed multigraph with 9 components and spatially explicit edges #> # #> # Dimension: XY #> # Bounding box: xmin: 7.522595 ymin: 51.94151 xmax: 7.546705 ymax: 51.96119 #> # Geodetic CRS: WGS 84 #> # #> # Node data: 987 × 1 (active) #> geometry #> #> 1 (7.538109 51.95286) #> 2 (7.537867 51.95282) #> 3 (7.537815 51.95867) #> 4 (7.537015 51.95848) #> 5 (7.533441 51.95578) #> 6 (7.533415 51.95561) #> # ℹ 981 more rows #> # #> # Edge data: 1,215 × 5 #> from to name type geometry #> #> 1 1 2 Hagemanns Kämpken residential (7.538109 51.95286, 7.537867 51.95… #> 2 3 4 Stiegkamp residential (7.537815 51.95867, 7.537015 51.95… #> 3 5 6 Havixbecker Straße residential (7.533441 51.95578, 7.533467 51.95… #> # ℹ 1,212 more rows # Make edges spatially implicit. inet = net |> activate(edges) |> st_drop_geometry() inet #> # A sfnetwork: 987 nodes and 1215 edges #> # #> # A directed multigraph with 9 components and spatially implicit edges #> # #> # Dimension: XY #> # Bounding box: xmin: 7.522595 ymin: 51.94151 xmax: 7.546705 ymax: 51.96119 #> # Geodetic CRS: WGS 84 #> # #> # Edge data: 1,215 × 4 (active) #> from to name type #> #> 1 1 2 Hagemanns Kämpken residential #> 2 3 4 Stiegkamp residential #> 3 5 6 Havixbecker Straße residential #> 4 7 8 Holzschuhmacherweg residential #> 5 9 10 Annette-von-Droste-Hülshoff-Straße secondary #> 6 11 12 NA footway #> # ℹ 1,209 more rows #> # #> # Node data: 987 × 1 #> geometry #> #> 1 (7.538109 51.95286) #> 2 (7.537867 51.95282) #> 3 (7.537815 51.95867) #> # ℹ 984 more rows ggraph(net, \"sf\") + geom_edge_sf() + geom_node_sf() + theme_void() ggraph(inet, \"sf\") + geom_edge_link(linetype = 2) + geom_node_sf() + theme_void()"},{"path":"https://luukvdmeer.github.io/sfnetworks/articles/sfn02_create_represent.html","id":"directionality","dir":"Articles","previous_headings":"","what":"Directionality","title":"Creating and representing spatial networks","text":"sfnetwork objects possible represent networks directed edges, undirected edges. also possible mimic mixed representations edge types exist. default instance sfnetwork class initialized directed network. means edge can traveled source node target node, vice versa. case, geometry edge always matches direction, startpoint line location source node, endpoint line location target node. sfnetwork data structure also supports undirected networks. networks edge can traveled directions. Since clear source target, node lowest index referenced column, node highest index column. linestring geometry, however, remains unchanged. , undirected networks specified source node may always correspond startpoint edge geometry, instead endpoint. behavior ordering indices comes igraph might confusing, remember undirected networks terms meaning can thus used interchangeably. computation really need edge geometries match specified node indices, can use utility function make_edges_follow_indices(). function reverse edge geometries needed. sfnetworks native support represent mixed networks, .e. networks edges can traveled ways, others one way. However, type networks quite common applications spatial network analysis. example, road networks streets oneway streets. creating directed network, duplicating reversing edges undirected, can mimic mixed network structure. morpher to_spatial_mixed() exactly . Since network cleaning functions work well duplicated reversed edges, usually good idea first create directed network, clean , mimic mixed representation.","code":"as_sfnetwork(roxel, directed = FALSE) #> # A sfnetwork: 987 nodes and 1215 edges #> # #> # An undirected multigraph with 9 components and spatially explicit edges #> # #> # Dimension: XY #> # Bounding box: xmin: 7.522595 ymin: 51.94151 xmax: 7.546705 ymax: 51.96119 #> # Geodetic CRS: WGS 84 #> # #> # Node data: 987 × 1 (active) #> geometry #> #> 1 (7.538109 51.95286) #> 2 (7.537867 51.95282) #> 3 (7.537815 51.95867) #> 4 (7.537015 51.95848) #> 5 (7.533441 51.95578) #> 6 (7.533415 51.95561) #> # ℹ 981 more rows #> # #> # Edge data: 1,215 × 5 #> from to name type geometry #> #> 1 1 2 Hagemanns Kämpken residential (7.538109 51.95286, 7.537867 51.95… #> 2 3 4 Stiegkamp residential (7.537815 51.95867, 7.537015 51.95… #> 3 5 6 Havixbecker Straße residential (7.533441 51.95578, 7.533467 51.95… #> # ℹ 1,212 more rows # First we mark some streets as oneway. streets = roxel |> mutate(oneway = sample(c(TRUE, FALSE), n(), replace = TRUE, prob = c(0.8, 0.2))) # Check the distribution of oneway vs twoway streets. streets |> st_drop_geometry() |> count(oneway) #> # A tibble: 2 × 2 #> oneway n #> #> 1 FALSE 240 #> 2 TRUE 975 # Create a directed network. dnet = as_sfnetwork(streets) # Check the number of edges in the directed network. # This equals the total number of streets. n_edges(dnet) #> [1] 1215 # Convert it into a mixed network. # Oneway streets remain directed. # Twoway streets are duplicated and reversed. mnet = dnet |> convert(to_spatial_mixed, directed = oneway) # Check number of edges in the mixed network. # This equals the number of oneway streets ... # ... plus twice the number of twoway streets. n_edges(mnet) #> [1] 1455"},{"path":"https://luukvdmeer.github.io/sfnetworks/articles/sfn02_create_represent.html","id":"directed-networks","dir":"Articles","previous_headings":"","what":"Directed networks","title":"Creating and representing spatial networks","text":"default instance sfnetwork class initialized directed network. means edge can traveled source node target node, vice versa. case, geometry edge always matches direction, startpoint line location source node, endpoint line location target node.","code":""},{"path":"https://luukvdmeer.github.io/sfnetworks/articles/sfn02_create_represent.html","id":"undirected-networks","dir":"Articles","previous_headings":"","what":"Undirected networks","title":"Creating and representing spatial networks","text":"sfnetwork data structure also supports undirected networks. networks edge can traveled directions. Since clear source target, node lowest index referenced column, node highest index column. linestring geometry, however, remains unchanged. , undirected networks specified source node may always correspond startpoint edge geometry, instead endpoint. behavior ordering indices comes igraph might confusing, remember undirected networks terms meaning can thus used interchangeably. computation really need edge geometries match specified node indices, can use utility function make_edges_follow_indices(). function reverse edge geometries needed.","code":"as_sfnetwork(roxel, directed = FALSE) #> # A sfnetwork: 987 nodes and 1215 edges #> # #> # An undirected multigraph with 9 components and spatially explicit edges #> # #> # Dimension: XY #> # Bounding box: xmin: 7.522595 ymin: 51.94151 xmax: 7.546705 ymax: 51.96119 #> # Geodetic CRS: WGS 84 #> # #> # Node data: 987 × 1 (active) #> geometry #> #> 1 (7.538109 51.95286) #> 2 (7.537867 51.95282) #> 3 (7.537815 51.95867) #> 4 (7.537015 51.95848) #> 5 (7.533441 51.95578) #> 6 (7.533415 51.95561) #> # ℹ 981 more rows #> # #> # Edge data: 1,215 × 5 #> from to name type geometry #> #> 1 1 2 Hagemanns Kämpken residential (7.538109 51.95286, 7.537867 51.95… #> 2 3 4 Stiegkamp residential (7.537815 51.95867, 7.537015 51.95… #> 3 5 6 Havixbecker Straße residential (7.533441 51.95578, 7.533467 51.95… #> # ℹ 1,212 more rows"},{"path":"https://luukvdmeer.github.io/sfnetworks/articles/sfn02_create_represent.html","id":"mixed-networks","dir":"Articles","previous_headings":"","what":"Mixed networks","title":"Creating and representing spatial networks","text":"sfnetworks native support represent mixed networks, .e. networks edges can traveled ways, others one way. However, type networks quite common applications spatial network analysis. example, road networks streets oneway streets. creating directed network, duplicating reversing edges undirected, can mimic mixed network structure. morpher to_spatial_mixed() exactly . Since network cleaning functions work well duplicated reversed edges, usually good idea first create directed network, clean , mimic mixed representation.","code":"# First we mark some streets as oneway. streets = roxel |> mutate(oneway = sample(c(TRUE, FALSE), n(), replace = TRUE, prob = c(0.8, 0.2))) # Check the distribution of oneway vs twoway streets. streets |> st_drop_geometry() |> count(oneway) #> # A tibble: 2 × 2 #> oneway n #> #> 1 FALSE 240 #> 2 TRUE 975 # Create a directed network. dnet = as_sfnetwork(streets) # Check the number of edges in the directed network. # This equals the total number of streets. n_edges(dnet) #> [1] 1215 # Convert it into a mixed network. # Oneway streets remain directed. # Twoway streets are duplicated and reversed. mnet = dnet |> convert(to_spatial_mixed, directed = oneway) # Check number of edges in the mixed network. # This equals the number of oneway streets ... # ... plus twice the number of twoway streets. n_edges(mnet) #> [1] 1455"},{"path":"https://luukvdmeer.github.io/sfnetworks/articles/sfn02_create_represent.html","id":"geometries","dir":"Articles","previous_headings":"","what":"Geometries","title":"Creating and representing spatial networks","text":"makes sfnetwork objects different tbl_graph objects nodes (optionally) edges geometries. geometries stored geometry list-column, following design sf. also means just sf, columns “sticky”, survive column subsetting operations. Like sf, can always extract geometries active network element using sf::st_geometry(). shortcuts st_geometry(x, \"nodes\") st_geometry(net, \"edges\") can used extract geometries network element, regardless active . way around, can also replace geometries using setter function sf::set_set_geometry() (alternatively: st_geometry(x) = new). New node geometries required geometry type POINT, new edge geometries geometry type LINESTRING. preserve valid spatial network structure, following done: replacing node geometries, endpoints edge geometries replaced well match new node geometries. replacing edge geometries, endpoints geometries added new nodes network whenever don’t equal original location. original nodes remain network even now isolated. Original network New network can drop geometries using sf::st_drop_geometry() (alternatively: st_geometry(x) = NULL). already shown previous section, dropping edge geometries still return sfnetwork object, now spatially implicit instead spatially explicit edges. Dropping node geometries, however, return tbl_graph. area geometries occupy bounded bounding box. can use sf::st_bbox() compute bounding box active element sfnetwork object. compute bounding box full network, use st_network_bbox(). cases, network bounding box may different bounding box nodes . Element bounding boxes Network bounding box coordinates geometries always expressed specified coordinate reference system (CRS). sfnetwork object, CRS node edge geometries required equal. can extract CRS using sf::st_crs(). transform coordinates different CRS, use sf::st_transform(), specifying example EPSG code new CRS (ways specifying possible well, see documentation sf). Geometries also coordinate precision associated . precision round coordinate values, applied spatial operations. Just CRS, nodes edges sfnetwork object required precision. can extract precision using sf::st_precision(), set using sf::st_set_precision(). Precision values specified scale factor. example, specify 3 decimal places precision, use scale factor 1000. precision specified, defaults machine precision. However, sfnetworks, functions assess spatial equality nodes use default precision 1e12 (.e. 12 decimal places) speed processing. Thanks sf, also possible explicitly specify attribute-geometry relations. define attribute column attribute constant, aggregate, identity. See information. can get set attribute-geometry relations active network element function sf::st_agr(). setter, can also use pipe-friendly version sf::st_set_agr(). Note columns really attributes edges seen network analysis perspective, included attribute-geometry relation specification ensure smooth interaction sf.","code":"net |> activate(edges) |> st_geometry() #> Geometry set for 1215 features #> Geometry type: LINESTRING #> Dimension: XY #> Bounding box: xmin: 7.522595 ymin: 51.94151 xmax: 7.546705 ymax: 51.96119 #> Geodetic CRS: WGS 84 #> First 5 geometries: #> LINESTRING (7.538109 51.95286, 7.537867 51.95282) #> LINESTRING (7.537815 51.95867, 7.537015 51.95848) #> LINESTRING (7.533441 51.95578, 7.533467 51.9557... #> LINESTRING (7.525977 51.95283, 7.526581 51.95293) #> LINESTRING (7.532301 51.95559, 7.532214 51.9557... orig_net = as_sfnetwork(mozart, \"gabriel\") orig_nodes = st_geometry(orig_net, \"nodes\") new_nodes = st_jitter(orig_nodes, 250) new_net = orig_net |> st_set_geometry(new_nodes) ggraph(orig_net, \"sf\") + geom_sf(data = new_nodes, color = \"orange\") + geom_edge_sf() + geom_node_sf(color = \"darkgrey\", size = 4) + theme_void() ggraph(new_net, \"sf\") + geom_sf(data = orig_nodes, color = \"darkgrey\") + geom_edge_sf() + geom_node_sf(color = \"orange\", size = 4) + theme_void() net |> activate(nodes) |> st_drop_geometry() #> # A tbl_graph: 987 nodes and 1215 edges #> # #> # A directed multigraph with 9 components #> # #> # Node Data: 987 × 0 (active) #> # #> # Edge Data: 1,215 × 5 #> from to name type geometry #> #> 1 1 2 Hagemanns Kämpken residential (7.538109 51.95286, 7.537867 51.95… #> 2 3 4 Stiegkamp residential (7.537815 51.95867, 7.537015 51.95… #> 3 5 6 Havixbecker Straße residential (7.533441 51.95578, 7.533467 51.95… #> # ℹ 1,212 more rows p1 = st_point(c(1, 0)) p2 = st_point(c(0, 0.5)) p3 = st_point(c(1, 1)) p4 = st_point(c(2, 0.5)) nodes = st_sf(geometry = c(st_sfc(p1), st_sfc(p3), st_sfc(p4))) edges = st_sf(geometry = st_sfc(st_linestring(c(p1, p2, p3)))) edges$from = 1 edges$to = 2 G = sfnetwork(nodes, edges) node_bbox = G |> st_bbox() |> st_as_sfc() edge_bbox = G |> activate(edges) |> st_bbox() |> st_as_sfc() net_bbox = G |> st_network_bbox() |> st_as_sfc() ggraph(G, \"sf\") + geom_sf( data = node_bbox, color = \"#F8766D\", fill = NA, linewidth = 1.5, linetype = 4 ) + geom_sf( data = edge_bbox, color = \"#619CFF\", fill = NA, linewidth = 1.5, linetype = 4 ) + geom_edge_sf() + geom_node_sf(size = 4) + theme_void() ggraph(G, \"sf\") + geom_sf( data = net_bbox, color = \"orange\", fill = NA, linewidth = 1.5, linetype = 4 ) + geom_edge_sf() + geom_node_sf(size = 4) + theme_void() st_transform(net, 3035) #> # A sfnetwork: 987 nodes and 1215 edges #> # #> # A directed multigraph with 9 components and spatially explicit edges #> # #> # Dimension: XY #> # Bounding box: xmin: 4150707 ymin: 3206375 xmax: 4152366 ymax: 3208564 #> # Projected CRS: ETRS89-extended / LAEA Europe #> # #> # Node data: 987 × 1 (active) #> geometry #> #> 1 (4151782 3207612) #> 2 (4151765 3207609) #> 3 (4151784 3208259) #> 4 (4151728 3208240) #> 5 (4151472 3207948) #> 6 (4151470 3207929) #> # ℹ 981 more rows #> # #> # Edge data: 1,215 × 5 #> from to name type geometry #> #> 1 1 2 Hagemanns Kämpken residential (4151782 3207612, 4151765 3207609) #> 2 3 4 Stiegkamp residential (4151784 3208259, 4151728 3208240) #> 3 5 6 Havixbecker Straße residential (4151472 3207948, 4151474 3207941,… #> # ℹ 1,212 more rows # With unspecified precision, no node is equal to another node. any(lengths(st_equals(net)) > 1) #> [1] FALSE # With an extremely low precision, all nodes are equal to each other. all(lengths(st_equals(st_set_precision(net, 1))) == n_nodes(net)) #> [1] TRUE net |> activate(edges) |> st_agr() #> from to name type #> constant constant #> Levels: constant aggregate identity net |> activate(edges) |> st_set_agr(c(type = \"aggregate\")) |> st_agr() #> from to name type #> constant aggregate #> Levels: constant aggregate identity"},{"path":"https://luukvdmeer.github.io/sfnetworks/articles/sfn02_create_represent.html","id":"extract-geometries","dir":"Articles","previous_headings":"","what":"Extract geometries","title":"Creating and representing spatial networks","text":"Like sf, can always extract geometries active network element using sf::st_geometry(). shortcuts st_geometry(x, \"nodes\") st_geometry(net, \"edges\") can used extract geometries network element, regardless active .","code":"net |> activate(edges) |> st_geometry() #> Geometry set for 1215 features #> Geometry type: LINESTRING #> Dimension: XY #> Bounding box: xmin: 7.522595 ymin: 51.94151 xmax: 7.546705 ymax: 51.96119 #> Geodetic CRS: WGS 84 #> First 5 geometries: #> LINESTRING (7.538109 51.95286, 7.537867 51.95282) #> LINESTRING (7.537815 51.95867, 7.537015 51.95848) #> LINESTRING (7.533441 51.95578, 7.533467 51.9557... #> LINESTRING (7.525977 51.95283, 7.526581 51.95293) #> LINESTRING (7.532301 51.95559, 7.532214 51.9557..."},{"path":"https://luukvdmeer.github.io/sfnetworks/articles/sfn02_create_represent.html","id":"replace-geometries","dir":"Articles","previous_headings":"","what":"Replace geometries","title":"Creating and representing spatial networks","text":"way around, can also replace geometries using setter function sf::set_set_geometry() (alternatively: st_geometry(x) = new). New node geometries required geometry type POINT, new edge geometries geometry type LINESTRING. preserve valid spatial network structure, following done: replacing node geometries, endpoints edge geometries replaced well match new node geometries. replacing edge geometries, endpoints geometries added new nodes network whenever don’t equal original location. original nodes remain network even now isolated. Original network New network","code":"orig_net = as_sfnetwork(mozart, \"gabriel\") orig_nodes = st_geometry(orig_net, \"nodes\") new_nodes = st_jitter(orig_nodes, 250) new_net = orig_net |> st_set_geometry(new_nodes) ggraph(orig_net, \"sf\") + geom_sf(data = new_nodes, color = \"orange\") + geom_edge_sf() + geom_node_sf(color = \"darkgrey\", size = 4) + theme_void() ggraph(new_net, \"sf\") + geom_sf(data = orig_nodes, color = \"darkgrey\") + geom_edge_sf() + geom_node_sf(color = \"orange\", size = 4) + theme_void()"},{"path":"https://luukvdmeer.github.io/sfnetworks/articles/sfn02_create_represent.html","id":"drop-geometries","dir":"Articles","previous_headings":"","what":"Drop geometries","title":"Creating and representing spatial networks","text":"can drop geometries using sf::st_drop_geometry() (alternatively: st_geometry(x) = NULL). already shown previous section, dropping edge geometries still return sfnetwork object, now spatially implicit instead spatially explicit edges. Dropping node geometries, however, return tbl_graph.","code":"net |> activate(nodes) |> st_drop_geometry() #> # A tbl_graph: 987 nodes and 1215 edges #> # #> # A directed multigraph with 9 components #> # #> # Node Data: 987 × 0 (active) #> # #> # Edge Data: 1,215 × 5 #> from to name type geometry #> #> 1 1 2 Hagemanns Kämpken residential (7.538109 51.95286, 7.537867 51.95… #> 2 3 4 Stiegkamp residential (7.537815 51.95867, 7.537015 51.95… #> 3 5 6 Havixbecker Straße residential (7.533441 51.95578, 7.533467 51.95… #> # ℹ 1,212 more rows"},{"path":"https://luukvdmeer.github.io/sfnetworks/articles/sfn02_create_represent.html","id":"bounding-box","dir":"Articles","previous_headings":"","what":"Bounding box","title":"Creating and representing spatial networks","text":"area geometries occupy bounded bounding box. can use sf::st_bbox() compute bounding box active element sfnetwork object. compute bounding box full network, use st_network_bbox(). cases, network bounding box may different bounding box nodes . Element bounding boxes Network bounding box","code":"p1 = st_point(c(1, 0)) p2 = st_point(c(0, 0.5)) p3 = st_point(c(1, 1)) p4 = st_point(c(2, 0.5)) nodes = st_sf(geometry = c(st_sfc(p1), st_sfc(p3), st_sfc(p4))) edges = st_sf(geometry = st_sfc(st_linestring(c(p1, p2, p3)))) edges$from = 1 edges$to = 2 G = sfnetwork(nodes, edges) node_bbox = G |> st_bbox() |> st_as_sfc() edge_bbox = G |> activate(edges) |> st_bbox() |> st_as_sfc() net_bbox = G |> st_network_bbox() |> st_as_sfc() ggraph(G, \"sf\") + geom_sf( data = node_bbox, color = \"#F8766D\", fill = NA, linewidth = 1.5, linetype = 4 ) + geom_sf( data = edge_bbox, color = \"#619CFF\", fill = NA, linewidth = 1.5, linetype = 4 ) + geom_edge_sf() + geom_node_sf(size = 4) + theme_void() ggraph(G, \"sf\") + geom_sf( data = net_bbox, color = \"orange\", fill = NA, linewidth = 1.5, linetype = 4 ) + geom_edge_sf() + geom_node_sf(size = 4) + theme_void()"},{"path":"https://luukvdmeer.github.io/sfnetworks/articles/sfn02_create_represent.html","id":"coordinate-reference-system","dir":"Articles","previous_headings":"","what":"Coordinate reference system","title":"Creating and representing spatial networks","text":"coordinates geometries always expressed specified coordinate reference system (CRS). sfnetwork object, CRS node edge geometries required equal. can extract CRS using sf::st_crs(). transform coordinates different CRS, use sf::st_transform(), specifying example EPSG code new CRS (ways specifying possible well, see documentation sf).","code":"st_transform(net, 3035) #> # A sfnetwork: 987 nodes and 1215 edges #> # #> # A directed multigraph with 9 components and spatially explicit edges #> # #> # Dimension: XY #> # Bounding box: xmin: 4150707 ymin: 3206375 xmax: 4152366 ymax: 3208564 #> # Projected CRS: ETRS89-extended / LAEA Europe #> # #> # Node data: 987 × 1 (active) #> geometry #>