I am new to plotting in R/leaflet. I am plotting a shapefile with multilinestrings into R with leaflet.
Is there a way I can extract from the geometry column separate columns for lat and long coordinates? I have looked at this answer and this one, but I can't get the right result and it's a mixture of long/lat co-ordinates in each column.
The end result I would like to get is a map where the lines are coloured based on a variable (like this), but in order to run the loop I need to have long/lat co-ordinates separated.
I have two comments: to export lat & long coordinates of a multilinestring you could use sf::st_coordinates(), provided your multilinestring is in an unprojected CRS (otherwise you would get eastings & northings instead).
But I believe that - provided that I understand your question correctly - you are making it unnecessarily complicated.
Color coding multilines based on a variable can be done by the means of leaflet::colorFactor(). You first declare a palette by the means of a named lookup table - linking values to colors - and then apply it in your leaflet::addPolylines() call.
To illustrate on an example consider this piece of code; as your shapefile is not reproducible I am using a dataset of 13 rivers from Natural Earth to get a multiliestring (any multilinestring).
library(rnaturalearth) # to get some multilinestrings / any multilinestrings :)
library(dplyr)
library(sf)
rivers <- ne_download(category = 'physical',
scale = 110,
type = 'rivers_lake_centerlines',
returnclass = 'sf') %>%
mutate(color_source = case_when(name %in% c('Mississippi',
'Peace',
'Amazonas',
'ParanĂ¡') ~ "Americas",
T ~ "Rest of World")) %>%
group_by(color_source) %>%
summarise()
library(leaflet)
# prepare a palette - manual colors according to color_source column
palPwr <- leaflet::colorFactor(palette = c("Americas" = "red",
"Rest of World" = "blue"),
domain = rivers$color_source)
# first prepare a leaflet plot ...
lplot <- leaflet(rivers) %>%
addProviderTiles("CartoDB.Positron") %>% # or any other basemap...
addPolylines(color = ~palPwr(color_source), # note the tilde notation!
opacity = 2/3) %>% # opacity = alpha
leaflet::addLegend(position = "bottomright",
values = ~color_source, # data frame column for legend
opacity = .7, # alpha of the legend
pal = palPwr, # palette declared earlier
title = "Rivers of the World")
lplot # ... then display it
Related
I want to create a map of Germany where each state is shaded according to its gross domestic product. I know how to do this in R (and put the code below). Is there a possibility to do this in Julia in an equally simple way?
library(tidyverse)
library(ggplot2)
library(sf)
shpData = st_read("./geofile.shp")
GDPData <- read.delim("./stateGDP.csv", header=FALSE)
GDPData <- rename(GDPData,StateName=V1,GDP=V2)
GDPData %>%
left_join(shpData) ->mergedData
ggplot(mergedData) + geom_sf(data = mergedData, aes(fill = BIP,geometry=geometry)) + coord_sf(crs = st_crs(mergedData))-> pBIP1
You'd load the Shapefile and use Plots to plot it.
The ideomatic code is something like
using Plots, Shapefile, CSV
shp = Shapefile.shapes(Shapefile.Table("geofile.shp"))
GDPData = CSV.read("stateGDP.csv")
plot(shp, fill_z = GDPData.V2')
Note the ' which transposes the values to a column vector - this will tell Plots to apply the colors to individual polygons.
My question is similar (basically the same) to the previous asked one: Draw All Lines Between Points
But I would like to have a solution using leaflet in R. Is it possible to do this using leaflet? The addPolylines() function works as connecting all of the consecutive points in a dataframe. As the example dataset below, it is easy to connect all points by sequence, but how to draw all the possible segments between those five points?
I would like to see a general solution with leaflet that I can apply on scenarios with more points. Many thanks!
locations <- data.frame(Long = c(76,75,73,72,74,76), Lat = c(43,40,40,43,45,43))
leaflet("locations") %>%
addTiles() %>%
addPolylines(lng = locations$Long,
lat = locations$Lat)
It can be broken down into 2 steps:
Create a data frame which contains all combinations between coordinates.
Draw lines between each pair of coordinates. See How Do I connect two coordinates with a line using Leaflet in R
Step 1
library(leaflet)
library(tidyr)
library(dplyr)
library(purrr)
locations <- data.frame(Long = c(76,75,73,72,74,76), Lat = c(43,40,40,43,45,43))
# get unique coordinates
locations_distinct <- locations %>%
distinct_all()
# get all combinations between any two points
combs <- combn(1:nrow(locations_distinct),2,simplify = FALSE)
# get pairs of coordinates
locations_paris <- map_df(combs,function(x){
df <- bind_cols(
locations_distinct[x[1],],locations_distinct[x[2],]
)
colnames(df) <- c("Long","Lat","Long1","Lat1")
return(df)
})
Step 2
How Do I connect two coordinates with a line using Leaflet in R
map <- leaflet(locations_paris) %>%
addTiles()
for(i in 1 : nrow(locations_paris)){
map <- map %>%
addPolylines(
lng = c(locations_paris$Long[i],locations_paris$Long1[i]),
lat = c(locations_paris$Lat[i],locations_paris$Lat1[i])
)
}
map
I have a dataset with lat long coordinates. Each coordinate belongs to a group and I want to connect them with polylines using leaflet. I am trying to give different colors to different line segments. I am fairly new to leaflet, so I don't know if I'm approaching this problem the right way.
I have tried the solution provided here, but I only get a single color as a result.
I have simulated a dataset to illustrate my problem:
#Example dataframe
lat <- runif(10,-10.8544921875,2.021484375)
long <- runif(10,49.82380908513249,59.478568831926395)
group <- factor(c(1,1,1,1,2,2,2,1,1,1))
header <- c("lat", "long", "group")
df <- data.frame(lat, long, group)
colnames(df) <- header
I have tried the following:
#Color palette
pal <- colorFactor(palette = c('navy', 'red'),
levels = levels(df$group))
#Graph
leaflet(df) %>%
addTiles() %>%
addPolylines(lng = ~as.numeric(df$long),
lat = ~as.numeric(df$lat), stroke = pal(df$group),
opacity = 0.1)
I want that the polyline between points that belong to group 1 and 2 shows red, and the rest just blue (or any combination of 2 colors, for that matter). However, I get back only one color. Opacity doesn't seem to match either (I have defined an opacity of 0.1 but the value of resulting polyline has certainly a value of 1).
Can anyone give me some pointers as to what I'm doing wrong?
Also, (with the larger dataset) I notice that once I add colors to the polylines of my dataset, the process becomes computationally very intensive. Can anyone give me guidelines to optimize the process?
Any help is very much appreciated. Thank you in advance!!
You mentioned performance was an issue, for which I recommend using mapdeck to do the plotting
In this example I'm plotting 100,000 lines, coloured by a group variable.
Setting up the data
For the data I'm putting the origin & destination coordinates in the same row. And using data.table to make it.
library(data.table)
lons <- seq(-180, 180, by = 0.0001)
lats <- seq(-90, 90,by = 0.0001)
n <- 1e5
dt <- data.table(
lon = sample(lons, size = n)
, lat = sample(lats, size = n)
, group = sample(c(1,2), replace = T, size = n)
)
dt[
, `:=`(
lon_to = shift(lon, type = "lead")
, lat_to = shift(lat, type = "lead")
)
]
Plot
You need a Mapbox API key for the underlying base map
Use the add_line() function to create a coloured line between a given origin & destination
mapdeck() %>%
add_line(
data = dt
, origin = c("lon","lat")
, destination = c("lon_to", "lat_to")
, stroke_colour = "group"
)
It's a mess because I've just sampled random points, but you get the idea.
Each color needs added as a separate layer to the map.
library(leaflet)
library(dplyr)
lat <- runif(10,-10.8544921875,2.021484375)
long <- runif(10,49.82380908513249,59.478568831926395)
group <- factor(c(1,1,1,1,2,2,2,1,1,1))
header <- c("lat", "long", "group")
col<-mapvalues(group,from=c(1,2),to=c("#00FF00","#FF0000")) #mannually add colors
#col<-mapvalues(group,from=c(1,2),to=substr(rainbow(2),1,7)) # programatically; looks like addpolylines wants hex not 8-digit colors
df <- data.frame(lat, long, group,col)
#colnames(df) <- header #you dont need this
map <- leaflet(df)
map <- addTiles(map)
for( group in levels(df$group)){
map <- addPolylines(map, lng=~long,lat=~lat,data=df[df$group==group,], color=~col)
}
map
I don't think arguments like color and stroke will read unique levels of the vector for each point of the line if you have multiple unique ones for each layer, whcih is why you need the for. you can see this if you reverse the order of the colors, eg from
col<-mapvalues(group,from=c(1,2),to=c("#00FF00","#FF0000"))
to
col<-mapvalues(group,from=c(1,2),to=c("#FF0000","#00FF00"))
It only picks up whatever the first color is.
Regarding my performance question, the following code snippet was very helpful:
map <- leaflet(df, options = leafletOptions(preferCanvas = TRUE))
I'm struggling with a problem. I'd like to separate two countries by adding some space between them. The idea is, for example, to explode europe, by still showing each country but with e predefined space between each country.
I'm using R and ggplot for the project I'm working and until now I tried to look for some answer on the web but could not find anything. You can get something by changing the size but that solution will also imply a loss on the details of the map.
If you could help that would be super great!
A bit hacky, but you can try to scale the polygons to <100% of the originals...
library(sf)
library(magrittr)
sample data
#read shapefile with country polygons
# source: http://thematicmapping.org/downloads/TM_WORLD_BORDERS-0.3.zip
map <- st_read( "./data/countries/TM_WORLD_BORDERS-0.3.shp" )
#filter out some relevant countries
benelux <- c("Belgium", "Luxembourg", "Netherlands")
map <- map %>% filter( NAME %in% benelux )
#what do we have?
ggplot() + geom_sf( data = map )
code
#scale the polygons to 75% of original
#extract geometry
map.sfc = st_geometry(map)
#get centroids
map.centroid = st_centroid(map.sfc)
#recalculate geometry, scale to 75%
map.scale = ( map.sfc - map.centroid ) * 0.75 + map.centroid
#replace original geoemtry by recalculated geometry. set crs back to WGS84
map.scale_sf = st_set_geometry(map, map.scale) %>% st_set_crs( 4326 )
#ewhat do we have now?
ggplot() + geom_sf( data = map.scale_sf )
I am plotting some spatial data in R using the tmap package. I define breaks and plot color in the tm_dots function. I'd like to be able to define the plot order of the categories so that they are defined by the category (highest category on top, second highest below that, etc.). I need to be able to see clearly where the highest category points are. I know this could be achieved with multiple spatial point data frames, but is there another less clunky way? Below is an example using the meuse data. I make the points huge so they overlap. So ideally here in the plot the plot order would be: blue, green, orange, red.
libary(tmap)
library(sp)
data("meuse")
coordinates(meuse) <- c("x","y")
tm_layout() +
tm_shape(meuse) + tm_dots("cadmium", breaks = c(1,2,3,4,Inf), palette = "-Spectral", auto.palette.mapping = FALSE,
size = 1) +
tm_legend(legend.outside = TRUE)
Turns out the default plot order is the original data frame row order. To make the categories plot in the correct order, I create a numeric factor variable for the categories and sort the original data frame by it.
libary(tmap)
library(sp)
library(dplyr)
data("meuse")
meuse <- meuse %>%
mutate(cat = base::cut(cadmium, breaks = c(-Inf,1,2,3,4,Inf),
labels = c(1,2,3,4,5))) %>%
arrange(cat)
coordinates(meuse) <- c("x","y")
tm_layout() +
tm_shape(meuse) + tm_dots("cadmium", breaks = c(1,2,3,4,Inf), palette = "-Spectral", auto.palette.mapping = FALSE,
size = 1) +
tm_legend(legend.outside = TRUE)