plot raster factor values with ggplot - r

I have problems plotting a raster with factor values using ggplot2.
library(ggplot2)
library(raster)
first, load raster data
f <- system.file("external/test.grd", package="raster")
r <- raster(f)
extract coordinates and values
val <- getValues(r)
xy <- as.data.frame(xyFromCell(r,1:ncell(r)))
xy <- cbind(xy,val)
plot the grid using geom_raster(). Everything works fine.
ggplot(xy, aes(x=x, y=y, fill=val)) + geom_raster() + coord_equal()
I don not have a continuous raster, but a classified. Reclass the raster:
r <- reclass(r, c(0,500,1, 500,2000,2))
val <- getValues(r)
xy <- as.data.frame(xyFromCell(r,1:ncell(r)))
xy <- cbind(xy,val)
plot the classified raster. Also OK, but legend is continuous
ggplot(na.omit(xy), aes(x=x, y=y, fill=val)) + geom_raster() + coord_equal()
if I plot the values as factor, the map becomes wrong
ggplot(na.omit(xy), aes(x=x, y=y, fill=factor(val))) + geom_raster() + coord_equal()

Plotting the reclassified plot works for me using R version 2.15.1, ggplot2_0.9.2.1 and raster_2.0-12. If applicable, try updating R, packages, and dependencies. Proceeding from a slightly modified version of your code:
f <- system.file("external/test.grd", package="raster")
r <- raster(f)
r <- reclassify(r, c(0,500,1, 500,2000,2))
val <- getValues(r)
xy <- as.data.frame(xyFromCell(r,1:ncell(r)))
xy <- cbind(xy,val)
ggplot(na.omit(xy), aes(x=x, y=y, fill=val)) + geom_raster() + coord_equal()
p <- ggplot(na.omit(xy), aes(x=x, y=y, fill=factor(val))) +
geom_raster() +
coord_equal()
try(ggsave(plot=p,<some file>,height=8,width=8))
I get:
Note that classify() has been depreciated and reclassify() is its substitute.

Related

How to plot skewed and normal data in r

Using hypothetical data I want to generate these three plots in one plot.
I wonder how I can do it. Is it possible to do it using ggplot2 or fGarch packages?
Here an approach with ggplot2
library("ggplot2")
x <- 0:100
y <- c(dnorm(x, mean=50, sd=10),
dlnorm(x, meanlog=3, sdlog=.7),
dlnorm(100-x, meanlog=3, sdlog=.7))
df <- data.frame(
x=x,
y=y,
type=rep(c("normal", "right skewed", "left skewed"), each=101)
)
ggplot(df, aes(x, y, color=type)) + geom_line()

ggplot2 - facet_wrap with individual legends

I am using ggplot2 to plot maps that have the same extent (i.e. same spatial coverage) but that show different features.
This is how it looks like:
library(raster)
library(reshape2)
library(ggplot2)
# make-up data
r <- raster(system.file("external/test.grd", package="raster"))
s <- stack(r, r**2, r**3, r**4, r**5)
names(s) <- paste0("Field ",seq(1,5))
# convert to data frame
rast.df <- as.data.frame(s, xy=T)
# melt
rast.melt <- melt(rast.df, id.vars = c('x','y'), variable.name="field")
# plot
ggplot() +
geom_raster(data=rast.melt , aes(x=x, y=y, fill=value)) +
facet_wrap(~field) +
scale_fill_continuous(na.value="transparent")
The resulting figure looks quite crappy because there's one single legend for all the maps. Therefore, the maps have no contrast at all.
How can I use individual legends for each facet in the graph above?
Here's an approach with ggarrange from the ggpubr package:
library(ggpubr)
ggarrange(plotlist = lapply(split(rast.melt, rast.melt$field),function(x){
ggplot() + geom_raster(data=x , aes(x=x, y=y, fill=value)) +
scale_fill_continuous(na.value="transparent") +
ggtitle(x$field[1])}))

How to flip y axis in geom_sf()?

Trying to combine a geom_sf() with some other geoms. I need to reverse the y-axis for the plot to appear correctly. However, geom_sf() seems to ignore scale_y_reverse().
Example:
# install the dev version of ggplot2
devtools::install_github("tidyverse/ggplot2")
library(ggplot2)
library(sf)
library(rgeos)
library(sp)
# make triangle
tmpdf <- data.frame(id = 1,
geom = c("LINESTRING(10 10,-10 10,0 0,10 10)"), stringsAsFactors = F)
# read WKT polygons into 'sp' SpatialPolygons object
tmpdf$spgeom <- lapply(tmpdf$geom, FUN = function(x) readWKT(x))
# extract coordinates from the linestring (there has got to be a better way to do this...)
test <- tmpdf[1,"spgeom"]
test2 <- sapply(test, FUN=function(x) x#lines)
test3 <- sapply(test2, FUN=function(x) x#Lines)
test4 <- lapply(test3, FUN=function(x) x#coords)
# plot the sp coordinates
ggplot() +
geom_point(data=data.frame(test4[[1]]), aes(x,y), color="blue") +
geom_path(data=data.frame(test4[[1]]), aes(x=x, y=y), color="blue") +
coord_fixed()
# make an 'sf' sfc_POLYGON object
tmpdf$sfgeom <- st_as_sfc(tmpdf$geom)
## plot both together, they overlap
ggplot() +
geom_point(data=data.frame(test4[[1]]), aes(x,y), color="blue") +
geom_path(data=data.frame(test4[[1]]), aes(x=x, y=y), color="blue") +
coord_fixed() +
geom_sf(data=tmpdf, aes(geometry=sfgeom), color="red")
plot outputs with warning:
Coordinate system already present. Adding new coordinate system, which
will replace the existing one.
## plot with scale reverse, and everything but the geom_sf flips.
ggplot() +
geom_point(data=data.frame(test4[[1]]), aes(x,y), color="blue") +
geom_path(data=data.frame(test4[[1]]), aes(x=x, y=y), color="blue") +
coord_fixed() +
geom_sf(data=tmpdf, aes(geometry=sfgeom), color="red") +
scale_y_reverse()
plot outputs with warning:
Coordinate system already present. Adding new coordinate system, which
will replace the existing one.
Suggestions for getting the geom_sf y coordinates reversed?
I tried this:
coord_sf(ylim=-(range(st_coordinates(tmpdf$sfgeom)[,"Y"])))
and all that did was change the axis, not the actual geoms.
Aha! Here's a workaround:
## get the geom coordinates as data.frame
geomdf <- st_coordinates(tmpdf$sfgeom)
## reverse Y coords
geomdf[,"Y"] <- geomdf[,"Y"]*-1
## re-create geom
tmpdf$sfgeom2 <- st_as_sfc(st_as_text(st_linestring(geomdf)))
## plot the reversed y-coordinate geom:
ggplot() +
geom_point(data=data.frame(test4[[1]]), aes(x,y), color="blue") +
geom_path(data=data.frame(test4[[1]]), aes(x=x, y=y), color="blue") +
coord_fixed() +
geom_sf(data=tmpdf, aes(geometry=sfgeom2), color="red") +
scale_y_reverse()

Approximate area size by counting pixels in ggplot2

Is it possible to extract the number of pixels of some arbitrary filled area to approximate the size of the area in ggplot2?
Specifically, I am using geom_ribbon to highlight some area in a graph and was wondering if there is some generic way to approximate the corresponding area size (without directly referring to the input data). I was thinking about hidden functions or intermediate data which ggplot2 might produce to color each pixel of the blue area on the screen.
library(ggplot2)
yint <- 5
x <- 1:100
df <- data.frame(x=x, y=x^0.5)
rib <- df[df$y>=yint,]
ggplot(df, aes(x=x)) + geom_line(aes(y=y)) + geom_hline(aes(yintercept=yint)) + geom_ribbon(data=rib, aes(x=x, ymin=yint, ymax=y), fill='lightblue')
EDIT:
Adopting lukeA's first solution, I can simply complete my previous ribbon data to form a closed polygon and then use the Polygon() function on it which automatically also calculates the corresponding area.
library(sp)
pol <- rbind(rib, c(100,5), c(25,5))
Polygon(pol)#area
Here are two approaches - one is polygon/vector based, the other one is pixel/raster based:
library(ggplot2)
library(rgeos)
library(sp)
library(png)
f <- function(x) Polygons(list(Polygon(map_data("world", region = x)[, 1:2])), x)
(tab1 <- gArea(SpatialPolygons(list(f("Germany"), f("France"))), byid=T))
# Germany France
# 41.21485 84.34209
unname(tab1["France"]/tab1["Germany"])
# [1] 2.046401
map <- map_data("world", region=c("Germany", "France"))
p <- ggplot(map, aes(long, lat, group=group, fill=region)) +
geom_polygon() + coord_map() +
theme_minimal() +
scale_fill_manual(values=c("Germany"="#00BFC4", "France"="#F8766D"), guide="none")
ggsave(tf <- tempfile(fileext = ".png"), p, dpi = 90)
r <- as.matrix(as.raster(readPNG(tf)))
(tab2 <- table(r[r %in% c("#F8766D", "#00BFC4")]))
unname(tab2["#F8766D"]/tab2["#00BFC4"])
# 1.2781

cumulative probability plot from frequency table

Is there any way to plot the cumulative probability from a frequency table? I mean a "smooth" version of it, similar to the way geom_density() plots.
So far, I managed to plot the individually calculated probabilities as points joined by lines, but it doesn't look very good.
I generate some test data:
set.seed(1)
x <- sort(sample(1:100, 20))
p <- runif(x); p <- cumsum(p)/sum(p)
table <- data.frame(x=x, prob=p)
You can use geom_smooth from the ggplot2 package.
require("ggplot2")
qplot(x=x, y=p, data=table, aes(ymin=0, ymax=1)) + ylab("ecf") +
geom_smooth(se=F, stat="smooth", method="loess", fullrange=T, fill="lightgrey", size=1)
As an alternative, an easy way to specifiy smoothing by a parameter try DeconCdf from the decon package:
require("decon")
plot(DeconCdf(x, sig=1))
If you want to use ggplot, you first have to transform the Decon function object in a data.frame.
f <- DeconCdf(x, sig=1)
m <- ggplot(data=data.frame(x=f$x, p=f$y), aes(x=x, y=p, ymin=0, ymax=1)) + ylab("ecf")
m + geom_line(size=1)
Use the sig-Parameter as your smoothing parameter:
f <- DeconCdf(x, sig=0.3)
m <- ggplot(data=data.frame(x=f$x, p=f$y), aes(x=x, y=p, ymin=0, ymax=1)) + ylab("ecf")
m + geom_line(size=1)
This version plots a histogram with a smoothed line from geom_density:
# Generate some data:
set.seed(28986)
x2 <- rweibull(100, 1, 1/2)
# Plot the points:
library(ggplot2)
library(scales)
ggplot(data.frame(x=x2),aes(x=x, y=1-cumsum(..count..)/sum(..count..))) +
geom_histogram(aes(fill=..count..)) +
geom_density(fill=NA, color="black", adjust=1/2) +
scale_y_continuous("Percent of units\n(equal to or larger than x)",labels=percent) +
theme_grey(base_size=18)
Note that I've used 1 - "cumulative probability" due to individual preference (I think it looks better and I'm accustomed to dealing with "reliability" metrics), but obviously that's just a preference that you could ignore by removing the 1- part in the aes.

Resources