i'm doing a tmap plot with a shape file, and i want to be plotting several points for which i have long-lat coordinates onto the shape file. i've got the plot working just fine, however there are too many points on the map, meaning that the label text for different points is overlapping, and is just not particularly legible in general.
here's what the plot currently looks like.
i would really like for the text in the plot to be outside of the actual map, and to be connected to the points in the plot by thin lines which blend into the overall aesthetic of the map.
here's some example data:
name long lat
1 location -71.40909 41.82426
2 location -71.41959 41.82796
3 location -71.41277 41.79667
4 location -71.37327 41.81737
5 location -71.37170 41.89266
6 location -71.33356 41.87736
and here's the code i've got to display the above plot:
let's assume the above dataframe is plot2_points.df, while shapes is the underlying shape file.
library(tmap)
library(sp)
library(rgdal)
coordinates(plot2_points.df) <- c("long", "lat")
proj4string(plot2_points.df) <- CRS("+proj=longlat +datum=WGS84")
plot2_points.df <- spTransform(plot2_points.df, CRS("+proj=utm +zone=19T ellps=WGS84"))
# plot
tm_shape(shapes) + tm_borders() + tm_shape(plot2_points.df) + tm_dots(col = "blue", size = 0.4) + tm_text("name", col = "blue", size = 0.75, just = "top", ymod = 0.75)
i have not been able to find any function that comes anywhere near doing this. tm_lines() doesn't work, but i feel like this is intended for something completely different. also, maybe it would work to do something with the just = option? so far nothing i've tried had any kind of effect, so i figured i'd ask here. any help would be greatly appreciated, thank you very much :)
While the exact solution you are asking for (drawing thin lines from text annotations) is extremely impractical and not (to my knowledge) implemented in tmap you could improve the underlying problem by using tm_symbols() instead of tm_dots() and using the shape property for the spa name (tm_dots() have the shape set to #16 = a dot). The meaning of the symbols would be then explained in a standard legend.
This would be a more "lege artis" way of solving the problem of overlapping text annotations.
Related
I have a question about facet_wrap() in ggplot2.
I am trying to make a graph that looks like this. I attach an example image 1.enter image description here
In image 1 it can be seen that there are two maps and each one has its legend and color scale. I would like to be able to do this with ggplot and the facet_wrap() function.
My problem is that because the data in the dataframe is very different, they have a lot of amplitude for each map, when plotting the scale it does not allow me to visualize it the way I want.
enter image description here
ggplot(dataframe,mapping=aes(x=lon,x=lat))+
geom_contour_fill((aes(z=hgt,fill=stat(level)))+
geom_contour(aes(z=hgt),color="black",size=0.2)+
scale_fill_distiller(palette = "YlOrBr",direction = 1,super=ScaleDiscretised)+
mi_mapa+
coord_quickmap(xlim = range(dataframe$lon),ylim=range(dataframe$lat),expand = FALSE)+
facet_wrap(~nombre_nivel,scales="free", ncol =2) +
labs(x="Longitud",y="Latitud",fill="altura",title = "campos")
my dataframe has a shape like this. Where the facets are determined by the level variable. In this case the dataframe has another variable which is temp instead of hgt, but it's just another name.
enter image description here
Thanks
I think I've faced the alike problem building the two parts of the single map with two different scales. I found the package grid useful.
library(grid)
grid.newpage()
print(myggplot, vp = specifiedviewport)
In my case I built the first p <- ggplot() than adjusted p2 <- p + ...
with printing the two ggplots (p and p2) in two viewports. You can newly construct p2 with individual scale and print it in the grid. You can find useful information
here.
I have a sf layer in R, in real life from a shape file, created externally, but here a super simple line. All I want is to be able to add a arrow head to my lines but geom_sf() doesn't seem to have this capability. Is there any other way around? I want to keep the plot in ggplot as I am just adding one extra layer to existing maps which are set up in ggplot (the actual maps will have several other sf layers with polygons, points and lines). Basically all I want is to add an arrow head like you can in geom_path. Any ideas?
What I have:
library(sf)
library(ggplot2)
line = st_sfc(st_linestring(rbind(c(30,30), c(40,40))), crs = 28355)
ggplot(line)+geom_sf()+coord_sf(datum = 28355)
What I would like, but still using my shapefile data, and proper map projections etc.
dat <- data.frame(x = c(30,40), y = c(30,40))
ggplot(dat, aes(x, y)) + geom_path(arrow = arrow())
Created on 2021-05-06 by the reprex package (v0.3.0)
I would like to plot the outline of UK, along with an nb object that I generated from a spatial points dataframe.
The problem is that the outline of UK takes really, really long to plot --it keeps crashing my Rstudio. This for example, either take really long to load or my Rstudio just stops responding.
library(raster)
UK_gadm <- getData("GADM", country="GB", level=0)
plot(UK_gadm)
So I resorted to using ggplot2 from this solution where I can get the outline of UK like in a fraction of a second with the following commands:
library(ggplot2)
UK <- map_data(map = "world", region = "UK") # changed map to "world"
ggplot(data = UK, aes(x = long, y = lat, group = group)) +
geom_polygon() +
coord_map()
The issue now is that I would like the nb object to be plotting against the backdrop of the outline of UK -- however, this seems only achievable in base R like for example:
plot(orotl.shp, xlim=c(-125, -115), ylim=c(42,47))
plot(orstationc.neighbors.dist, orstationc.loc, add=T, lwd=2, col="blue")
Is there any way I could plot nb objects in ggplot or is there a way for R to plot the outline of UK without crashing my computer with the base R plot function?
Managed to find a fast, simple solution after a whole night of effort. Hope this helps someone else with a similar issue.
Just to elaborate on the goal: plot a neighbours object (nb) against a shapefile. This is to visualise the linkages among certain coordinates. After some googling, I think this can only be done with base R's plot function. The problem however, was loading a country's shapefile (downloaded from official sources/gadm)-- its too big.
To solve this issue, get a more generalised, simple map of the country via the maps package, turn it into a shapefile and then plot it alongside the neighbours object.
Here's the code:
library(spdep)
# get your neighbour object from your spatial points df
rest_neighbours <- dnearneigh(rest_spdf,0,1)
library(maps)
# get boundary of UK
UK_map <- sf::st_as_sf(maps::map(database='world',regions='UK', plot = FALSE, fill = TRUE))
# write to shapefile
st_write(UK_map, 'shapefiles/UK.shp')
# henceforth, we can just call the shapefile
UK <- readOGR('shapefiles/UK.shp')
# plot the boundary and the neighbours
plot(UK)
plot(rest_neighbours, rest_coords, add=T, lwd=2, col="blue")
I did not realise that official boundary files are often really detailed which also means that they are really huge and I'm glad that there's ready-made watered down versions of the maps available in the maps package of r. (Sorry if you already knew -- I'm still learning!)
Hope this helps anyone else!
I've got some issue creating a map with ggplot2 above which I project points using geom_point. When exporting in pdf or in an other support, the point size varies (because she's absolute and not axis-relative). I've searched how to change that and found a lot of answers saying, that it was on purpose, because if it wasn't the case it would be changing to ellipse each time the axis proprtions change. I understand that, however, because I work on a map, I use coord_fixed to fix the output and avoid distorsions of my map, so if I was able to fix the point size relatively to the plot size, it wouldn't be a problem.
Is there some solution to do that? I've read some interesting things suggesting using geom_polygon to artificially create ellipses. But I have two problems with this method:
First I don't know how to implement that with my data, now I know the place where the centers of my points are, but how could I then later say how to define all the centers and then defin a filled circled polygon around?
Second I have used scale_size_continuous to plot smaller or bigger points relatively to other variable. How could I implement that with geom_polygon?
Facit: I would be happy either with the possibility of override the impossibility to determine a relative unit for the point size, or with some help to make me understand how I can create the same thing with the function geom_polygon.
I tried to join a small reproducible example here. It is only an example, the problem with my data is that I have a lot of closed small values (mainly 1, like the small dot in the reproducible example), and so they seem really good, but when exporting it can become very bigger and create a lot of problems by overplotting, which is the reason why I need to fix this ratio.
Link for the map informations and second link for map informations
dat <- data.frame(postcode=c(3012, 2000, 1669, 4054, 6558), n=c(1, 20, 40, 60, 80))
ch <- read.csv("location/PLZO_CSV_LV03/PLZO_CSV_LV03.csv", sep=";")#first link, to attribute a geographical location for each postcode
ch <- ch%>%
distinct(PLZ, .keep_all=TRUE)%>%
group_by(PLZ, N, E)%>%
summarise
ch <- ch%>%
filter(PLZ %in% dat$postcode)
ch <- ch%>%
arrange(desc(as.numeric(PLZ)))
dat <- dat%>%
arrange(desc(as.numeric(postcode)))
datmap <- bind_cols(dat, ch)
ch2 <- readOGR("location/PLZO_SHP_LV03/PLZO_PLZ.shp")#second link, to make the shape of the country
ch2 <- fortify(ch2)
a <- ggplot()+
geom_polygon(dat=ch2, aes(x=long, y=lat, group=group), colour="grey75", fill="grey75")+
geom_jitter(data=datmap, aes(x=E, y=N, group=FALSE, size=n), color=c("red"))+ #here I put geom_jitter, but geom_point is fine too
scale_size_continuous(range=c(0.7, 5))+
coord_fixed()
print(a)
Thanks in advance for the help!
You can use ggsave() to save the last plot and adjust the scaling factor used for points/lines etc. Try this:
ggplot(data = ch2) +
geom_polygon(aes(x=long, y=lat, group=group),
colour="grey85", fill="grey90") +
geom_point(data=datmap, aes(x=E, y=N, group=FALSE, size=n),
color=c("red"), alpha = 0.5) +
scale_size_continuous(range=c(0.7, 5)) +
coord_fixed() +
theme_void()
ggsave(filename = 'plot.pdf', scale = 2, width = 3, height = 3)
Play around with the scale parameter (and optionally the width and height) until you are happy with the result.
DO NOT use geom_jitter(): this will add random XY variation to your points. To deal with overplotting you can try adding transparency - I added an alpha parameter for this. I also used theme_void() to get rid of axes and background.
Your shape file with map information is quite heavy: you can try a simple one with Swiss cantons, like this one.
I want to create a contour and then clip the contour by the polygon and only show the contour within the polygon.
Shapefile data can be found here
Csv file can be found here
The code I used is as follows:
library("ggplot2")
library("rgdal")
library("gpclib")
library("maptools")
require(sp)
age2100 <- read.csv("temp.csv",header=TRUE, sep=",")
shape.dir <- "C:/Users/jdbaba/Documents/R working folder/shape" # use your directory name here
lon.shape <- readOGR(shape.dir, layer = "Export_Output_4")
str(lon.shape)
lon.df <- fortify(lon.shape, region = "Id")
p <- ggplot(lon.df, aes(x = long, y = lat, group = group)) +
geom_polygon(colour = "black", fill = "grey80", size = 1) +
theme()
p <- p + geom_point(data=age2100,aes(x=age2100$x,y=age2100$y,group="z"),size=0.1)
p <- p + geom_density2d(colour="red")
p
Here, I have created the map, points and the contour. I don't know whether the code I am using created the contour for variable z or not. If it is not correct can anyone suggest me ?
The sample output that I got is as follows:
Now, I want to clip the contour within the polygon and hide the part of contour that is outside the polygon.
I want to know how to add the labels to the contour and control the contour interval.
Please let me know if my question is not clear.
Thanks
Jdbaba
I can't reproduce your map exactly. The code you provided gives me a map with two sets of contours - one that looks like yours and one that overlaps it in the southern part of the region. I suspect this is an artefact of your group setting. Also, I can see there is an island in the southern part of what I assume is the lake.
I like to clean up and partition my ggplot stuff into bits, since I often find something in an early part of a ggplot call confuses something in a later part. Here's how I would map the region, draw points, and then add a density contour:
map <- function(){
geom_polygon(data=lon.df,aes(x=long,y=lat,group=piece),colour="black",fill="grey80",size=1)
}
points <- function(){
geom_point(data=age2100,aes(x=x,y=y),size=0.1)
}
density <- function(){
geom_density2d(data=age2100,aes(x=x,y=y),colour="red")
}
ggplot()+map() +points() +density()
Which gives this:
Now that's much different to what your contour looks like, and I don't know why. Maybe your group parameter is grouping all the points with the same z?
Anyway, it seems you don't want a density plot, you want a map of your Z values over your area. This is going to need kriging or some other interpolation technique. Forget about ggplot for a while, concentrate on the numbers.
For starters, plot the points coloured by the z value. You should see this:
which at least will give you a good idea of what the correct contour will look like.
Anyway, this is getting into a full-on tutorial..