New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
calc_network_catchment does not seem to show all paths #261
Comments
Interesting and I confirm the issue, with mapview::mapview(sydroads) +
mapview::mapview(network, col.regions = "green") +
mapview::mapview(testcycleway, color = "red", lwd = 5) See what you mean about the lack of coverage in that neighbourhood. Also would you expect more coverage around the middle section of the left line? Note: I didn't write the function or define its purpose so may not be the best person to fix this issue. Thoughts @richardellison ? Cheers for reporting this with a decent reproducible example in any case. |
Yes, I'd expect there to be more coverage in a few places on the left side and a few roads on the right side too. I might dig into the igraph package to see if there are other functions other than |
The reason for this is that the function that generates the graph looks for
matching coordinates at the end of the linestrings (which should be in the
intersection). Unfortunately many streets on Open Street Maps are done as a
single line string for a large section (ignoring any intersections). You
can see this if you inspect the ways in OSM. The code works for a properly
defined network.
I have tried to change it previously so it looks for any matching
coordinates (this is what Open Trip Planner does I think), but the danger
there is that it will create some "intersections" where there are matching
vertices even if these are not intended as intersections (for example
bridges, tunnels, etc.) which also isn't ideal. When I tried this for New
York (for the New York map I did) that is what happened which is why I
abandoned that idea.
Any suggestions for how to overcome that are appreciated!
Richard
…On 6 June 2018 at 23:56, Steven Andrews ***@***.***> wrote:
Yes, I'd expect there to be more coverage in a few places on the left side
and a few roads on the right side too. I might dig into the igraph package
to see if there are other functions other than igraph::get.shortest.paths
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#261 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AKIixeVKdBzHNjsvSgWFlLEZN0Z-MSrbks5t59-LgaJpZM4UbZCU>
.
|
OSM mandates that all intersections exist as single points, so |
@mpadge yes please do - that could solve this problem and perhaps be part of a wider function like |
I think there are two issues here: 1) Long lines that don't break on intersections, which
and suppose we were trying to find all of the edges within 1 unit from "A" by finding the shortest path to each node, we'd find out that AB, AC, ABD, ABDE are all the shortest paths (from It seems like we need a list of all the paths the algorithm searched on its way to the shortest path and choose all of them that are shorter than the impedance parameter. Using |
Good clarification @sandrews-CTPS - agree 1) is a data prep issue and 2) is more an issue associated with the function. I think we can make progress on both. |
The way the function works (I think, trying to remember correctly) is that
it calculates the shortest path from the geometry to each node on the
network within a straight-line distance of the geometry limited by the
impedance parameter. So for that reason, it should include at leat most
edges within the catchment area but I agree that some edges would be missed
like in the example you showed. The problem is that although calculating
every possible route between two nodes is feasible for small networks, on
larger city-size networks that becomes very computationally intensive to
the point where it becomes impossible to complete. Assuming that igraph
uses something like the Dijkstra algorithm, it won't compute all possible
routes when searching for the shortest path.
One approach might be to use the current function as it is, then
selectively identify edges that are otherwise within the catchment area for
a secondary check.
Richard
…On 8 June 2018 at 01:15, Robin ***@***.***> wrote:
Good clarification @sandrews-CTPS <https://github.com/sandrews-CTPS> -
agree 1) is a data prep issue and 2) is more an issue associated with the
function. I think we can make progress on both.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#261 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AKIixXlv3WzS9z2VlP4xKNJE6Frg8clDks5t6UOOgaJpZM4UbZCU>
.
|
The
The
Cutting at juntions increases number of |
Thanks for that - seems dodgr can add new nodes where they are needed, breaking the network down into its component segments. That's awesome - something I hadn't grasped about the package. It tooks some wrestling to get what I think are comparative results based on OSM and dodr networks but eventually it seems to have paid-off as catchment based on the dodgr one seems way more detailed (see below). @richardellison should we recommend users decompose their networks before doing @mpadge I got an error message with the below, should I add an issue to https://github.com/ATFutures/dodgr/issues ?:
@sandrews-CTPS what does this solve your problem for now? Input into the documentation very welcome - give me a shout if you'd like pointers on that - but the input so far is appreciated and should (eventually) lead to improvements in stplanr in any case! library(stplanr)
library(dodgr)
library(sf)
#> Linking to GEOS 3.5.1, GDAL 2.1.2, proj.4 4.9.3
library(rgdal)
#> Loading required package: sp
#> rgdal: version: 1.2-20, (SVN revision 725)
#> Geospatial Data Abstraction Library extensions to R successfully loaded
#> Loaded GDAL runtime: GDAL 2.1.2, released 2016/10/24
#> Path to GDAL shared files: /usr/share/gdal/2.1
#> GDAL binary built with GEOS: TRUE
#> Loaded PROJ.4 runtime: Rel. 4.9.3, 15 August 2016, [PJ_VERSION: 493]
#> Path to PROJ.4 shared files: (autodetected)
#> Linking to sp version: 1.2-7
library(sp)
data_dir <- system.file("extdata", package = "stplanr")
unzip(file.path(data_dir, "smallsa1.zip"), exdir = tempdir())
unzip(file.path(data_dir, "testcycleway.zip"), exdir = tempdir())
unzip(file.path(data_dir, "sydroads.zip"), exdir = tempdir())
sa1income <- readOGR(tempdir(), "smallsa1")
#> OGR data source with driver: ESRI Shapefile
#> Source: "/tmp/Rtmpjqg5nc", layer: "smallsa1"
#> with 638 features
#> It has 19 fields
#> Integer64 fields read as strings: OBJECTID_1
testcycleway <- readOGR(tempdir(), "testcycleway")
#> OGR data source with driver: ESRI Shapefile
#> Source: "/tmp/Rtmpjqg5nc", layer: "testcycleway"
#> with 2 features
#> It has 2 fields
#> Integer64 fields read as strings: id
testcycleway_sf <- read_sf(tempdir(), "testcycleway")
sydroads <- readOGR(tempdir(), "roads")
#> OGR data source with driver: ESRI Shapefile
#> Source: "/tmp/Rtmpjqg5nc", layer: "roads"
#> with 4451 features
#> It has 7 fields
#> Integer64 fields read as strings: osm_id
sydroads_sf <- as(sydroads, "sf")
sydroads_mini <- sydroads_sf[testcycleway_sf[1, ], , op = st_is_within_distance,
dist = 100]
# get network from dodgr: what's the difference?
streetnet <- dodgr::dodgr_streetnet("glebe sydney")
streetnet_mini = streetnet[sydroads_mini, ]
#> although coordinates are longitude/latitude, st_intersects assumes that they are planar
# setdiff(names(streetnet_mini), names(sydroads_mini)) # quite a lot!
# characterise street network:
l = st_length(streetnet_mini)
w = l/mean(l)
plot(streetnet_mini["osm_id"], lwd = w) # clean the street network:
nrow(streetnet_mini)
#> [1] 171
streetnet_mini$highway = "tertiary" # attempt to make the next bit work...
graph <- weight_streetnet(streetnet_mini)
streetnet_dodgr <- dodgr::dodgr_to_sf(graph) %>% st_sf()
nrow(streetnet_dodgr)/nrow(streetnet_mini) # 4 fold increase
#> [1] 4.02924
l = st_length(streetnet_dodgr)
w = l/mean(l)
plot(st_geometry(streetnet_dodgr), lwd = w, col = 1:nrow(streetnet_dodgr)) # sln1 <- SpatialLinesNetwork(sydroads_mini) # fails
sln1 <- SpatialLinesNetwork(sydroads)
sln2 <- SpatialLinesNetwork(as(streetnet_dodgr, "Spatial"))
network1 <- calc_network_catchment(sln = sln1, polygonlayer = sa1income, targetlayer = testcycleway,
calccols = c("Total"), maximpedance = 800, distance = 10, projection = "austalbers",
dissolve = TRUE)
#> Warning in igraph::get.shortest.paths(sln@g, x, output = "epath"): At
#> structural_properties.c:4597 :Couldn't reach some vertices
#> Warning in igraph::get.shortest.paths(sln@g, x, output = "epath"): At
#> structural_properties.c:4597 :Couldn't reach some vertices
#> Warning in igraph::get.shortest.paths(sln@g, x, output = "epath"): At
#> structural_properties.c:4597 :Couldn't reach some vertices
#> Warning in igraph::get.shortest.paths(sln@g, x, output = "epath"): At
#> structural_properties.c:4597 :Couldn't reach some vertices
#> Warning in igraph::get.shortest.paths(sln@g, x, output = "epath"): At
#> structural_properties.c:4597 :Couldn't reach some vertices
#> Warning in igraph::get.shortest.paths(sln@g, x, output = "epath"): At
#> structural_properties.c:4597 :Couldn't reach some vertices
#> Warning in igraph::get.shortest.paths(sln@g, x, output = "epath"): At
#> structural_properties.c:4597 :Couldn't reach some vertices
#> Warning in igraph::get.shortest.paths(sln@g, x, output = "epath"): At
#> structural_properties.c:4597 :Couldn't reach some vertices
#> Warning in igraph::get.shortest.paths(sln@g, x, output = "epath"): At
#> structural_properties.c:4597 :Couldn't reach some vertices
#> Warning in igraph::get.shortest.paths(sln@g, x, output = "epath"): At
#> structural_properties.c:4597 :Couldn't reach some vertices
#> Warning in igraph::get.shortest.paths(sln@g, x, output = "epath"): At
#> structural_properties.c:4597 :Couldn't reach some vertices
network2 <- calc_network_catchment(sln = sln2, polygonlayer = sa1income, targetlayer = testcycleway[1,
], calccols = c("Total"), maximpedance = 800, distance = 10, projection = "austalbers",
dissolve = TRUE)
# network1 = network1[network2, ]
plot(network2)
plot(network1, col = "red", add = T) Session infodevtools::session_info()
#> Session info -------------------------------------------------------------
#> setting value
#> version R version 3.5.0 (2018-04-23)
#> system x86_64, linux-gnu
#> ui X11
#> language (EN)
#> collate en_US.UTF-8
#> tz Etc/UTC
#> date 2018-06-08
#> Packages -----------------------------------------------------------------
#> package * version date
#> assertthat 0.2.0 2017-04-11
#> backports 1.1.2 2017-12-13
#> base * 3.5.0 2018-05-20
#> bindr 0.1.1 2018-03-13
#> bindrcpp 0.2.2 2018-03-29
#> class 7.3-14 2015-08-30
#> classInt 0.2-3 2018-04-16
#> compiler 3.5.0 2018-05-20
#> curl 3.2 2018-03-28
#> datasets * 3.5.0 2018-05-20
#> DBI 1.0.0 2018-05-02
#> devtools 1.13.5 2018-02-18
#> digest 0.6.15 2018-01-28
#> dodgr * 0.1.0.099 2018-06-08
#> dplyr 0.7.5 2018-05-19
#> e1071 1.6-8 2017-02-02
#> evaluate 0.10.1 2017-06-24
#> foreign 0.8-70 2018-04-23
#> formatR 1.5 2017-04-25
#> geosphere 1.5-7 2017-11-05
#> glue 1.2.0 2017-10-29
#> graphics * 3.5.0 2018-05-20
#> grDevices * 3.5.0 2018-05-20
#> grid 3.5.0 2018-05-20
#> htmltools 0.3.6 2017-04-28
#> httr 1.3.1 2017-08-20
#> igraph 1.2.1 2018-03-10
#> jsonlite 1.5 2017-06-01
#> knitr 1.20 2018-02-20
#> lattice 0.20-35 2017-03-25
#> lubridate 1.7.4 2018-04-11
#> lwgeom 0.1-4 2018-01-28
#> magrittr 1.5 2014-11-22
#> maptools 0.9-2 2017-03-25
#> memoise 1.1.0 2017-04-21
#> methods * 3.5.0 2018-05-20
#> mime 0.5 2016-07-07
#> openxlsx 4.0.17 2017-03-23
#> osmdata 0.0.7 2018-05-17
#> pillar 1.2.2 2018-04-26
#> pkgconfig 2.0.1 2017-03-21
#> purrr 0.2.4 2017-10-18
#> R.methodsS3 1.7.1 2016-02-16
#> R.oo 1.22.0 2018-04-22
#> R.utils 2.6.0 2017-11-05
#> R6 2.2.2 2017-06-17
#> raster 2.6-7 2017-11-13
#> rbenchmark 1.0.0 2012-08-30
#> Rcpp 0.12.17 2018-05-18
#> RcppParallel 4.4.0 2018-03-02
#> rgdal * 1.2-20 2018-05-07
#> rgeos 0.3-26 2017-10-31
#> rlang 0.2.0 2018-02-20
#> rmarkdown 1.9 2018-03-01
#> rprojroot 1.3-2 2018-01-03
#> rvest 0.3.2 2016-06-17
#> sf * 0.6-3 2018-05-17
#> sp * 1.3-1 2018-06-05
#> spData 0.2.8.9 2018-05-25
#> spDataLarge 0.2.6.5 2018-05-25
#> stats * 3.5.0 2018-05-20
#> stplanr * 0.2.4.9000 2018-05-25
#> stringi 1.2.2 2018-05-02
#> stringr 1.3.1 2018-05-10
#> tibble 1.4.2 2018-01-22
#> tidyselect 0.2.4 2018-02-26
#> tools 3.5.0 2018-05-20
#> udunits2 0.13 2016-11-17
#> units 0.5-1 2018-01-08
#> utils * 3.5.0 2018-05-20
#> withr 2.1.2 2018-03-15
#> xml2 1.2.0 2018-01-24
#> yaml 2.1.19 2018-05-01
#> source
#> CRAN (R 3.5.0)
#> CRAN (R 3.5.0)
#> local
#> CRAN (R 3.5.0)
#> CRAN (R 3.5.0)
#> CRAN (R 3.5.0)
#> CRAN (R 3.5.0)
#> local
#> CRAN (R 3.5.0)
#> local
#> CRAN (R 3.5.0)
#> CRAN (R 3.5.0)
#> CRAN (R 3.5.0)
#> Github (ATFutures/dodgr@51d30fd)
#> CRAN (R 3.5.0)
#> CRAN (R 3.5.0)
#> CRAN (R 3.5.0)
#> CRAN (R 3.5.0)
#> CRAN (R 3.5.0)
#> CRAN (R 3.5.0)
#> CRAN (R 3.5.0)
#> local
#> local
#> local
#> CRAN (R 3.5.0)
#> CRAN (R 3.5.0)
#> CRAN (R 3.5.0)
#> CRAN (R 3.5.0)
#> CRAN (R 3.5.0)
#> CRAN (R 3.5.0)
#> CRAN (R 3.5.0)
#> CRAN (R 3.5.0)
#> CRAN (R 3.5.0)
#> CRAN (R 3.5.0)
#> CRAN (R 3.5.0)
#> local
#> CRAN (R 3.5.0)
#> CRAN (R 3.5.0)
#> CRAN (R 3.5.0)
#> CRAN (R 3.5.0)
#> CRAN (R 3.5.0)
#> CRAN (R 3.5.0)
#> CRAN (R 3.5.0)
#> CRAN (R 3.5.0)
#> CRAN (R 3.5.0)
#> CRAN (R 3.5.0)
#> CRAN (R 3.5.0)
#> cran (@1.0.0)
#> CRAN (R 3.5.0)
#> cran (@4.4.0)
#> CRAN (R 3.5.0)
#> CRAN (R 3.5.0)
#> CRAN (R 3.5.0)
#> CRAN (R 3.5.0)
#> CRAN (R 3.5.0)
#> CRAN (R 3.5.0)
#> CRAN (R 3.5.0)
#> cran (@1.3-1)
#> Github (nowosad/spData@7b53933)
#> Github (nowosad/spDataLarge@bc058ad)
#> local
#> Github (robinlovelace/stplanr@276c68e)
#> CRAN (R 3.5.0)
#> CRAN (R 3.5.0)
#> CRAN (R 3.5.0)
#> CRAN (R 3.5.0)
#> local
#> CRAN (R 3.5.0)
#> CRAN (R 3.5.0)
#> local
#> CRAN (R 3.5.0)
#> CRAN (R 3.5.0)
#> CRAN (R 3.5.0) |
@Robinlovelace yes, please open an issue in |
@Robinlovelace I'm happy that "long line" problem is on its way towards being solved. I think I'll keep trying to solve the issue with the shortest paths "missing" some edges. I think I can improve what's there, but it's going to take a little time. Perhaps we can get a list of all of the nodes that were on the shortest paths, and select all edges connecting those nodes too. I think that works out logically. I've never actually contributed to a github project so I'm not super confident about how the workflow works. |
@sandrews-CTPS You've already contributed by raising a decent reproducible issue. Congrats 👍 in terms of more contributing you can clone a version of it, play around, e.g. by changing |
Closing for now. If you have any further comments/questions on this @stevenpandrews please let us know and we'll try to fix them. |
The
calc_network_catchment
function seems to only find shortest paths based on entire features. It won't break features into smaller parts. If a portion of a line would be within 800m, but the end segment is farther than 800m away, the entire feature won't be selected.It also seems to miss some paths that are are within the
maximpedance
, but are not the fastest path.I ran the code mostly as shown in the example:
I changed the distance to
10
to make it more clear what's going on. It seems like the circled neighborhood should have more coverage. Because the nodes on either end of each street are already part of a different shortest path, the roads never get selected.Is there a way to get all paths that are less than 800m away? I can probably figure out a way to break the line segments into smaller pieces.
The text was updated successfully, but these errors were encountered: