ggplot2 overwrites plot limits - r

I have two shapefiles, which I would like to plot into a given plot extent. One of the shapefiles exceeds the extent and when plotted it automatically overwrites the limits of the extent. This happens when loading the shapefiles using the terra package and plotting it using the tidyterra functions, but it is not an issue when reading the shapefiles using the old readOGR function and ploting it using the core ggplot2 functions.
# libraries
library(terra)
library(tidyterra)
library(ggplot2)
library(ggspatial)
library(raster)
library(sp)
library(sf)
library(rgdal)
EXAMPLE 1 - I don't want this
# read shapefiles
SHP1 <- terra::vect('file1.shp')
SHP2 <- terra::vect('file2.shp')
# plot
ggplot() +
coord_equal(ylim=c(100000,800000)) +
geom_spatvector(data=SHP1,fill=NA,color='grey',inherit.aes=T) +
geom_spatvector(data=SHP2,fill=NA,color='green',size=1)
EXAMPLE 2 - I want this
# read shapefiles
SHP1 <- terra::vect('file1.shp')
SHP2 <- terra::vect('file2.shp')
ggplot() +
coord_equal(ylim=c(100000,800000)) +
geom_polygon(SHP1,mapping=aes(x=long,y=lat,group=group),fill=NA,color='grey',size=0.1) +
geom_polygon(SHP2,mapping=aes(x=long,y=lat,group=group),fill=NA,color='green',size=0.5)
How could I obtain map from example 2 using the geom_spatvector function used in example 1?
I really would like to use the terra package to read and manipulate shapefiles but then it produces SpatVector class object which is not supperted by the ggplot2 function. This means that only for the plotting purposes I have to transfer it to the older SpatialPolygonsDataFrame and this is exactly what I would like to avoid.

You need to use coord_sf rather than coord_equal. Obviously, we don't have your shapefile, but if I take a similar shapefile of Germany, then we can demonstrate:
library(tidyterra)
library(ggplot2)
p <- ggplot(SHP1) +
geom_spatvector()
Firstly, with the standard geom_spatvector plot:
p
Secondly, with axis limits written by a call to geom_sf:
p + coord_sf(ylim = c(47, 52))

Related

how to show raster cell values with tmap?

The code below plots raster cell values. How can I do the same with package tmap?
library(terra)
pai_sim <- rast(ncols=6, nrows=6,
xmin=1, xmax=60,
ymin=1, ymax=60,
res=10)
values(pai_sim) <- 1
plot(pai_sim)
text(pai_sim)
The code below results in errors (incorrect number of dimensions and canĀ“t find object). I have searched using different terms e.g. tmap tm_raster show cell values, but have not found a solution. This is a teaching example so I want to avoid additional steps e.g to not convert to polygon on the fly if at all possible.
library(tmap)
tm_shape(pai_sim) +
tm_raster() +
tm_text("lyr.1")
tm_shape(pai_sim) +
tm_raster() +
tm_text(lyr.1)

Global cartogram in R

I am trying to create a global cartogram using the cartogram package in R. I am trying to use the data from wrld_simpl. What I expect is a cartogram in which the Population ("Pop2005" variable) is plotted. The code I have developed is this:
data(wrld_simpl)
world<-wrld_simpl
world_sf = st_as_sf(world)
world_sf_proj = st_transform(world_sf, crs = 3785)
world_cartogram <- cartogram_cont(world_sf_proj, "POP2005")
plot(world_cartogram)
Nonetheless, this has resulted in the following figure:
Do you know what is wrong with the code? Maybe the CRS? I have tried to use others CRS but I got the following error:
"Error: Using an unprojected map. This function does not give correct centroids and distances for longitude/latitude data:
Use "st_transform()" to transform coordinates to another projection."
Taken from this documentation, it is stated that
The default plot of an sf object is a multi-plot of all attributes, up
to a reasonable maximum
If you want to use the base R plot function, then use st_geometry(your_map) to plot (the geometry) an sf object.
Another possibility (which I don't recommend) is to set plot options to 1 plot maximum (options(sf_max.plot=1)), but this plots the first variable, and it might not be the best idea.
library(sf)
library(spData)
library(cartogram)
library(tidyverse)
world_sf = st_as_sf(world)
world_sf_proj = st_transform(world_sf, crs = 3785)
world_cartogram <- cartogram_cont(world_sf_proj, "pop")
plot(st_geometry(world_cartogram))
Now, sf is particularly well suited with ggplot2 and the tidyverse. In that setting, just use ggplot in combination with geom_sf.
ggplot(world_cartogram) +
geom_sf()

Trying to plot in tmap shapefile with attribute

I am trying to work with municipality data in Norway, and I'm totally new to QGIS, shapefiles and plotting this in R. I download the municipalities from here:
Administrative enheter kommuner / Administrative units municipalities
Reproducible files are here:
Joanna's github
I have downloaded QGIS, so I can open the GEOJson file there and convert it to a shapefile. I am able to do this, and read the data into R:
library(sf)
test=st_read("C:/municipality_shape.shp")
head(test)
I have on my own given the different municipalities different values/ranks that I call faktor, and I have stored this classification in a dataframe that I call df_new. I wish to merge this "classification" on to my "test" object above, and wish to plot the map with the classification attribute onto the map:
test33=merge(test, df_new[,c("Kommunekode_str","faktor")],
by=c("Kommunekode_str"), all.x=TRUE)
This works, but when I am to plot this with tmap,
library(tmap)
tmap_mode("view")
tm_shape(test33) +
tm_fill(col="faktor", alpha=0.6, n=20, palette=c("wheat3","red3")) +
tm_borders(col="#000000", lwd=0.2)
it throws this error:
Error in object[-omit, , drop = FALSE] : incorrect number of
dimensions
If I just use base plot,
plot(test33)
I get the picture:
You see I get three plots. Does this has something to do with my error above?
I think the main issue here is that the shapes you are trying to plot are too complex so tmap is struggling to load all of this data. ggplot also fails to load the polygons.
You probably don't need so much accuracy in your polygons if you are making a choropleth map so I would suggest first simplifying your polygons. In my experience the best way to do this is using the package rmapshaper:
# keep = 0.02 will keep just 2% of the points in your polygons.
test_33_simple <- rmapshaper::ms_simplify(test33, keep = 0.02)
I can now use your code to produce the following:
tmap_mode("view")
tm_shape(test_33_simple) +
tm_fill(col="faktor", alpha=0.6, n=20, palette=c("wheat3","red3")) +
tm_borders(col="#000000", lwd=0.2)
This produces an interactive map and the colour scheme is not ideal to tell differences between municipalities.
static version
Since you say in the comments that you are not sure if you want an interactive map or a static one, I will give an example with a static map and some example colour schemes.
The below uses the classInt package to set up breaks for your map. A popular break scheme is 'fisher' which uses the fisher-jenks algorithm. Make sure you research the various different options to pick one that suits your scenario:
library(ggplot2)
library(dplyr)
library(sf)
library(classInt)
breaks <- classIntervals(test_33_simple$faktor, n = 6, style = 'fisher')
#label breaks
lab_vec <- vector(length = length(breaks$brks)-1)
rounded_breaks <- round(breaks$brks,2)
lab_vec[1] <- paste0('[', rounded_breaks[1],' - ', rounded_breaks[2],']')
for(i in 2:(length(breaks$brks) - 1)){
lab_vec[i] <- paste0('(',rounded_breaks[i], ' - ', rounded_breaks[i+1], ']')
}
test_33_simple <- test_33_simple %>%
mutate(faktor_class = factor(cut(faktor, breaks$brks, include.lowest = T), labels = lab_vec))
# map
ggplot(test_33_simple) +
geom_sf(aes(fill = faktor_class), size= 0.2) +
scale_fill_viridis_d() +
theme_minimal()

Plot ggplot polygons with holes with geom_polygon

There are questions out there about the fact that ggplot2 can't plot polygon shapes that have holes.
That is because, if the order of points is not OK, the end graph looks bad, usually with clipping/trimming lines inside the donut shape.
I have read a lot about how order matters, but I am not able to step forward.
I have a SpatialPolygonsDataFrame with 26 features (comes from raster::rasterToPolygons(dissolve=T)) and I want to plot it with ggplot.
Here's what happens -
r3.pol <- rasterToPolygons(r3, dissolve=T)
r3.df <- fortify(r3.pol)
names(r3.df) <- c('x','y','order','hole','piece','ID','group')
p <- ggplot(r3.df)
p <- p + geom_polygon(mapping=aes(x=x,y=y,group=ID), fill='red')
p <- p + coord_equal()
I see this output:
While it should be like so, with plot(r3.pol):
How can I make this work?
I tried for hours but I am not able to reorder r3.df.
Also, can the information in r3.df$hole be helpful? It is returned by the function fortify for points that are holes (I think).
Side question: how can I give you my r3.pol SpatialPolygonsDataFrame, so that you can try yourself? I remember seeing long, reproducible "dumps" of objects here, but I don't know how to do it.
I saved the polygons data frame here. Was not able to save it using dput, sorry. You can fetch it using load.
I suggest to install the package "ggpolypath" and use geom_polypath instead of geom_polygon. Works for me.
My temporary solution is: ##$% polygons, and use the raster package.
Namely:
r <- raster(x=extent(r3.pol), crs=crs(r3.pol)) # empty raster from r3.pol
res(r) <- 250 # set a decent resolution (depends on your extent)
r <- setValues(r, 1) # fill r with ones
r <- mask(r, r3.pol) # clip r with the shape polygons
And now plot it as you would do with any raster with ggplot. The rasterVis package might come helpful here, but I'm not using it, so:
rdf <- data.frame(rasterToPoints(r))
p <- ggplot(rdf) + geom_raster(mapping=aes(x=x, y=y), fill='red')
p <- p + coord_equal()
And here it goes.
Alternatively, you can create the raster with rasterize, so the raster will hold the polygons values (in my case, just an integer):
r <- raster(x=extent(r3.pol), crs=crs(r3.pol))
res(r) <- 250
r <- rasterize(r3.pol, r)
rdf <- data.frame(rasterToPoints(r))
p <- ggplot(rdf) + geom_raster(mapping=aes(x=x, y=y, fill=factor(layer)))
p <- p + coord_equal()
If someone comes up with a decent solution for geom_polygon, probably involving re-ordering of the polygons data frame, I'll be glad to consider it.

Create histogram of raster in R

I want to create a value distribution chart, like a histogram or graph, of a raster image using:
library(raster)
library(sp)
library(rgdal)
DEM <- raster("NR.tif")
hist(DEM)
plot(DEM)
plot() is used to validate my data and shows me an all green image. Supposedly band 1 of 3.
However I can't see other bands?
Obviously the distribution in the histogram doesn't represent interpolated values in the imagefile.
A histogram created in ARCgis is herehist, which I believe represent the true values.
Any suggestions on how to create a histogram of the real values like the image.
Best,
Mathias
You could try
download.file("https://www.dropbox.com/s/t279m5ojners7fl/NR.tif?dl=1",
tf <- tempfile(fileext = ".tif"), mode="wb")
library(raster)
library(tiff)
library(ggplot2)
library(reshape2)
DEM <- readTIFF(tf)
plot(as.raster(DEM))
ggplot(melt(DEM),
aes(value, fill=as.factor(Var3))) +
geom_histogram(position="dodge")
Or, with regards to your update
r <- as.raster(DEM)
tab <- as.data.frame(sort(table(r)))
ggplot(subset(tab, !r %in% c("#F0F0F0", "#000000")),
aes(x=r, y=Freq, fill=I(r))) +
geom_bar(stat="identity") +
theme(axis.text.x = element_text(angle=90))
Try setting the NAvalue to the background color and then call the hist() function or use the ggplot commands from lukeA:
library(raster)
ras <- stack("Downloads/NR.tif")
NAvalue(ras) <- 240
hist(ras)
This results in the following plots:

Resources