library(ggplot2)
p <- ggplot(iris,aes(Sepal.Width,Petal.Length))+
geom_line()
p
Imagine that you have a ggplot object and you have no access to the code or data that created this plot. How does one adjust the size/thickness of the plotted line?
I have tried modifying the theme, but that only changes the background lines and not the plotted lines.
p+
theme(line=element_line(size=10))
You can change or add parameters to a specific layer in a ggplot object like this:
p$layers[[1]]$aes_params$size = 2
p
For more complex ggplots, where you don't know which layers are the geom_line layers, you will have to pick out which layers are geom_line layers to rewrite their aesthetic parameters:
geomlines <- which(sapply(p$layers, function(x) class(x$geom)[1] == "GeomLine"))
p$layers[geomlines] <- lapply(p$layers[geomlines], function(x) {
x$aes_params$size <- 2
x
})
p
Related
I am trying to create an annotation (particularly a rectangle) over a ggplot. Here's what I want to get:
I have tried geom_rect but that can only draw inside the plot axis.
I have also attempted to use annotate_custom which this post mentions, but when I try to work with xmin = -3 (for instance), it doesn't work.
Thank you!
I'm gonna start by asking what you are trying to achieve with this? It seems odd, at least in your example.
But, it can be done. Because you did not provide a reproducible example, I've got something else. The goal here is to turn of the panel's clipping, such that elements that lie outside it's boundaries will be plotted.
library(ggplot2)
library(grid)
# Create a plot
p <- ggplot(mtcars, aes(wt, mpg)) + geom_point()
Here, I'm adding a rectangle with rect. But this also modifies the x- and y-axis, so we fix these with coord_cartesian. You cannot use xlim as this will remove data points that fall outside the range.
g <- p + annotate('rect', xmin=-1, xmax=3, ymin=10, ymax=30, fill='blue', alpha=1/3) +
coord_cartesian(xlim=c(1, 4))
# Convert into a graphical object -- a grob
g <- ggplotGrob(g)
# Try printing g
g is an object that puts all the elements into a table-like structure. So now, we find the panel in the layout dataframe of g, and turn of clipping.
i <- which(g$layout$name == 'panel')
g$layout[i,'clip'] <- 'off'
Finally draw the grob:
# grid.newpage()
grid.draw(g)
I'm trying to create a picture with points (actually bars, but whatever) in two distinct colours with parallel saturated-to-unsaturated colour scales, with corresponding colourbar legends. I'm most of the way there, but there are a few minor points I can't handle yet.
tl;dr the color scales I get from a red-to-white gradient and a saturated-red-to-completely-unsaturated gradient are not identical.
Set up data: y will determine both y-axis position and degree of saturation, w will determine binary colour choice.
set.seed(101)
dd <- data.frame(x=1:100,y=rnorm(100))
dd$w <- as.logical(sample(0:1,size=nrow(dd),
replace=TRUE))
Get packages:
library(ggplot2)
library(cowplot)
library(gridExtra)
I can get the plot I want by allowing alpha (transparency) to vary with y, but the legend is ugly:
g0 <- ggplot(dd,aes(x,y))+
geom_point(size=8,aes(alpha=y,colour=w))+
scale_colour_manual(values=c("red","blue"))
## + scale_alpha(guide="colourbar") ## doesn't work
I can draw each half of the points by themselves to get a legend similar to what I want:
g1 <- ggplot(dd[!dd$w,],aes(x,y))+
geom_point(size=8,aes(colour=y))+
scale_colour_gradient(low="white",high="red",name="not w")+
expand_limits(x=range(dd$x),y=range(dd$y))
g2 <- ggplot(dd[dd$w,],aes(x,y))+
geom_point(size=8,aes(colour=y))+
scale_colour_gradient(low="white",high="blue",name="w")+
expand_limits(x=range(dd$x),y=range(dd$y))
Now I can use tools from cowplot to pick off the legends and combine them with the original plot:
g1_leg <- get_legend(g1)
g2_leg <- get_legend(g2)
g0_noleg <- g0 + theme(legend.position='none')
ggdraw(plot_grid(g0_noleg,g1_leg,g2_leg,nrow=1,rel_widths=c(1,0.2,0.2)))
This is most of the way there, but:
ideally I'd like to squash the two colourbars together (I know I can probably do that with sufficient grid-hacking ...)
the colours don't quite match; the legend colours are slightly warmer than the point colours ...
Ideas? Or other ways of achieving the same goal?
In trying to color my stacked histogram according to a factor column; all the bars have a "green" roof? I want the bar-top to be the same color as the bar itself. The figure below shows clearly what is wrong. All the bars have a "green" horizontal line at the top?
Here is a dummy data set :
BodyLength <- rnorm(100, mean = 50, sd = 3)
vector <- c("80","10","5","5")
colors <- c("black","blue","red","green")
color <- rep(colors,vector)
data <- data.frame(BodyLength,color)
And the program I used to generate the plot below :
plot <- ggplot(data = data, aes(x=data$BodyLength, color = factor(data$color), fill=I("transparent")))
plot <- plot + geom_histogram()
plot <- plot + scale_colour_manual(values = c("Black","blue","red","green"))
Also, since the data column itself contains color names, any way I don't have to specify them again in scale_color_manual? Can ggplot identify them from the data itself? But I would really like help with the first problem right now...Thanks.
Here is a quick way to get your colors to scale_colour_manual without writing out a vector:
data <- data.frame(BodyLength,color)
data$color<- factor(data$color)
and then later,
scale_colour_manual(values = levels(data$color))
Now, with respect to your first problem, I don't know exactly why your bars have green roofs. However, you may want to look at some different options for the position argument in geom_histogram, such as
plot + geom_histogram(position="identity")
..or position="dodge". The identity option is closer to what you want but since green is the last line drawn, it overwrites previous the colors.
I like density plots better for these problems myself.
ggplot(data=data, aes(x=BodyLength, color=color)) + geom_density()
ggplot(data=data, aes(x=BodyLength, fill=color)) + geom_density(alpha=.3)
Let's say I have this data.frame:
df <- data.frame(x = rep(1, 20), y = runif(20, 10, 20))
and I want to plot df$y vs. df$x.
Since the x values are constant, points that have identical or close y values will be plotted on top of each other in a simple scatterplot, which kind of hides the density of points at such y-values. One solution for that situation is of course to use a violin plot.
I'm looking for another solution - plotting clusters of points instead of the individual points, which will therefore look similar to a bubble plot. In a bubble plot however, a third dimension is required in order to make the bubbles meaningful, which I don't have in my data. Does anyone know of an R function/package that take as input points (and probably a defined radius) and will cluster them and plot them?
You can jitter the x values:
plot(jitter(df$x),df$y)
You could try a hexplot, using either the hexplot library or stat_binhex in ggplot2.
http://cran.r-project.org/web/packages/hexbin/
http://docs.ggplot2.org/0.9.3/stat_binhex.html
The other standard approach (vs. jitter) is to use a partially transparent color, so that overlapping points will appear darker than "lone" points.
De gustibus, etc.
Using transparency is another solution. E.g.:
ggplot(df, aes(x=x, y=y)) +
geom_point(alpha=0.2, size=3)
When there is only one x value, a density plot:
ggplot(df, aes(x=y)) +
stat_density(geom="line")
or a violin plot:
ggplot(df, aes(x=x, y=y)) +
geom_violin()
might also be options for displaying your data.
look at the sunflowerplot function (and the xyTable function that it uses to count overlapping points).
You could also use the my.symbols function from the TeachingDemos package with the results of xyTable to use other shapes (polygrams or example).
once again Im confronted with a complicated ggplot. I want to plot different plottypes within one plot using facet grid.
I hope I can make my point clear using the following example:
I want to produce a plot similar to the first picture but the upper plot should look like the second picture.
I already found the trick using the subset function but I can't add vertical lines to only one plot let alone two or three (or specify the color).
CODE:
a <- rnorm(100)
b <- rnorm(100,8,1)
c <- rep(c(0,1),50)
dfr <- data.frame(a=a,b=b,c=c,d=seq(1:100))
dfr_melt <- melt(dfr,id.vars="d")
#I want only two grids, not three
ggplot(dfr_melt,aes(x=d,y=value)) + facet_grid(variable~.,scales="free")+
geom_line(subset=.(variable=="a")) + geom_line(subset=.(variable=="b"))
#Upper plot should look like this
ggplot(dfr,aes(x=d,y=a)) + geom_line() + geom_line(aes(y=c,color="c"))+
geom_hline(aes(yintercept=1),linetype="dashed")+
geom_hline(aes(yintercept=-2),linetype="dashed")
If I understand your question correctly, you just need to a variable column to dfr in order to allow the faceting to work:
dfr$variable = "a"
ggplot(subset(dfr_melt, variable=="a"),aes(x=d,y=value)) +
facet_grid(variable~.,scales="free")+
geom_line(data=subset(dfr_melt,variable=="a")) +
geom_line(data=subset(dfr_melt, variable=="b")) +
geom_line(data=dfr, aes(y=c, colour=factor(c))) +
geom_hline(aes(yintercept=1),linetype="dashed")+
geom_hline(aes(yintercept=-2),linetype="dashed")
Notice that my plot doesn't have the zig-zig line, this is because I changed:
#This is almost certainly not what you want
geom_line(data=dfr, aes(y=c, colour="c"))
to
#I made c a factor since it only takes the values 0 or 1
geom_line(data=dfr, aes(y=c, colour=factor(c)))
##Alternatively, you could have
geom_line(data=dfr, aes(y=c), colour="red") #or
geom_line(data=dfr, aes(y=c, colour=c)) #or
To my knowledge, you can't put multiple plot types in a single plot using facet.grid(). Your two options, as far as I can see, are
to put empty data in the first facet, so the lines are 'there' but not displayed, or
to combine multiple plots into one using viewports.
I think the second solution is more general, so that's what I did:
#name each of your plots
p2 <- ggplot(subset(dfr_melt, variable=="a"),aes(x=d,y=value)) + facet_grid(variable~.,scales="free")+
geom_line(subset=.(variable=="a")) + geom_line(subset=.(variable=="b"))
#Upper plot should look like this
p1 <- ggplot(dfr,aes(x=d,y=a)) + geom_line() + geom_line(aes(y=c,color="c"))+
geom_hline(aes(yintercept=1),linetype="dashed")+
geom_hline(aes(yintercept=-2),linetype="dashed")
#From Wickham ggplot2, p154
vplayout <- function(x,y) {
viewport(layout.pos.row=x, layout.pos.col=y)
}
require(grid)
png("myplot.png", width = 600, height = 300) #or use a different device, e.g. quartz for onscreen display on a mac
grid.newpage()
pushViewport(viewport(layout=grid.layout(2, 1)))
print(p1, vp=vplayout(1, 1))
print(p2, vp=vplayout(2, 1))
dev.off()
You might need to fiddle a bit to get them to line up exactly right. Turning off the faceting on the upper plot, and moving the legend on the lower plot to the bottom, should do the trick.