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
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()
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])}))
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()
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
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.