My map-making code generates a map based on census data and plots important points as a tm_dots() layer. What I'd like to be able to do is differentiate between the types of dots (e.g. if the location is "Informal" or "Commercial").
tm_shape(bristol) + tm_fill("population", palette = "YlOrRd",
auto.palette.mapping = TRUE,
title = "Bristol Population",
breaks = c(0,5,10,15,20,25), colorNA = "darkgrey") + tm_borders("grey25",alpha = 0.7, lwd = 0.1) +
tm_dots("n", size=0.1,col="green", shapeNA = NA, title = "Spaces") +
tm_legend(text.size=1,title.size=1.2,position=c("left","top")) +
tm_layout(legend.outside = TRUE, legend.outside.position = "bottom", title.snap.to.legend = TRUE)
What I'm looking for is essentially:
tm_dots("n", size=0.1,col=Classification, shapeNA = NA, title = "Spaces")
Adding several tm_dots() layers isn't an option. I also can't rename the dot legend, any advice on that too is appreciated.
Thanks for your help!
Solution
For future reference, I added offices to bristol via left_join, thus adding the Classification variable to the SpatialPolygonsDataFrame. I was having issues with it displaying NA values despite the showNA = NA parameter, but colorNA = NULL worked. Final line:
tm_dots(size=0.1,col="Classification", palette = "Set1", colorNA = NULL)
So bristol is a polygon shape (SpatialPolygonDataFrame or sf), and you want to plot dots in some polygons?
Normally, you would have a variable Offices, with two levels "Informal" and "Commercial". Then it's just tm_dots(size = 0.1, col = "Offices"). If you want to place two dots in one polygons because there are Informal and Commercial offices, then you can use your own approach (and use xmod and/or ymod for one group to prevent overlap), or create a SpatialPointsDataFrame or sf object with all offices, and a variable Offices with two levels as described above.
I figured it out, you need to have another tm_shape() for it to work. Still haven't got the title() to appear properly but one step at a time.
tm_shape(bristol) + tm_fill("population", palette = "YlOrRd", auto.palette.mapping = TRUE,
title = "Bristol Population",
breaks = c(0,5,10,15,20,25), colorNA = "darkgrey") + tm_borders("grey25",alpha = 0.7, lwd = 0.1) +
tm_dots("Informal_Offices", size=0.1,col="green", shapeNA = NA, title = "Informal Offices") +
tm_shape(bristol) + tm_dots("Commercial_Offices", size=0.1,col="white",shapeNA=NA, title="Commercial Offices") +
tm_legend(text.size=1,title.size=1.2,position=c("left","top")) +
tm_layout(legend.outside = TRUE, legend.outside.position = "bottom", title.snap.to.legend = TRUE)
Result
Related
I am trying to make my beautiful ggplot map interactive with a tooltip using ggplotly. But the map rendered with ggploty is not beautiful.
Here is a picture of my map with only ggplot:
Here is a picture of my map when using ggplotly. It removes the legend and make the map ugly:
Is there another way of making my ggplot map interactive with a tooltip? And also ggplotly takes some time to render the interactive map:
Here is my sample code for my ggplot:
ggplot(data = sdpf_f, aes( fill = n,x = long, y = lat, group = group, text = tooltip)) +
geom_polygon(color = "white") +
theme_void() +
scale_fill_continuous(low="#c3ffff", high="#0291da",
guide = guide_legend(title.position = "top", label.position = "bottom", keywidth = 2,
keyheight = 0.5,
title = "Number of agreements"),na.value="lightgrey"
) +
theme(legend.position="bottom") +
coord_map()
Thanks & kind regards,
Akshay
I don't have your data and this isn't exactly the same, but it's fairly close to what I think you're expecting.
The libraries:
I called tidyverse for the plotting and piping. I called maps for the data I used and plotly for the Plotly graph.
I used a function that is derived from one of the ways ggplot sets the aspect ratio. I know I found this function on SO, but I don't remember who wrote it.
library(tidyverse)
library(maps)
library(plotly)
map_aspect = function(x, y) {
x.center <- sum(range(x)) / 2
y.center <- sum(range(y)) / 2
x.dist <- ggplot2:::dist_central_angle(x.center + c(-0.5, 0.5), rep(y.center, 2))
y.dist <- ggplot2:::dist_central_angle(rep(x.center, 2), y.center + c(-0.5, 0.5))
y.dist / x.dist
}
I had to create data as your question is not reproducible. I figured I would include it, so that my answer was reproducible.
ms <- map_data("state") %>%
mutate(n = ifelse(str_detect(region, "^a"), 1.0,
ifelse(str_detect(region, "^o"), 1.5,
ifelse(str_detect(region, "^t"), 2.0,
ifelse(str_detect(region, "^s"), 2.5,
ifelse(str_detect(region, "^w"),
3.0,
NA))))))
I modified your ggplot call. The only change is coord_fixed instead of coord_map. I did this so that Plotly could interpret the aspect ratio correctly. Within coord_fixed, I used the function map_aspect.
gp <- ggplot(data = ms, aes(fill = n, x = long, y = lat,
group = group, text = tooltip)) +
geom_polygon(color = "white") +
theme_void() +
scale_fill_continuous(low="#c3ffff", high="#0291da",
guide = guide_legend(title.position = "top",
label.position = "bottom",
keywidth = 2,
keyheight = 0.5,
title = "Number of agreements"),
na.value="lightgrey"
) +
theme(legend.position="bottom") +
coord_fixed(with(ms, map_aspect(long, lat)))
Then I created a Plotly object. I set some requirements for the layout, as well (horizontal legend at the bottom, with the legend title above the elements—similar to the legend in your ggplot call).
pp <- ggplotly(gp) %>%
layout(legend = list(orientation = "h", valign = "bottom",
title = list(side = "top"),
x = .02),
xaxis = list(showgrid = F), yaxis = list(showgrid = F),
showlegend = T)
Next, I needed to add the information for the legend. I chose to name the traces (which are split by color). I started by creating a vector of the names of the traces (which is what you see in the legend). I added a "" at the end, so that the NA-colored states wouldn't have a named trace (so they won't show in the legend).
This is likely something you'll need to change for your data.**
# the color values and the last one, which is for NAs, no legend
nm <- seq(1, 3, by = .5) %>% sprintf(fmt = "%.1f") %>% append(., "")
Then I wanted to ensure that showlegend was true for all but the NA (light gray) states. I created a vector of T and F.
legs <- c(rep(TRUE, 5), FALSE)
Then I added these to the plot.
invisible(lapply(1:length(pp$x$data),
function(i){
pp$x$data[[i]]$name <<- nm[i]
pp$x$data[[i]]$showlegend <<- legs[i]
}))
I am trying to do something similar to what is described in the blog here but using R with ggtree, ggmap, and ggplot2.
I want to be able to combine the plots of the phylogenetic tree and the map showing the sampling locations of the tips on a geographical map, and link the tips to the sampling locations by segments. That would allow to see ie. if some clusters appears to specific geographical locations (ie north, south of an area) and would allow also to display different data with tips colors/symbols. This would be at first used as exploratory graphs, but this can also be used later on for publication ...
I would like to use the gg* libraries (ggplot2, ggtree, ggmap ...) to do that, because then it is easy to modify plots to display different variables. Here is a dummy script to describe how I do that so far. I do the tree and map plot separately and combine them. I want also to be able to have a common legend for the two plots. I am stuck after combining, I do not find out how to link the points from the tree plot to the points on the map plot with segments.
Anyone with ideas / possible solutions on how to do that or an alternative approach ?
Here is the dummy dataset to illustrate for creating the plots
library(patchwork)
library(ggpubr)
library(ggtree)
library(tidyverse)
library(ggmap)
library(ggplot2)
mytree <- ggtree::rtree(100)
mymap <- ggmap::get_map(c(left = 0.903, bottom = 44.56, right = 6.72, top = 49.38),
scale = 4, maptype = "terrain",
source = "stamen",
color = "bw")
save(mymap, file = "dummy_map.Rdata")
ggmap require API key to create the map (sorry I cannot share the API key, but you can make one for free on google cloud). I saved the map object and its downloadable from here.
# Loading the map
load("dummy_map.Rdata")
# creating dummy metadata
mytree_data <- tidytree::as_tibble(mytree)
mymetadata <- mytree_data %>%
dplyr::filter(!is.na(label)) %>%
tibble::add_column(year = sample(seq(1990, 2020, by = 1), 100, replace = T),
lon = sample(seq(0.91, 6.7, by = 0.01), 100, replace = T),
lat = sample(seq(44.56, 49.38, by = 0.01), 100, replace = T)) %>%
dplyr::rename(id = label) %>%
dplyr::select(id, year, lat, lon)
# plotting the phylogenetic tree
# phylogenetic tree example
mytree_plot <-
ggtree::ggtree(mytree, layout = "rectangular", ladderize = T, lwd = .2) %<+%
mymetadata +
geom_tippoint(aes(color = year), size = 1, show.legend = T) +
scale_color_gradient(low='red', high="blue", space = "Lab",
limits = c(NA, NA), na.value = "black",
n.breaks = 8,
guide = "colorbar") +
geom_tiplab(aes(label = label), size = 1, offset = -1E-10) +
geom_treescale(fontsize = 2, linesize = 0.5, offset = 1) +
theme(legend.position = c(0.9,0.15),
legend.title = element_text(size = 8),
legend.text = element_text(size = 6),
plot.title = element_text(hjust = 1))
mytree_plot
For some reason, I have to add the theme to be able to see the legend for the points, it is not created automatically. This should not occur. If anyone see what I am doing wrong here please let me know.
Then I add the sampling locations on the map, and deactivate the legend that is common with the tree legend
mymap_plot <- ggmap(mymap, n_pix = 340, darken = c(0.6, "white"))+
geom_point(data = mymetadata,
aes(x = lon, y = lat, color = year),
size = 2, alpha = .8, na.rm = T) +
scale_color_gradient(low='red', high="blue", space = "Lab",
limits = c(NA, NA),
n.breaks = 8,
guide = "colorbar") +
guides(color = F)
mymap_plot
Then I combine the tree plot and the map plot together. I tried with "patchwork" and "ggpubr" packages.
So far it appear easier to combine plots and draw a single legend with ggpubr, so this is currently my first choice at combining plot
# combining plots with patchwork
combined_plot <- mytree_plot + mymap_plot
# combining plots with ggpubr
# which I like better because it allows to combine the legends which is usefull
# when more variables are used ie shape for uncertainty location
other_combined <- ggarrange(mytree_plot, mymap_plot,
ncol = 2,
labels = c("A", "B"),
align = "hv",
legend = "bottom",
common.legend = T)
Here is the combined plot of the phylogenetic tree (ggtree) and the map (ggmap) obtained with ggpubr.
I am stuck at this point.
I need a way to add segments between corresponding points at the tips of the tree to the corresponding sampling locations of each tip on the map
Any solutions/ideas on how I could do that?
I'm having an issue with finding answers for a fairly simple question. I just need to move the axis titles (xlab and ylab) away from the axes. I haven't uploaded reproducible data since the files are large shapefiles, but I can upload it if needed (I figure it's a fairly straightforward answer). I have attached the code I've used so far as well as the map I'm struggling with:
LandUseMap <- tm_shape(LandUseshape, ylim = c(50.45, 50.68), xlim=c(-105,
-104.7), projection = "longlat") +
tm_fill("COVTYPE", title = "Land Cover Type",style="fixed",breaks=c(20,30,34,50,110,121,122,220,230),
labels=c("Water","Non-Vegetated Land","Developed","Shrubland","Grassland","Annual Cropland","Perennial Crops/Pasture","Broadleaf","No Data"),
palette=manualpal) +
tm_borders("grey") +
tm_legend(outside = TRUE, text.size = .65) +
tm_layout(frame = FALSE,asp =NA, outer.margins = c(0.05,0.1,0,0), inner.margins = c(0.05,0.05,0.01,0.05))+
tm_grid(y=c(50.45, 50.50, 50.55, 50.60, 50.65), x=c(-105.0,-104.9,-104.8,-104.7),labels.inside.frame = FALSE, col = "#00ff0000",
labels.size =0.8)+
tm_xlab("Longitude", size = 1)+
tm_ylab("Latitude", size = 1)+
tm_scale_bar(size = 1, position = c(0,0.8)) +
tm_compass(size=2.5,north = 0,position = c(0,0.9))
LandUseMap
Here's the map:
I have this code:
tm_shape(usa, bbox = bbox, projection = map.crs)+
tm_borders(col = "grey", lwd = 1) +
tm_fill(palette = "grey") +
tm_grid(x = c(-77,-75,-73,-71),
y = c(39,37,35),
labels.inside.frame = F,
labels.size = 1.1,
col = "white") +
tm_layout(outer.margins = c(.1,.03,.05,.05),
outer.bg.color = "white")+
tm_shape(sk.dat1,axes = T) +
tm_dots("DATELAND", palette = colo,
auto.palette.mapping=FALSE,
size = .5,
breaks = seq(2010,2017,
length.out =8),legend.show = T, alpha=.7) +
tm_layout(title = "Southern Kingfish Occurrence",
legend.show = T,
legend.position = c("right","bottom"),
legend.bg.color = "grey70",
legend.height = 2)
Which outputs this legend. How can I change the tmap input to only include single years with no commas?
This looks as a number format problem; your code is not exactly reproducible, so I can not make 100% sure, but I am fairly certain by the look.
To remedy try including this in your tm_layout call:
legend.format=list(fun=function(x) formatC(x, digits=0, format="d"))
By the way I wrote a short blog post on tmap legend formatting a couple months back (my problem were currency and percentage signs).
https://www.jla-data.net/eng/tmap-legend/
I am trying to create a function to map different variables for a specific state's school districts. However I a running into some problems formatting the legend. At the moment I have it laid out the best way to fit the maps(horizontally), but some of the text is being cut off (Below Average Poverty Rate), and I'd like to add % to the number labels in the legend. My code and an image of the legend is below. Any help you can provide would be very much appreciated. Thank You.
MakeLEAMap <-function(StateNum,NCHE_VAR,VAR1_NAME,In,Folder){
as.character(substitute(StateNum))
as.character(substitute(NCHE_VAR))
as.character(substitute(NCHE_In))
as.character(substitute(VAR1_NAME))
as.character(substitute(Folder))
map <-
tm_shape(LEA_1415_New[LEA_1415_New#data$STATEFP == StateNum, ]) +
tm_polygons(NCHE_VAR,border.col="#000000", lwd= .5, textNA="Below Average \nPoverty Rate" , palette = 'Blues', style="quantile",
title=paste(In," State LEA Map: ",VAR1_NAME),
legend.is.portrait = FALSE) +
tm_text("LCITY", size=NCHE_VAR,scale=.8, root=2,print.tiny = FALSE, size.lowerbound = .85, bg.alpha = .75,
remove.overlap = TRUE,legend.size.show = FALSE, col="black") +
tm_layout( legend.title.size = 3,
frame = FALSE, inner.margins = c(0,.0,.05,.0), asp = 1.5,
legend.text.size = 1,
legend.outside=TRUE, legend.outside.position = 'bottom',
legend.frame = TRUE,
legend.outside.size = .3, legend.position = c(-0.1, 0.3))
save_tmap(map, filename=paste("State_Maps_TEST/",Folder,"/",In,".pdf", sep = ''),width=8, height=8 )
}
MakeLEAMap("48","Abv_Diff_Home_Pov","% Children in Poverty minus \n% Children HCY (Ages5-17)",
"TX","ALL")
Here is what the legend looks like now
To make the legend show percentages use this function inside your tm_polygons call:
legend.format=list(fun=function(x) paste0(formatC(x, digits=0, format="f"), " %"))
You can play with the digits (decimal points) and you can drop the space before % sign if you desire.
To make the legend more legible increase the space around your map by making a bigger bbox (possibly using extent function from raster package to read bbox of your spatial object and then enlarging it) and move the legend by adjusting its position.
This is what I came up with in a different context, but one which also called for a percentage sign in tmap legend.