UrbanAnalyst / dodgr

Distances on Directed Graphs in R
https://urbananalyst.github.io/dodgr/
127 stars 16 forks source link

Directed and weighed networks as routes #180

Closed XoliloX closed 2 years ago

XoliloX commented 2 years ago

Dear all,

I am completely new to networks so sorry for this question in advance !

I have a data frame that has latitudes and longitudes for both an origin and a destination point. They refer to desired routes (I would like to go from A to B) and some of those routes can be weighed against each other (pre-defined weight). My question is: what is the best workflow to parse this data frame in order to have [1] those routes on a map with [2] an attributes such as color (or a point size) that would show which routes, origin or destination are more demanded. In addition to this, what's the best way to aggregate origins and destinations in order to make the map more readable when there's too many variables.

Thanks a thousand times in advance!

Best, D.

mpadge commented 2 years ago

Hi @XoliloX, thanks for the question and no worries about the apologies. I'm not exactly sure what you want to do, but it sounds like the kind of workflow explained in the "flows" vignette. The reprex here is mostly the code taken from there, but starting with a bunch of random coordinates like it seems you have. This code uses a simple uniform "flow matrix" representing aggegation of 1 unit between each pair of origin-destination points. It sounds like you already have other data for that, so just submit for the flows parameter a matrix of (nfrom, nto) points specifying the weight of each pair.

I took the chance to go through the full workflow here, and discovered a bug in the final plotting routine, so to get that to work, you'll need to remotes::install_github("atfutures/dodgr") to update your version.

Very important note: dodgr is intended for local use only, ilke the size of one city. If your coordinates extend over anything more than a few tens of degrees, the dodgr_streetnet_sc() call will likely fail, as the server won't deliver that much data. Make sure the ranges of your coordinates aren't too large!

The following code also uses dodgr_streetnet_sc() instead of dodgr_streetnet(). You shouldn't have to even worry about the differences there, but the _sc format is better for detailed routing queries. Finally, the wt_profile parameter is important, and you should read the documentation to decide what you want to specify there.

library (dodgr)
packageVersion ("dodgr")
#> [1] '0.2.14.33'
# random points from a SMALL region:
x_range <- c (76.37261, 76.49232)
y_range <- c (15.30104, 15.36033)
npts <- 100
xy <- data.frame (
    x = runif (npts, x_range [1], x_range [2]),
    y = runif (npts, y_range [1], y_range [2])
)
head (xy)
#>          x        y
#> 1 76.39131 15.32672
#> 2 76.44673 15.31803
#> 3 76.37451 15.30612
#> 4 76.43804 15.30636
#> 5 76.43982 15.33686
#> 6 76.47239 15.34243

# get street network, expanding slightly beyond bounding box of 'xy':
net_sc <- dodgr_streetnet_sc (pts = xy, expand = 0.05)
net <- weight_streetnet (net_sc, wt_profile = "foot") # or whatever; see ?weight_streetnet for details
#> Loading required namespace: geodist
#> Loading required namespace: dplyr
# Aggregate flows presuming 1 trip between each pair of points:
flows <- matrix (1, nrow = npts, ncol = npts)
net <- dodgr_flows_aggregate (net, from = xy, to = xy, flows = flows)
# Post-process for plotting by merging the directed flows:
net <- merge_directed_graph (net)
dodgr_flowmap (net, linescale = 5)

Created on 2022-06-15 by the reprex package (v2.0.1)

You can use lots of other plotting routines and packages, notably including interactive plotting on basemaps with packages like mapdeck. With that, i'll close the issue, but feel free to ask any further questions.

XoliloX commented 2 years ago

Hi,

Super, thanks a lot ! I'll give it a try !!!

Have a great day!!!! Thanks again !!!!!

Best, David

XoliloX commented 2 years ago

Hi Mark,

One thing that I don't understand (or fail to do) is to have selected pairs of latitude and longitude in the workflow. In fact, if I understand correctly, in your example you pair each row of xy to get route density. In my case, I have 4 coordinates that match together: point of origin (lat, lon) + point of destination (lat, lon) so that each line is a final combination that needs to be mapped as a route (and the weight is a another predefined column next to those).

How would you do it then?

In advance, thanks a lot for your answer!

Best, D.

mpadge commented 2 years ago

I'm not sure exactly what you mean, but if you look through the documentation you'll see examples like that. You just need to submit origin points as the from argument, and destination points as to. Those two don't have to match in any way, and the results will simply route between all pairwise combinations of from and to points.

As for the weights, those can't be an additional column because, for example, there is no way to understand what it means to weight a flow between point A with a weight of x and point B with a weight of y? Is the weight of that route x? or maybe y? Or x times y? Those weights therefore need to be submitted as a matrix of with length(from) rows and length(to) columns. If the weights are all from, then just use array(weights, dim=c(length(weights), length(to))).

XoliloX commented 2 years ago

Hi Mark,

Thanks a lot for your answer! Regarding the first question, that's exactly what I want to avoid: to route between all pairwise from-to. I need to have a route for each row of pairwise combination separately (it's unique route each time).

For the weight, it's actually a column that says "this unique row of pairwise combination has been used n times". But I understand your point that it needs to be set in a matrix.

Thanks again for you help !!!

Best, D.