Can't limit boundaries of a plotted shapefile properly - r

I can't really set the boundaries of my plotted shapefile. I'm plotting the shapefile first to get nice x- and y- labels in degrees first, plotting the data afterwards. In the end, I'm plotting my shapefile over the data again. ylim is changeable, but xlim seems to be solely dependend on ylim changes, because I cant vary xlim itself. It only varies, when I change ylim without changing xlim, like as it is an aspect ratio issue.
I want to limit the x-axis between 8.5 and 11.5 degrees.
A link to the shapefile and raster in question: https://www.dropbox.com/sh/l42mty01mwtm8qc/AADqjNbGkmNwx3o9aFceGrkya?dl=0
My code:
library(rgeos)
library(rgdal)
library(raster)
Sys.setlocale(category = "LC_ALL", locale = "C") # In the case German Umlauts are a problem while reading the shapefile
map <- readOGR("C:\\Path\\NATRAUM_MR_utm32.shp")
# Exclude unnecessary regions
map <- subset(map, NATREGNR != 3)
map <- subset(map, NATREGNR != 4)
map <- subset(map, NATREGNR != 9)
map_wgs84 <- spTransform(map, crs(raster.percent.change.rcp85.1971_2005.2071_2100))
# Pixelplot
par(mar = c(3, 3, 2, 1)) # For saving pictures through a device like pdf
m <- plot(map_wgs84, axes=TRUE, xlim = c(8.5, 11.5), ylim=c(51.35, 53.15), cex = .5,
bty = "n")
# Colortable for legend
colTab <- c("#0033CC", "#3366FF", "#6699FF","#99FFFF", "#FFCC99","#FF9933", "#FF4D00","#660000")
N <- length(colTab)
breaks <- seq(-2, 2, length.out= N+1 )
plot(raster.percent.change.rcp85.1971_2005.2071_2100, col = colTab, breaks = breaks,
axis.args = list(cex.axis = 1, at = breaks, labels = breaks, mgp = c(1, 0, 0), tck = 0.1),
legend.args = list(text='Change [%]', side=4, font=2, line=1.75, cex=0.7),
add = TRUE
)
plot(map_wgs84, add = TRUE) # Plotting shapefile over data

You need to resize your plotting window. You can use par(fin=c(x,y)), or png() to set a ratio that works, and fix that in code.
This is because for maps, the correct aspect (ratio of vertical and horizontal extent) is enforced. For planar data the aspect is 1. For angular data (longitude/latitude) it varies by latitude.
With some data.
library(raster)
p <- shapefile(system.file("external/lux.shp", package="raster"))
Compare:
par(fin=c(6,6))
plot(p, axes=T, xlim=c(6,6.2), ylim=c(49.6, 49.8))
par(fin=c(4, 6))
plot(p, axes=T, xlim=c(6,6.2), ylim=c(49.6, 49.8))

Related

Too many legend items making it impossible to read

I have a SpatialPolygonsDataFrame with 213 Ecoregions to plot.
My issue is that I'm not able to organize the legend in a way that I could indeed read the legend. I'm new to r and I've been trying this for 2 days now, I feel really stupid... I wonder if anyone could give me some hint on how to achieve this goal.
#### Download and unzip ecoregions ####
#the reference for this ecoregions data: https://doi.org/10.1093/biosci/bix014
#Don't forget to change the path to a path of your own
dir_eco<-"C:/Users/thai/Desktop/Ecologicos/w2"
download.file("https://storage.googleapis.com/teow2016/Ecoregions2017.zip",
file.path(paste0(dir_eco,"/","Ecoregions2017.zip",sep="")))
unzip("Ecoregions2017.zip")
#Read this shapefile
#install.packages("rgdal")
library(rgdal)
ecoreg_shp<- readOGR("Ecoregions2017.shp")
#Crop to a smaller extent
xmin=-120; xmax=-35; ymin=-60; ymin2=-40; ymax=35
limits2 <- c(xmin, xmax, ymin2, ymax) # Just from mexico to Uruguay.
ecoreg_shp<-crop(ecoreg_shp,limits2)
# Color palette - one color for each attribute level
n <- 213
color = grDevices::colors()[grep('gr(a|e)y', grDevices::colors(), invert = T)]
# pie(rep(1,n), col=sample(color, n)) #just to take a look at the colors
col_samp<-sample(color, n)
ecoreg_shp#data$COLOR<-col_samp #put the colors in the polygons data frame
#Plot
png(file="29_ecoreg2.png", width=3000, height=3000, units="px", res=300)
par(mar=c(50,0.3,1.5,0),pty="s")
spplot(ecoreg_shp, zcol = "ECO_NAME", col.regions = ecoreg_shp#data$COLOR,
colorkey = list(space = "bottom", height = 1))
dev.off()
Now, this is how this plot looks like:
I've managed to put this legend at the right of the map, but gets also too overlayed... I've tried to do colorkey = FALSE and set a separate legend...
#Plot the map with no legend
spplot(ecoreg_shp, zcol = "ECO_NAME", col.regions = ecoreg_shp#data$COLOR,
colorkey = FALSE)
#Now, just the legend
legend("bottom",legend=ecoreg_shp#data$ECO_NAME,fill=ecoreg_shp#data$COLOR, ncol=3)
But doesn't work.. I get a message that plot.new has not been called yet
I've managed to do a lot of things with the legend, but I can't make it good... Like the legend item below the map in 2 or 3 columns in a long figure... Actually doesn't matter the format at all, I just wanted to be able to make a good figure. Can anyone point me in some direction? I'm trying to learn ggplot2, but I don't know r enough yet for using such a difficult package.
Thank you in advance, any tip is much appreciated.
As said in the comments, you will not really be able to distinguish between colors. You should define a classification with multiple levels and choose similar colors for similar ecoregions.
Nevertheless, you can create an image only for this long legend as follows. I used a reproducible example as I do not have your dataset but I use the same names as yours so that you can directly use the script:
library(sp)
library(rgdal)
n <- 213
dsn <- system.file("vectors", package = "rgdal")[1]
ecoreg_shp <- readOGR(dsn = dsn, layer = "cities")
ecoreg_shp <- ecoreg_shp[1:n,]
# Color palette - one color for each attribute level
color <- grDevices::colors()[grep('gr(a|e)y', grDevices::colors(), invert = T)]
col_samp <- sample(color, n)
ecoreg_shp#data$COLOR <- col_samp #put the colors in the polygons data frame
ecoreg_shp#data$ECO_NAME <- ecoreg_shp#data$NAME
# Define a grid to plot the legend
grid.dim <- c(45, 5)
ecoreg_shp#data$ROW <- rep(rev(1:grid.dim[1]), by = grid.dim[2], length.out = n)
ecoreg_shp#data$COL <- rep(1:grid.dim[2], each = grid.dim[1], length.out = n)
# Plot the legend
png(file = "legend.png",
width = 21, height = 29.7,
units = "cm", res = 300)
par(mai = c(0, 0, 0, 0))
plot(ecoreg_shp#data$COL,
ecoreg_shp#data$ROW,
pch = 22, cex = 2,
bg = ecoreg_shp#data$COLOR,
xlim = c(0.8, grid.dim[2] + 1),
xaxs = "i")
text(ecoreg_shp#data$COL,
ecoreg_shp#data$ROW,
ecoreg_shp#data$ECO_NAME,
pos = 4, cex = 0.75)
dev.off()
The result:

R: plot circular histograms/rose diagrams on map

I am trying to plot rose diagrams/ circular histograms on specific coordinates on a map analogous to drawing pie charts on a map as in the package mapplots.
Below is an example generated with mapplots (see below for code), I'd like to replace the pie charts with rose diagrams
The package circular lets me plot the rose diagrams, but I am unable to integrate it with the mapplots package. Any suggestions for alternative packages or code to achieve this?
In response to the question for the code to make the map. It's all based on the mapplots package. I downloaded a shapefile for the map (I think from http://www.freegisdata.org/)
library(mapplots)
library(shapefiles)
xlim = c(-180, 180)
ylim = c(-90, 90)
#load shapefile
wmap = read.shapefile ("xxx")
# define x,y,z for pies
x <- c(-100, 100)
y <- c(50, -50)
z1 <- c(0.25, 0.25, 0.5)
z2 <- c(0.5, 0.2, 0.3)
z <- rbind(z1,z2)
# define radii of the pies
r <- c(5, 10)
# it's easier to have all data in a single df
plot(NA, xlim = xlim, ylim = ylim, cex = 0.75, xlab = NA, ylab = NA)
draw.shape(wmap, col = "grey", border = "NA")
draw.pie(x,y,z,radius = r, col=c("blue", "yellow", "red"))
legend.pie (x = -160, y = -70, labels = c("0", "1", "2"), radius = 5,
bty = "n", cex = 0.5, label.dist=1.5, col = c("blue", "yellow", "red"))
the legend for the pie size can then be added using legend.bubble
Have a look at this example, you can use the map as background an plot your rose diagrams withPlotrix or ggplot2. In either case you would want to overlay multiple of these diagrams on top of your map which is easy to do in ggplot, just have a look at the example.
I discovered subplot() in the package Hmisc, which seems to do exactly what I wanted. Below is my solution (without the map in the background, which can be plotted using mapplots). I am open to suggestions on how to improve this though...
library(Hmisc)
library (circular)
dat <- data.frame(replicate(2,sample(0:360,10,rep=TRUE)))
lat <- c(50, -40)
lon <- c(-100, 20)
# convert to class circular
cir.dat <- as.circular (dat, type ='angles', units = 'degrees', template = 'geographic', modulo = 'asis', zero = 'pi/2', rotation = 'clock')
# function for subplot, plots relative frequencies, see rose.diag for how to adjust the plot
sub.rose <- function(x){
nu <- sum(!is.na(x))
de <- max(hist(x, breaks = (seq(0, 360, 30)), plot = FALSE)$counts)
prop <- nu/de
rose.diag(x, bins = 12, ticks = FALSE, axes = FALSE,
radii.scale = 'linear',
border = NA,
prop = prop,
col = 'black'
)
}
plot(NA, xlim = xlim, ylim = ylim)
for(i in 1:length(lat)){
subplot(sub.rose(cir.dat[,i]), x = lon[i], y = lat[i], size = c(1, 1))
}

Vertical Histogram

I'd like to do a vertical histogram. Ideally I should be able to put multiple on a single plot per day.
If this could be combined with quantmod experimental chart_Series or some other library capable of drawing bars for a time series that would be great. Please see the attached screenshot. Ideally I could plot something like this.
Is there anything built in or existing libraries that can help with this?
I wrote something a year or so ago to do vertical histograms in base graphics. Here it is, with a usage example.
VerticalHist <- function(x, xscale = NULL, xwidth, hist,
fillCol = "gray80", lineCol = "gray40") {
## x (required) is the x position to draw the histogram
## xscale (optional) is the "height" of the tallest bar (horizontally),
## it has sensible default behavior
## xwidth (required) is the horizontal spacing between histograms
## hist (required) is an object of type "histogram"
## (or a list / df with $breaks and $density)
## fillCol and lineCol... exactly what you think.
binWidth <- hist$breaks[2] - hist$breaks[1]
if (is.null(xscale)) xscale <- xwidth * 0.90 / max(hist$density)
n <- length(hist$density)
x.l <- rep(x, n)
x.r <- x.l + hist$density * xscale
y.b <- hist$breaks[1:n]
y.t <- hist$breaks[2:(n + 1)]
rect(xleft = x.l, ybottom = y.b, xright = x.r, ytop = y.t,
col = fillCol, border = lineCol)
}
## Usage example
require(plyr) ## Just needed for the round_any() in this example
n <- 1000
numberOfHists <- 4
data <- data.frame(ReleaseDOY = rnorm(n, 110, 20),
bin = as.factor(rep(c(1, 2, 3, 4), n / 4)))
binWidth <- 1
binStarts <- c(1, 2, 3, 4)
binMids <- binStarts + binWidth / 2
axisCol <- "gray80"
## Data handling
DOYrange <- range(data$ReleaseDOY)
DOYrange <- c(round_any(DOYrange[1], 15, floor),
round_any(DOYrange[2], 15, ceiling))
## Get the histogram obects
histList <- with(data, tapply(ReleaseDOY, bin, hist, plot = FALSE,
breaks = seq(DOYrange[1], DOYrange[2], by = 5)))
DOYmean <- with(data, tapply(ReleaseDOY, bin, mean))
## Plotting
par(mar = c(5, 5, 1, 1) + .1)
plot(c(0, 5), DOYrange, type = "n",
ann = FALSE, axes = FALSE, xaxs = "i", yaxs = "i")
axis(1, cex.axis = 1.2, col = axisCol)
mtext(side = 1, outer = F, line = 3, "Length at tagging (mm)",
cex = 1.2)
axis(2, cex.axis = 1.2, las = 1, line = -.7, col = "white",
at = c(75, 107, 138, 169),
labels = c("March", "April", "May", "June"), tck = 0)
mtext(side = 2, outer = F, line = 3.5, "Date tagged", cex = 1.2)
box(bty = "L", col = axisCol)
## Gridlines
abline(h = c(60, 92, 123, 154, 184), col = "gray80")
biggestDensity <- max(unlist(lapply(histList, function(h){max(h[[4]])})))
xscale <- binWidth * .9 / biggestDensity
## Plot the histograms
for (lengthBin in 1:numberOfHists) {
VerticalHist(binStarts[lengthBin], xscale = xscale,
xwidth = binWidth, histList[[lengthBin]])
}
Violin plots might be close enough to what you want. They are density plots that have been mirrored through one axis, like a hybrid of a boxplot and a density plot. (Much easier to understanding by example than description. :-) )
Here is a simple (somewhat ugly) example of the ggplot2 implementation of them:
library(ggplot2)
library(lubridate)
data(economics) #sample dataset
# calculate year to group by using lubridate's year function
economics$year<-year(economics$date)
# get a subset
subset<-economics[economics$year>2003&economics$year<2007,]
ggplot(subset,aes(x=date,y=unemploy))+
geom_line()+geom_violin(aes(group=year),alpha=0.5)
A prettier example would be:
ggplot(subset,aes(x=date,y=unemploy))+
geom_violin(aes(group=year,colour=year,fill=year),alpha=0.5,
kernel="rectangular")+ # passes to stat_density, makes violin rectangular
geom_line(size=1.5)+ # make the line (wider than normal)
xlab("Year")+ # label one axis
ylab("Unemployment")+ # label the other
theme_bw()+ # make white background on plot
theme(legend.position = "none") # suppress legend
To include ranges instead of or in addition to the line, you would use geom_linerange or geom_pointrange.
If you use grid graphics then you can create rotated viewports whereever you want them and plot to the rotated viewport. You just need a function that will plot using grid graphics into a specified viewport, I would suggest ggplot2 or possibly lattice for this.
In base graphics you could write your own function to plot the rotated histogram (modify the plot.histogram function or just write your own from scratch using rect or other tools). Then you can use the subplot function from the TeachingDemos package to place the plot wherever you want on a larger plot.

r spatial mapping

I am trying to make some nice spatial maps in R. I am trying to understand how to upload the data in case you would like to have a look at them but I have not figured that out (I am sorry for that but being a new user means looking for all these things).
What is my situation. I have a shapefile of the whole USA, I only need some states, and I can select my grid when I plot it (as you see from the code in the plot section).
I also have some yield data (points) which have latitude, longitude and Yield. I have 4 different Yield data which are called ("All Stations", "0.5", "1.0", and "2.0").
I am trying to plot these 4 yields data on the spatial map to have 4 different spatial maps. Which is done.
I have done this by reading on stackoverflow here and there I used bits and pieces to do that, although I have never done it before I was surprised how fast I could advance (Thank you people on StackOverflow!!!).
Can someone help me to understand if my code is correct?
Also, how can I make the legends of the 4 maps a regularr scale? E.g. from 4000 to 9000 with 500 intervals for each of the 4 maps. What I have done is to create a separate text file ("Yield for Legend.txt") which I use to generate the colour scales in the maps and the legends. Is that correct?
Again, your critics are mostly welcome!
Thank you,
David
rm(list=ls())
setwd("C:\\Users\\.....\\Shape File")
library(spatstat)
library(rgdal)
library(shapefiles)
library(maptools)
library(RColorBrewer)
library(classInt)
# read in shapefiles
counties.rg <- readOGR("C:\\Users\\......\\Shape File", "tl_2011_us_county")
Yields <- read.table("Yield.txt", skip=1, header = F)
Yield.g <- as.ppp(Yields, owin( c(-89, -76), c(25, 37)))
## Reading Data for Legend and colouring breaks
Y.LE <- read.table("Yield for Legend.txt", header=F)
Y.L.I <- classIntervals(Y.LE$V1, n=9, style = "quantile")
Y.L.I <- Y.L.I$brks
#select color palette and the number colors (levels of income) to represent on the map
#colors <- brewer.pal(9, "RdYlGn")
colors <- brewer.pal(9, "Greys")
################################################
### Generating MAPS ############################
################################################
#set breaks for the 9 colors
#par(mfrow=c(2,2))
pdf("13 August Spatial Maps.pdf")
# All Points
brks.all <-classIntervals(Yields$V3, n=9, style = "quantile")
brks.all <- brks.all$brks
plot(counties.rg, axes=TRUE, border="grey", xlim = c(-82, -80),
ylim = c(24, 37))
points(Yield.g, cex= 1.1, bg=colors[findInterval(Yields$V3, Y.L.I,all.inside=TRUE)], pch=21)
#add a title
title(paste ("Rainfed Yield (kg/ha)All Stations"))
#add a legend
legend("bottomright", legend=leglabs(round(Y.L.I)), fill=colors, bty="n", cex=0.7 ) #,x.intersp = .5, y.intersp = .5)
# 0.5 Grid
brks.05 <-classIntervals(Yields$V4, n=9, style = "quantile")
brks.05 <- brks.05$brks
plot(counties.rg, axes=TRUE, border="grey", xlim = c(-82, -80),
ylim = c(24, 37))
points(Yield.g, cex= 1.1, bg=colors[findInterval(Yields$V4, Y.L.I,all.inside=TRUE)], pch=21)
#abline(v=GF$V1, col="grey40")
#abline(h=GF$V2, col="grey10", lty="dotted")
#backup
#points(Yield.g, cex= Yields$V4/9000, col=colors[findInterval(Yields$V4, brks.05,all.inside=TRUE)], pch=19)
#add a title
title(paste ("Rainfed Yield (kg/ha)0.5"))
#add a legend
legend("bottomright", legend=leglabs(round(Y.L.I)), fill=colors, bty="n", cex=0.7 ) #,x.intersp = .5, y.intersp = .5)
# 1.0 Grid
brks.1 <-classIntervals(Yields$V5, n=9, style = "quantile")
brks.1 <- brks.1$brks
plot(counties.rg, axes=TRUE, border="grey", xlim = c(-82, -80),
ylim = c(24, 37))
points(Yield.g, cex= 1.1, bg=colors[findInterval(Yields$V5, Y.L.I,all.inside=TRUE)], pch=21)
#abline(v=GO$V1, col="grey40")
#abline(h=GO$V2, col="grey10", lty="dotted")
#add a title
title(paste ("Rainfed Yield (kg/ha)1.0"))
#add a legend
legend("bottomright", legend=leglabs(round(Y.L.I)), fill=colors, bty="n", cex=0.7 ) #,x.intersp = .5, y.intersp = .5)
# 2.0 Grid
brks.2 <-classIntervals(Yields$V6, n=9, style = "quantile")
brks.2 <- brks.2$brks
plot(counties.rg, axes=TRUE, border="grey", xlim = c(-82, -80),
ylim = c(24, 37))
points(Yield.g, cex= 1.1, bg=colors[findInterval(Yields$V6, Y.L.I,all.inside=TRUE)], pch=21)
#abline(v=GG$V1, col="grey40")
#abline(h=GG$V2, col="grey10", lty="dotted")
#add a title
title(paste ("Rainfed Yield (kg/ha)2.0"))
#add a legend
legend("bottomright", legend=leglabs(round(Y.L.I)), fill=colors, bty="n", cex=0.7 ) #,x.intersp = .5, y.intersp = .5)
dev.off()
In response to your specific query about setting the breaks and having your legend match, there is a fairly straightforward fix.
You use the classInterval function with style="quantile" to define your breaks. If you want the maps to show "from 4000 to 9000 with 500 intervals for each of the 4 maps" why not use style="fixed"
brks.all <-classIntervals(Yields$V3, n=10, style = "fixed",
fixedBreaks=seq(from=4000, to=9000, by=500)
brks.all <- brks.all$brks
Note that 4k to 9k by 500's creates 10 intervals by my count and 9 color gradations doesn't often make for a pretty map.
Alternatively, the dataPrecision variable within classInt may also help you get labels and breaks that are closer to what you want, but still based on quantiles (if not uniform across maps)

Axes at minimum extent, no padding, in plots of raster* objects

Is there a way to ensure that the box around a plot matches the raster extents exactly? In the following there is a gap above and below or to the left and right of the raster depending on the device proportions:
require(raster)
r = raster()
r[]= 1
plot(r, xlim=c(xmin(r), xmax(r)), ylim=c(ymin(r), ymax(r)))
One element of the problem with raster objects is that asp=1 to ensure proper display. The following basic scatterplot has the same issue when asp=1:
plot(c(1:10), c(1:10), asp=1)
Try vectorplot(r) from the rasterVis package to see what I want the axes to look like.
EDIT:
Solutions need to play nice with SpatialPoints overlays, not showing points outside the specified raster limits:
require(raster)
require(maptools)
# Raster
r = raster()
r[]= 1
# Spatial points
x = c(-100, 0, 100)
y = c(100, 0, 100)
points = SpatialPoints(data.frame(x,y))
plot(r, xlim=c(xmin(r), xmax(r)), ylim=c(ymin(r), ymax(r)))
plot(points, add=T)
You'd probably do best to go with one of the lattice-based functions for plotting spatial raster objects provided by the raster and rasterVis packages. You discovered one of them in vectorplot(), but spplot() or levelplot() better match your needs in this case.
(The base graphics-based plot() method for "RasterLayer" objects just doesn't allow any easy way for you to set axes with the appropriate aspect ratio. For anyone interested, I go into more detail about why that's so in a section at the bottom of the post.)
As an example of the kind of plot that levelplot() produces:
require(raster)
require(rasterVis)
## Create a raster and a SpatialPoints object.
r <- raster()
r[] <- 1:ncell(r)
SP <- spsample(Spatial(bbox=bbox(r)), 10, type="random")
## Then plot them
levelplot(r, col.regions = rev(terrain.colors(255)), cuts=254, margin=FALSE) +
layer(sp.points(SP, col = "red"))
## Or use this, which produces the same plot.
# spplot(r, scales = list(draw=TRUE),
# col.regions = rev(terrain.colors(255)), cuts=254) +
# layer(sp.points(SP, col = "red"))
Either of these methods may still plot some portion of the symbol representing points that fall just outside of the plotted raster. If you want to avoid that possibility, you can just subset your SpatialPoints object to remove any points falling outside of the raster. Here's a simple function that'll do that for you:
## A function to test whether points fall within a raster's extent
inExtent <- function(SP_obj, r_obj) {
crds <- SP_obj#coord
ext <- extent(r_obj)
crds[,1] >= ext#xmin & crds[,1] <= ext#xmax &
crds[,2] >= ext#ymin & crds[,2] <= ext#ymax
}
## Remove any points in SP that don't fall within the extent of the raster 'r'
SP <- SP[inExtent(SP, r), ]
Additional weedy detail about why it's hard to make plot(r) produce snugly fitting axes
When plot is called on an object of type raster, the raster data is (ultimately) plotted using either rasterImage() or image(). Which path is followed depends on: (a) the type of device being plotted to; and (b) the value of the useRaster argument in the original plot() call.
In either case, the plotting region is set up in a way which produces axes that fill the plotting region, rather than in a way that gives them the appropriate aspect ratio.
Below, I show the chain of functions that's called on the way to this step, as well as the call that ultimately sets up the plotting region. In both cases, there appears to be no simple way to alter both the extent and the aspect ratio of the axes that are plotted.
useRaster=TRUE
## Chain of functions dispatched by `plot(r, useRaster=TRUE)`
getMethod("plot", c("RasterLayer", "missing"))
raster:::.plotraster2
raster:::.rasterImagePlot
## Call within .rasterImagePlot() that sets up the plotting region
plot(NA, NA, xlim = e[1:2], ylim = e[3:4], type = "n",
, xaxs = "i", yaxs = "i", asp = asp, ...)
## Example showing why the above call produces the 'wrong' y-axis limits
plot(c(-180,180), c(-90,90),
xlim = c(-180,180), ylim = c(-90,90), pch = 16,
asp = 1,
main = "plot(r, useRaster=TRUE) -> \nincorrect y-axis limits")
useRaster=FALSE
## Chain of functions dispatched by `plot(r, useRaster=FALSE)`
getMethod("plot", c("RasterLayer", "missing"))
raster:::.plotraster2
raster:::.imageplot
image.default
## Call within image.default() that sets up the plotting region
plot(NA, NA, xlim = xlim, ylim = ylim, type = "n", xaxs = xaxs,
yaxs = yaxs, xlab = xlab, ylab = ylab, ...)
## Example showing that the above call produces the wrong aspect ratio
plot(c(-180,180), c(-90,90),
xlim = c(-180,180), ylim = c(-90,90), pch = 16,
main = "plot(r,useRaster=FALSE) -> \nincorrect aspect ratio")
Man, I got stumped and ended up just turning the foreground color off to plot. Then you can take advantage of the fact that the raster plot method calls fields:::image.plot, which lets you just plot the legend (a second time, this time showing the ink!). This is inelegant, but worked in this case:
par("fg" = NA)
plot(r, xlim = c(xmin(r), xmax(r)), ylim = c(ymin(r), ymax(r)), axes = FALSE)
par(new = TRUE,"fg" = "black")
plot(r, xlim = c(xmin(r), xmax(r)), ylim = c(ymin(r), ymax(r)), axes = FALSE, legend.only = TRUE)
axis(1, pos = -90, xpd = TRUE)
rect(-180,-90,180,90,xpd = TRUE)
ticks <- (ymin(r):ymax(r))[(ymin(r):ymax(r)) %% 20 == 0]
segments(xmin(r),ticks,xmin(r)-5,ticks, xpd = TRUE)
text(xmin(r),ticks,ticks,xpd=TRUE,pos=2)
title("sorry, this could probably be done in some more elegant way")
This is way I solved this problem
require(raster)
r = raster()
# default for raster is 180 row by 360 cols = 64800 cells
# fill with some values to make more interesting
r[]= runif(64800, 1, 1000)
# Set margin for text
par(mar=c(2, 6, 6, 2))
# Set some controls for the raster cell colours and legend
MyBrks<-c(0,1,4,16,64,256,1E20)
MyLbls<-c("<1","<4","<16","<64","<256","<Max")
MyClrs<-c("blue","cyan","yellow","pink","purple","red")
# Plot raster without axes or box or legend
# Note xlim and ylim don't seem do much unless you want to trim x and y
plot(r,
col=MyClrs,
axes=FALSE,
box=FALSE,
legend=FALSE
)
# Set up the ranges and intervals for axes - you can get the min max
# using xmin(r) and ymax(r) and so on if you like
MyXFrm <- -180
MyXTo <- 180
MyXStp <- 60
MyYFrm <- -90
MyYTo <- 90
MyYStp <- 30
# Plot the axes
axis(1,tick=TRUE,pos=ymin(r),las=1,at=seq(MyXFrm,MyXTo ,MyXStp ))
axis(2,tick=TRUE,pos=xmin(r),las=1,at=seq(MyYFrm ,MyYTo ,MyYStp ))
# Plot the legend use xpd to plot the legend outside the plot region
par(xpd=TRUE)
legend(MyXTo ,MyYTo ,
legend=MyLbls[1:6],
col= MyClrs,
fill=Clrs[1:6],
bg=rgb(0,0,0,0.85),
cex=0.9,
text.col="white",
text.font=2,
border=NA
)
# Add some axis labels and a title
text(-220,0,"Y",font=2)
text(0,-130,"X",font=2)
text(0,120,"My Raster",font=4,cex=1.5)
I think the best (or simplest) solution is to use image():
library(raster)
# Raster
r = raster()
r[]= rnorm(ncell(r))
# Spatial points
x = c(-100, 0, 100)
y = c(100, 0, 100)
points = SpatialPoints(data.frame(x,y))
# plot
image(r)
plot(points, add=T, pch=16, cex=2)

Resources