Why is the legend distorted on my map using tmap? - r

I'm following an example from Geocomputation with R in Chapter 4, section 4.2.6. In the example from the book, the map of New Zealand that has the average elevation in the polygons/regions has a nice, compact legend that is easy to read and placed automatically in the upper left corner. See the image output from the book below.
Here is the link to the section of the book: https://geocompr.robinlovelace.net/spatial-operations.html
When I execute the same code to try to duplicate this map, the image that is produced for me has a very distorted legend with text that is also small. I've tried adjusting my Plots pane, exporting the image in multiple formats, etc., and the legend is still distorted like this.
The code below is what I am executing:
library(sf)
library(spData)
library(tmap)
# Summarize nz regions by average elevation
nz_agg = aggregate(x = nz_height, by = nz, FUN = mean)
# Map nz regions colored by average elevation
tm_shape(nz) +
tm_polygons() +
tm_shape(nz_agg) +
tm_polygons(col = "elevation")
A couple months ago, when I produced tmaps with legends, I wasn't having this issue. I don't know if some setting has been changed or updated that I don't know about. The version of R that I'm using is 4.1.2 (2021-11-01) -- "Bird Hippie".

So, it wasn't a problem with my R version or the versions of the R packages I am using.
I use a laptop and have a couple of different locations where I use it for work. One location has multiple monitors; the other does not. I didn't notice it until researching this further, but when I plug in/unplug my monitors, sometimes it changes the resolution settings on my computer. Apparently, it wasn't enough for me to notice on my laptop until attempting to run this code. So, the cause of the distortion was due to changes on my computer that I was unaware of that happened automatically. I'll have to keep an eye on this.

Related

Why is this R code to generate maps not completing?

I'm trying to use R to make some maps but I have having problems getting anything to generate. I took the following code from a post here:
library(ggplot2)
library(sf)
eng_reg_map <-
st_read("data/Regions_(December_2017)_Boundaries/Regions_(December_2017)_Boundaries.shp")
eng_reg_map |>
ggplot() +
geom_sf(fill = "white",
colour = "black") +
theme_void()
I have the relevant files in the right place, but when I run this code it just runs and never stops. I've waited for an hour.
Any help would be much appreciated.
As discussed in the comments, I personally find this problem for one of two reasons.
The shapefile you want to plot is really large. It might not be surprising that R doesn't want to plot a 30 gigabyte shapefile, but it might be surprising to you that your file is that large. You can usually get around this by reducing the number of vertices, combining like shapes, filtering out some unnecessary features, etc.
You are trying to print the plot to the consol. For some reason, actually making the map is relatively fast, but displaying the map takes a really long time. I'm sure this varies computer by computer, but this has been my experience. In this case, it works best to save the plot as a pdf or something else and then view the plot outside of R.

Why is plot of GADM SpatialPolygonsDataFrame not loading in R?

One-liner: R is taking too long to plot a SpatialPolygonsDataFrame and the best answer I've found online is that the issue is machine-specific.
Problem: I am trying to plot a SpatialPolygonsDataFrame of India (level = 1) that I downloaded from GADM but no plotting function (spplot, plot, tm_shape) is producing a plot in any given time; instead R appears to do work in the background but 5+ minutes later there still is no plot. Pressing the stop button that appears above the console does nothing and eventually in order to re-try some other method I have to force-quit the app. My question is similar to this question but the consensus on that question was that the issue appears machine specific with no solution thereafter.
Here's some info about my machine/R studio version:
R version 3.3.2 (2016-10-31) / R Studio Version 1.0.136 / OS: MacOS Sierra version 10.12.6.
The file was downloaded from: GADM in RDS format
(1.) I've tried different plotting mechanisms
setwd("~/Data/Reference/")
india <- readRDS("IND_adm1.rds")
library(sp)
library(tmap)
# Plot method #1
plot(india)
# Plot method #2
spplot(india, "NAME_1")
# Plot method #3
tm_shape(india) + tm_borders()
(2.) I've tried recreating the SpatialPolygonsDataFrame from a shapefile instead of the RDS
india <- readOGR(dsn = "~/Data/Reference/" , layer = "IND_adm1")
(3.) I've updated all packages on the machine and uninstalled and re-installed the sp package and the tmap package.
(4.) I've tried other countries' file and had the same issue.
(5.) I've examined the structure of the SpatialPolygonsDataFrame and found no issues with it -- things seem to be in place and in the right way.
(6.) Using maps package to plot their data works fine. For some reason SpatialPolygonsDataFrame classes are not plotting. I've now also tried to plot the shape files from DIVA-GIS.
library(maps)
tx <- map("county", "texas", plot = FALSE, fill = TRUE)
plot(tx) # this plots fine and immediately
Requirement I basically need a state boundary map of India which I can put into a Shiny interactive RMarkdown report and fill state colors based on a factor variable. Is there some work-around for the data that I can use?
Ask: I'm not sure what to do or how to further diagnose. I'd appreciate any help that I can get and happy to provide any more info if that would be helpful. I'm also linking the exact RDS file that I'm using for you to load and try on your machine.
Update
None of the suggested solutions worked on my system but I think this challenge I was having was systems specific. I ultimately tried running the same code on a remote Windows instance on Amazon web services and there the code worked fine. So I am not sure whether it was a Mac issue or a hardware issue, but I hope this update is helpful.
I've had this problem on my mac for a while and when searching for solutions, found this on R Bloggers. The code simplifies a shapefile enabling it to plot much more easily:
library("shapefiles")
map = readOGR(dsn = "shp", layer = "shp")
for(i in 1:length(map#polygons)){
for(j in 1:length(map#polygons[[i]]#Polygons)){
temp <- as.data.frame(map#polygons[[i]]#Polygons[[j]]#coords)
names(temp) <- c("x", "y")
temp2 <- dp(temp, 0.01)
map#polygons[[i]]#Polygons[[j]]#coords <- as.matrix(cbind(temp2$x, temp2$y))
}
}
plot(map, col = "black")
(http://www.r-bloggers.com/simplifying-polygon-shapefiles-in-r/).
However, although this can help the plotting process, it becomes troublesome to try and perform GIS operations on the new shapefile due to its simplified form.
It is worth looking for country shapefiles from sites other than GADM. For example, all the shapefiles I have used from this site plot effortlessly and instantly on my mac: http://mapeastafrica.com/countries/east-africa-shapefiles/.

Google Maps vs. ggplot2/MarMap

Below is a JavaScript page I have created that allows me add and freely move markers on the map. From this map I can figure out the regions I am interested in.
Basically what I want to do is show the same map using ggplot2/MarMap with coastline indicators + bathymetry data. I am really just interested in getting bathymetry data per GPS location, basically getting negative/positive elevation per Lat+Long, so I was thinking if I can plot it then I should be able to export data to a Database. I am also interested in coastline data, so I want to know how close I am (Lat/Long) to coastline, so with plot data I was also going to augment in DB.
Here is the R script that I am using:
library(marmap);
library(ggplot2);
a_lon1 = -79.89836596313478;
a_lon2 = -79.97179329675288;
a_lat1 = 32.76506070891712;
a_lat2 = 32.803624214389615;
dat <- getNOAA.bathy(a_lon1,a_lon2,a_lat1,a_lat2, keep=FALSE);
autoplot(dat, geom=c("r", "c"), colour="white", size=0.1) + scale_fill_etopo();
Here is the output of above R script:
Questions:
Why do both images not match?
In google-maps I am using zoom value 13. How does that translate in ggplot2/MarMap?
Is it possible to zoom in ggplot2/MarMap into a (Lat/Long)-(Lat/Long) region?
Is it possible to plot what I am asking for?
I don't know how you got this result. When I use your script, I get an error since the area your are trying to fetch from the ETOPO1 database using getNOAA.bathy() is too small. However, adding resolution=1 (this gives the highest possible resolution for the ETOPO1 database), here is what I get:
To answer your questions:
Why do both images not match?
Probably because getNOAA.bathy() returned an error and the object dat you're using has been created before, using another set of coordinates
In google-maps I am using zoom value 13. How does that translate in ggplot2/MarMap?
I have no clue!
Is it possible to zoom in ggplot2/MarMap into a (Lat/Long)-(Lat/Long) region?
I urge you to take a look at section 4 of the marmap-DataAnalysis vignette. This section is dedicated to working with big files. You will find there that you can zoom in any area of a bathy object by using (for instance) the subsetBathy() function that will allow you to click on a map to define the desired area
Is it possible to plot what I am asking for? Yes, but it would be much easier to use base graphics and not ggplot2. Once again, you should read the package vignettes.
Finally, regarding the coastline data, you can use the dist2isobath() function to compute the distance between any gps point and any isobath, including the coastline. Guess where you can learn more about this function and how to use it...

Wrong output size when plotting over an image in R

My goal is to read an image file in either the PNG or JPEG format and plot various data over said image and save it to disk.
I also want the image to take up all available space in the produced plot, no axes or labels or anything. I'm a bit concerned that this might be relevant to my problem.
Code example
Below is my current code that currently only tries to output the same image as you put in. Later I plan on plotting data points corresponding to coordinates over the image. I've used some sample code found here in order to remove the axes and be able to have the image in the background of the plot.
library(jpeg)
library(grid)
img <- readJPEG(system.file("img", "Rlogo.jpg", package="jpeg"),native=TRUE)
jpeg(filename = "Rlogo-2.jpg", width=100,height=76, quality = 100,res=299)
op<-par(mar=rep(0,4))
plot(0:100,type="n", axes="FALSE",ann="FALSE")
lim <- par()
rasterImage(img, lim$usr[1], lim$usr[3], lim$usr[2], lim$usr[4])
dev.off()
Example output
This is an example output of my above code in a comparison with the original image:
The image to the left is the original and the right one is the modified one. As you can see it seems as if the image I read and plot somehow is smaller than the original image and when saved to the original dimensions it appears blurred.
I've been pulling my hair over this one for hours and I don't seem to get anywhere. This is my first attempt to plot data over images and I'm aware of my lack of knowledge about how R represents images and I've mostly been using the basic graphics to do relatively simple plots before.
I'm currently considering doing this in Python instead but I'm afraid that'll come back and bite me when it comes to the actual plotting of the data.
I run R version 3.1.0 on x86_64 running Windows 7.
Just to summarize, since you already found the culprit, there are two issues present here:
Firstly, the blurring appears to be caused by the jpeg device on Windows. There is no such problem on Ubuntu Linux and it disappears if you use the Cairo-device instead, as you did already discover. Cairo-devices are great for pdf:s too since they embed all the fonts etc. making the figure look the same across platforms.
Secondly, R adds 4% extra margin to the x and y axes by default to prevent graphics from being chopped off near the edge of the plot area. It can be corrected by setting xaxs="i" and yaxs="i".
par(mfrow=1:2)
plot(1:5, 1:5) # Left
plot(1:5, 1:5, xaxs="i", yaxs="i") # Right
In your case the difference is subtle but still would cause everything to be slightly misaligned.

where could we get such a landscape GIS layer

Here, I found a landscape GIS layer is really attractive, especially for presenting species/samples distributions. I would like to know if it can be reached in R or any other resources?
The GIS layer were used in Fig 1. in this article (http://onlinelibrary.wiley.com/doi/10.1111/j.1469-8137.2010.03479.x/full).
This Fig 1 image is here:
http://onlinelibrary.wiley.com/store/10.1111/j.1469-8137.2010.03479.x/asset/image_t/NPH_3479_f1_thumb.gif?v=1&t=gsk5sbhs&s=e5e2e4bbb194f799f7ab9bec85a416e295405784
I have ever tried to submit this question in R-sig-geo. But, I failed. I expect to get some helps/directions here.
Thanks a lots for any directions.
Best wishes,
It is very possible to download this file and read it in with R, configure it to have the correct geo-coordinates so that overplotting works easily, and showing the image with the right colour scheme and so on. But, automating getting all of the data you need is not so easy.
You need the colour table from the GIF file so that you can plot the correct set of RGB values for each pixel (the information is in the file, but I'm not sure if this can be obtained directly with R, I will check - it certainly can be with GDAL, but extracting those values in an automated way depends on various tools being available).
UPDATE: It turns out that the raster package gets hold of the colour information correctly and plots it, see below.
You also need the geo-spatial information, i.e. the coordinates of a reference pixel (say, the top left pixel corner), and the scale (the geographic width and height of the pixels) and this information is not stored in the file. Also, the coordinate system of the file is not in the file, and very likely not provided explicitly with the image data.
If the colours and the coordinate system were stored with the file, then it would all be easy and something like the following would be enough.
(Note this worked for me once, but then I think subsequent requests are blocked by the server, so try to only download the file one time).
u <- "http://onlinelibrary.wiley.com/store/10.1111/j.1469-8137.2010.03479.x/asset/image_n/NPH_3479_f1.gif?v=1&t=gskxvi17&s=0f13fa9dae78bd6837aeee594065c6ca112864d2"
imfile <- paste(tempfile(), ".gif", sep = "")
download.file(u, imfile, mode = "wb")
library(raster) ## rgdal also required for this file format
library(rgdal)
im <- raster(imfile)
plot(im)
This looks fine but now see that there is no "real-world" coordinate system, this is just an axis from pixel 1 to the number in the X dimension (and same for Y).
axis(1, pos = 2)
So, still we need manually work to discover appropriate reference coordinates for the image - and guesses here can work fine, but still they are only guesses and you may end up creating a lot of pain for something seemingly simple.
If plot points interactively is enough for you, then you might use locator in conjunction with points and lines and text, and related plotting functions.
Feng,
if I read the Google docs correctly, you can modify the labels and displayed features with the extra parameters style and element.
I did not include custom parameters for these in the RgoogleMaps package, however, you can easily pass ANY addition parameters via the path argument !
If you read the help file for GetMap carefully, you will note the following example:
note that since the path string is just appended to the URL you can "abuse" the path argument to pass anything to the query, e.g. the style parameter:
#The following example displays a map of Brooklyn where local roads have been changed to bright green and the residential areas have been changed to black:
## Not run: GetMap(center='Brooklyn', zoom=12, maptype = "roadmap", path = "&style=feature:road.local|element:geometry|hue:0x00ff00|saturation:100&style=feature:landscape|element:geometry|lightness:-100", sensor='false', destfile = "MyTile4.png", RETURNIMAGE = FALSE);
Hope this helps,
Markus Loecher
If you just want data like this image, then there are packages to access imagery directly, again utilizing the tools in sp and rgdal. This example is close using gmap in the dismo package.
library(dismo)
e <- extent(-7, 5, 38, 44)
gm <- gmap(e, type = "terrain")
plot(gm)
Note that while we specify the extents in "longlat" the image comes back in its native (Google) Mercator.
print(gm)
See ?gmap for more options on transforming your own data to match the image's projection, or the broader function set in raster, rgdal and sp for other options. There are other imagery providers that might be preferable, and quite a few options in the R suite of contributed packages.

Resources