R ggplot2 -- Set z axis limit in stat_contour plot - r

In ggplot2 x and y axis limits can be specified using a shorthand approach (xlim(0, 1)) or a more structured approach (scale_x_continuous(limits = c(0, 1))). How do I do this for the z axis in a contour plot?
Reproducible example:
library(ggplot2)
library(akima)
x <- runif(40)
y <- runif(40)
z <- runif(40, min = 0.5, max = 1)
fld <- interp(x = x,
y = y,
z = z,
xo = seq(min(x), max(x), length = 40),
duplicate = 'mean')
gdat <- interp2xyz(fld, data.frame = TRUE)
ggplot(gdat, aes(x = x, y = y, z = z)) +
geom_tile(aes(fill = z)) +
stat_contour(aes(fill = ..level..), geom = 'polygon', binwidth = 0.005) +
geom_contour(colour = 'white', alpha = 0.5) +
scale_fill_gradient(low = 'white', high = 'red') +
theme_bw()
In this example, I artificially constrained the z axis to range from 0.5 to 1. However, I would like to plot it so that the white colour gradient begins at 0 instead of 0.5. Any suggestions on how to do this?

Related

Fill area below geom_curve in ggplot

This is my code:
ggplot(data = tibble(x = 1:20, y = 1:20),
aes(x = x, y = y)) +
geom_curve(x = 10, y = 7.55, xend = 15, yend = 7.6,
curvature = .28, size = .7250, color ='black')+
geom_point()
How can I fill the area below this curve? Between x = 10 and x = 12 and considering the ymax being the curve.
I don't know how to extract geom_curve's internal data produced during rendering, but here's a method:
gg <- ggplot(data = tibble(x = 1:20, y = 1:20),
aes(x = x, y = y)) +
geom_curve(x = 10, y = 7.55, xend = 15, yend = 7.6,
curvature = .28, size = .7250, color ='black')+
geom_point()
We'll produce a curve on our own. I'm using 51 here just to get many points; you may want fewer or more depending on the size of your curve and the resolution of your eventual plot.
curvedat <- data.frame(x = seq(10, 15, len = 51))
curvedat$y <- with(curvedat, 4 + 5*abs((x - 10) / 5 - 0.5)^2)
gg + geom_path(data = curvedat)
(The two curves are shown together here in order to demonstrate their similarity. There's no assumption of maintaining the original curve in the plot. Also, the second curve is shown offset down, I'm assuming you would address that in your suitability decision.)
Once you have a curve that looks okay, then wrap two "low" points around it and add as a polygon:
gg +
geom_polygon(data = rbind(
data.frame(x = min(curvedat$x), y = -Inf),
curvedat,
data.frame(x = max(curvedat$x), y = -Inf)
))

ggplot2 geom_errorbar with different linetype but with solid whiskers

I am making errorbar plot with different linetype
library(ggplot2)
library(plyr)
# Create dataset:
DF <- data.frame(
group = rep(c("a", "b", "c", "d"),each=10),
Ydata = c(seq(1,10,1),seq(5,50,5),seq(20,11,-1),seq(0.3,3,0.3)),
Xdata = c(seq(1,10,1),seq(5,50,5),seq(20,11,-1),seq(0.3,3,0.3)))
# Summarise data:
subDF <- ddply(DF, .(group), summarise,
X = mean(Xdata), Y = mean(Ydata),
X_sd = sd(Xdata, na.rm = T), Y_sd = sd(Ydata))
# Plot data with error bars:
ggplot(subDF, aes(x = X, y = Y,linetype = group)) +
geom_errorbar(aes(x = X,
ymin = (Y-Y_sd),
ymax = (Y+Y_sd)),
width = 1, size = 0.5) +
geom_point(cex = 3) +
scale_linetype_manual(values = c("solid","twodash","longdash","longdash"))
This give me the following plot, but I want the end whiskers to be solid. Anyone could help?
One option to achieve your desired result would be to switch to geom_linerange and add the whiskers via geom_segment like so:
library(ggplot2)
width <- .3
# Plot data with error bars:
ggplot(subDF, aes(x = X, y = Y, linetype = group)) +
geom_segment(aes(
x = X - width, xend = X + width,
y = Y - Y_sd, yend = Y - Y_sd
),
size = 0.5, linetype = "solid"
) +
geom_segment(aes(
x = X - width, xend = X + width,
y = Y + Y_sd, yend = Y + Y_sd
),
size = 0.5, linetype = "solid"
) +
geom_linerange(aes(
x = X,
ymin = (Y - Y_sd),
ymax = (Y + Y_sd)
),
size = 0.5
) +
geom_point(cex = 3) +
scale_linetype_manual(values = c("solid", "twodash", "longdash", "longdash"))

Creating a vertical color gradient for a geom_bar plot

I have searched and searched, but I cant seem to find an elegant way of doing this!
I have a dataset Data consisting of Data$x (dates) and Data$y (numbers from 0 to 1)
I want to plot them in a bar-chart:
ggplot(Data) + geom_bar(aes(x = x, y = y, fill = y, stat = "identity")) +
scale_fill_gradient2(low = "red", high = "green", mid = "yellow", midpoint = 0.90)
The result looks like this
However, I wanted to give each bar a gradient in the vertical direction ranging from 0 (red) to y (greener depending on y). Is there any way of doing this smoothly?
I have tried to see if I could impose a picture on the graph as a hack, but I can't impose it on the bars only except in a super super ugly way.
Another, not very pretty, hack using geom_segment. The x start and end positions (x and xend) are hardcoded (- 0.4; + 0.4), so is the size. These numbers needs to be adjusted depending on the number of x values and range of y.
# some toy data
d <- data.frame(x = 1:3, y = 1:3)
# interpolate values from zero to y and create corresponding number of x values
vals <- lapply(d$y, function(y) seq(0, y, by = 0.01))
y <- unlist(vals)
mid <- rep(d$x, lengths(vals))
d2 <- data.frame(x = mid - 0.4,
xend = mid + 0.4,
y = y,
yend = y)
ggplot(data = d2, aes(x = x, xend = xend, y = y, yend = yend, color = y)) +
geom_segment(size = 2) +
scale_color_gradient2(low = "red", mid = "yellow", high = "green",
midpoint = max(d2$y)/2)
A somewhat related question which may give you some other ideas: How to make gradient color filled timeseries plot in R
Doesn't exist as far as I know, but you can manipulate your data to produce it.
library(ggplot2)
df = data.frame(x=c(1:10),y=runif(10))
prepGradient <- function(x,y,spacing=max(y)/100){
stopifnot(length(x)==length(y))
df <- data.frame(x=x,y=y)
newDf = data.frame(x=NULL,y=NULL,z=NULL)
for (r in 1:nrow(df)){
n <- floor(df[r,"y"]/spacing)
for (s in c(1:n)){
tmp <- data.frame(x=df[r,"x"],y=spacing,z=s*spacing)
newDf <- rbind(newDf,tmp)
}
tmp <- data.frame(x=df[r,"x"],y=df[r,"y"]%%spacing,z=df[r,"y"])
newDf <- rbind(newDf,tmp)
}
return(newDf)
}
df2 <- prepGradient(df$x,df$y)
ggplot(df2,aes(x=x,y=y,fill=z)) +
geom_bar(stat="identity") +
scale_fill_gradient2(low="red", high="green", mid="yellow",midpoint=median(df$y))+
ggtitle('Vertical Gradient Example') +
theme_minimal()
Found a less hacky way to do this when answering Change ggplot bar chart fill colors
library(tidyverse)
df <- data.frame(value = c(20, 50, 90),
group = c(1, 2, 3))
df_expanded <- df %>%
rowwise() %>%
summarise(group = group,
value = list(0:value)) %>%
unnest(cols = value)
df_expanded %>%
ggplot() +
geom_tile(aes(
x = group,
y = value,
fill = value,
width = 0.9
)) +
coord_flip() +
scale_fill_viridis_c(option = "C") +
theme(legend.position = "none")
Because this did not explicitly ask for divergent / multi-hue scales (in the title), here a simple hack for a single-hue gradient. This is very much the approach like suggested for a gradient fill under a curve as seen here
library(ggplot2)
d <- data.frame(x = 1:3, y = 1:3)
n_grad <- 1000
grad_df <- data.frame(yintercept = seq(0, 3, len = 200),
alpha = seq(0.3, 0, len = 200))
ggplot(d ) +
geom_col(aes(x, y), fill = "darkblue") +
geom_hline(data = grad_df, aes(yintercept = yintercept, alpha = alpha),
size = 1, colour = "white", show.legend = FALSE) +
## white background looks nicer then
theme_minimal()

operation between stat_summary_hex plots made in ggplot2

I have two populations A and B distributed spatially with one character Z, I want to be able to make an hexbin substracting the proportion of the character in each hexbin. Here I have the code for two theoretical populations A and B
library(hexbin)
library(ggplot2)
set.seed(2)
xA <- rnorm(1000)
set.seed(3)
yA <- rnorm(1000)
set.seed(4)
zA <- sample(c(1, 0), 20, replace = TRUE, prob = c(0.2, 0.8))
hbinA <- hexbin(xA, yA, xbins = 40, IDs = TRUE)
A <- data.frame(x = xA, y = yA, z = zA)
set.seed(5)
xB <- rnorm(1000)
set.seed(6)
yB <- rnorm(1000)
set.seed(7)
zB <- sample(c(1, 0), 20, replace = TRUE, prob = c(0.4, 0.6))
hbinB <- hexbin(xB, yB, xbins = 40, IDs = TRUE)
B <- data.frame(x = xB, y = yB, z = zB)
ggplot(A, aes(x, y, z = z)) + stat_summary_hex(fun = function(z) sum(z)/length(z), alpha = 0.8) +
scale_fill_gradientn(colours = c("blue","red")) +
guides(alpha = FALSE, size = FALSE)
ggplot(B, aes(x, y, z = z)) + stat_summary_hex(fun = function(z) sum(z)/length(z), alpha = 0.8) +
scale_fill_gradientn (colours = c("blue","red")) +
guides(alpha = FALSE, size = FALSE)
here is the two resulting graphs
My goal is to make a third graph with hexbins with the values of the difference between hexbins at the same coordinates but I don't even know how to start to do it, I have done something similar in the raster Package, but I need it as hexbins
Thanks a lot
You need to make sure that both plots use the exact same binning. In order to achieve this, I think it is best to do the binning beforehand and then plot the results with stat_identity / geom_hex. With the variables from your code sample you ca do:
## find the bounds for the complete data
xbnds <- range(c(A$x, B$x))
ybnds <- range(c(A$y, B$y))
nbins <- 30
# function to make a data.frame for geom_hex that can be used with stat_identity
makeHexData <- function(df) {
h <- hexbin(df$x, df$y, nbins, xbnds = xbnds, ybnds = ybnds, IDs = TRUE)
data.frame(hcell2xy(h),
z = tapply(df$z, h#cID, FUN = function(z) sum(z)/length(z)),
cid = h#cell)
}
Ahex <- makeHexData(A)
Bhex <- makeHexData(B)
## not all cells are present in each binning, we need to merge by cellID
byCell <- merge(Ahex, Bhex, by = "cid", all = T)
## when calculating the difference empty cells should count as 0
byCell$z.x[is.na(byCell$z.x)] <- 0
byCell$z.y[is.na(byCell$z.y)] <- 0
## make a "difference" data.frame
Diff <- data.frame(x = ifelse(is.na(byCell$x.x), byCell$x.y, byCell$x.x),
y = ifelse(is.na(byCell$y.x), byCell$y.y, byCell$y.x),
z = byCell$z.x - byCell$z.y)
## plot the results
ggplot(Ahex) +
geom_hex(aes(x = x, y = y, fill = z),
stat = "identity", alpha = 0.8) +
scale_fill_gradientn (colours = c("blue","red")) +
guides(alpha = FALSE, size = FALSE)
ggplot(Bhex) +
geom_hex(aes(x = x, y = y, fill = z),
stat = "identity", alpha = 0.8) +
scale_fill_gradientn (colours = c("blue","red")) +
guides(alpha = FALSE, size = FALSE)
ggplot(Diff) +
geom_hex(aes(x = x, y = y, fill = z),
stat = "identity", alpha = 0.8) +
scale_fill_gradientn (colours = c("blue","red")) +
guides(alpha = FALSE, size = FALSE)

How to adjust the point size to the scale of the plot in ggplot2?

Let's generate some data:
x <- -10*cos(seq(0, pi, length.out = 100))+1
y <- 10*seq(0, pi, length.out = 100)
xerr <- rep(2, 100)
yerr <- rep(2, 100)
dd <- as.data.frame(cbind(x, y, xerr, yerr))
Here I have x and y coordinates of some points with their errors, xerr and yerr (for convenience I have set them constant). I would like to represent these errors with the size of the points. This is easily doable:
ggplot() +
geom_point(data = dd, aes(x, y, size = sqrt(xerr^2 + yerr^2)), colour = "gray") +
geom_path(data = dd, aes(x, y), colour = "red", size = .5) +
scale_size_identity() +
theme_bw()
However, the size of these points is defined on a scale that doesn't have any relation with the scale of the plot. Is there a way to adjust the dimension of the points in relation to the scale of the plot? In the above example, the radius of each point should have size equal to 2.828 and not less than one as it is now.
One way is to explicitly draw ellipses with the axes defined by the size of the errors.
x <- -10*cos(seq(0, pi, length.out = 10))+1
y <- 10*seq(0, pi, length.out = 10)
xerr <- runif(10, 1, 5)
yerr <- runif(10, 1, 5)
dd <- as.data.frame(cbind(x, y, xerr, yerr))
dd$frame <- factor(seq(1:10))
For this purpose we define our function to generate ellipses:
ellipseFun <- function(center = c(0, 0), axes = c(1, 1), npoints = 101){
tt <- seq(0,2*pi, length.out = npoints)
xx <- center[1] + axes[1] * cos(tt)
yy <- center[2] + axes[2] * sin(tt)
return(data.frame(x = xx, y = yy))
}
We then generate the matrices for all ellipses:
ddEll <- data.frame()
for(k in levels(dd$frame)){
ddEll <- rbind(ddEll, cbind(as.data.frame(with(dd[dd$frame == k,], ellipseFun(center = c(x, y), axes = c(xerr, yerr), npoints = 101))),frame = k))
}
And, finally, we can plot them:
library(ggplot2)
ggplot() +
geom_point(data = dd, aes(x, y)) +
geom_polygon(data=ddEll, aes(x = x, y = y, group = frame), colour = "gray", fill = "red", alpha = .2) +
scale_size_identity() +
theme_bw() +
xlim(c(-20, 20)) +
ylim(c(-5, 35)) +
coord_fixed()

Resources