I am using directlabels for the first time today and as this is a new package the documentation is pretty sparse still. I have created a faceted density plot similar to this data and the labels could all be moved up and slightly right.
If this were mtext I could use adj and padj to move the text around. How would I do the same to the labels below. Move every label slightly up and slightly right?
library(directlabels); library(ggplot2)
g <- ggplot(CO2, aes(x=conc, group=Type))
h <- g + geom_density(aes(colour=Type)) +facet_grid(Treatment~.)
direct.label(h)
This is the last bit until I have a figure ready for publication and so help here would be much appreciated.
EDIT The top.bumptwice doesn't move the text up quite enough. I would like more control over the move.
I asked the author and you can pass the moves to direct.labels as a list:
library(ggplot2); library(directlabels)
x <- ggplot(CO2, aes(x=uptake, group=Plant))
y <- x + geom_density(aes(colour=Plant)) +
facet_grid(Type~Treatment)+ theme_bw()
y
my.method1 <- list('top.points',dl.move("Qn1", hjust=0,vjust=-5)
)
direct.label(y, my.method1)
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 love ggplot, but find it hard to customize some elements such as X axis labels and grid lines. The title of the question says it all, but here's a reproducible example to go with it:
Reproducible example
library(ggplot2)
library(dplyr)
# Make a dataset
set.seed(123)
x1 <- c('2015_46','2015_47','2015_48','2015_49'
,'2015_50','2015_51','2015_52','2016_01',
'2016_02','2016_03')
y1 <- runif(10,0.0,1.0)
y2 <- runif(10,0.5,2.0)
# Make the dataset ggplot friendly
df_wide <- data.table(x1, y1, y2)
df_long <- melt(df_wide, id = 'x1')
# Plot it
p <- ggplot(df_long, aes(x=x1,
y=value,
group=variable,
colour=variable )) + geom_line(size=1)
plot(p)
# Now, plot the same thing with the same lines and numbers,
# but with increased space between x-axis labels
# and / or space between x-axis grid lines.
Plot1
The plot looks like this, and doesn't look too bad in it's current form:
Plot2
The problem occurs when the dataset gets bigger, and the labels on the x-axis start overlapping each other like this:
What I've tried so far:
I've made several attempts using scale_x_discrete as suggested here, but I've had no luck so far. What really bugs me is that I saw some tutorial about these things a while back, but despite two days of intense googling I just can't find it. I'm going to update this section when I try new things.
I'm looking forward to your suggestions!
As mentioned above, assuming that x1 represents a year_day, ggplot provides sensible defaults for date scales.
First make x1 into a valid date format, then plot as you already did:
df_long$x1 <- strptime(as.character(df_long$x1), format="%Y_%j")
ggplot(df_long, aes(x=x1, y=value, group=variable, colour=variable)) +
geom_line(size=1)
The plot looks a little odd because of the disconnected time series, but scales_x_date() provides an easy way to customize the axis:
http://docs.ggplot2.org/current/scale_date.html
I would like to change the font size of the labels in this plot:
library(ggplot2)
p <- ggplot(mtcars, aes(x=wt, y=mpg)) +
geom_text(label=rownames(mtcars))
p
My problem: I do not know what the labels are. (I stored a plot in which I used different data.frame()s to add geom_text(). I now only loaded the plot (p in this example), but do not want to also load the data.frame()s with which I created the labels).
As I do not know what the labels are, I cannot use this solution:
p + geom_text(label=rownames(mtcars), size=2)
(Another problem with this solution would be that I still needed to delete the original geom_text() with the larger font-size).
I can change the size of all text in the plot with this solution:
library(grid)
grid.force()
grid.gedit("GRID.text", grep=TRUE, gp=gpar(fontsize=4.5))
However, now also my axes changed, which is not what I wanted.
I believe there are several options to achieve what I want, at least two of which should be fairly simply to implement:
Save the object from grid.gedit() to p1 and then p1 + theme(text = element_text(size=2)). My problem here: I do not know how to save the object from grid.gedit(). This would be my preferred option.
Go to the right viewport before applying grid.gedit(). I tried this, but still change both the labels (which I want) and the axes text (which I do not want).
Somehow extract the data.frame for the labels from the stored plot (p in this example) to apply the solution that I provided first.
You can inspect (/modify) the plot after building it,
library(ggplot2)
p <- ggplot(mtcars, aes(x=wt, y=mpg)) +
geom_text(label=rownames(mtcars))
g <- ggplot_build(p)
# original data is in str(g$plot$data)
# but it's easier to process the data for rendering
g[["data"]][[1]][["size"]] <- 5
g[["data"]][[1]][["colour"]] <- "red"
gg <- ggplot_gtable(g)
grid.newpage()
grid.draw(gg)
Your grid.gedit command was close. You need to set up a gPath so that the edit command finds just those labels in the plot panel. grid.ls(grid.force()) returns a hierarchy of grobs. Find the 'panel', then the 'text'. (Note: the 'g' in 'gedit' stands for 'grep = TRUE, global = TRUE')
library(ggplot2)
p <- ggplot(mtcars, aes(x=wt, y=mpg)) +
geom_text(label=rownames(mtcars))
p
library(grid)
grid.ls(grid.force()) # Locate the path to the labels in the panel
grid.gedit(gPath("panel","GRID.text"), gp=gpar(fontsize=4.5))
If you prefer, with a few more lines of code, the plot object can be edited rather than editing on screen.
g = ggplotGrob(p)
g = editGrob(grid.force(g), gPath("panel", "GRID.text"), grep=TRUE, gp=gpar(fontsize=4.5))
grid.newpage()
grid.draw(g)
I'm plotting some index data as a bar chart. I'd like to emphasise the "above index" and "below index"-ness of the numbers by forcing the x-axis to cross at 100 (such that a value of 80 would appear as a -20 bar.)
This is part of a much longer process, so it's hard to share data usefully. Here, though, is some bodge-y code that illustrates the problem (and the beginnings of my solution):
df <- data.frame(c("a","b","c"),c(118,80,65))
names(df) <- c("label","index")
my.plot <- ggplot(df,aes(label,index))
my.plot + geom_bar()
df$adjusted <- as.numeric(lapply(df$index,function(x) x-100))
my.plot2 <- ggplot(df,aes(label,adjusted))
my.plot2 + geom_bar()
I can, of course, change my index calculation to read: (value.new/value.old)*100-100 then title the chart appropriately (something like "xxx relative to index") but this seems clumsy.
So, too, does the approach I've been testing (to run the simple calculation above, then re-label the y-axis.) Is that really the best solution?
No doubt someone's going to tell me that this sort of axis manipulation is frowned upon. If this is the case, please could they point me in the direction of an explanation? At least then I'll have learned something.
This doesn't directly answer you question, but instead of missing about with the x-axis, why not make a single grid line a bit thicker? For example,
dd = data.frame(x = 1:10, y = runif(10))
g = ggplot(dd, aes(x, y)) + geom_point()
g + geom_hline(yintercept=0.2, colour="white", lwd=3)
Or as Paul suggested, with a black line and some text:
g + geom_hline(yintercept=0.2, colour="black", lwd=3) +
annotate("text", x = 2, y = 0.22, label = "Reference")
The coordinate system of you plot has the x-axis and the y-axis crossing at (0,0). This is just the way you define your coordinate system. You can of course draw a horizontal line at (x = 100), but to call this is x-axis is false.
What you already proposed is to redefine your coordinate system by transforming the data. Whether or not this transformation is appropriate is easier to answer with a reproducible example from your side.
I've got a nice facet_wrap density plot that I have created with ggplot2. I would like for each panel to have x and y axis labels instead of only having the y axis labels along the left side and the x labels along the bottom. What I have right now looks like this:
library(ggplot2)
myGroups <- sample(c("Mo", "Larry", "Curly"), 100, replace=T)
myValues <- rnorm(300)
df <- data.frame(myGroups, myValues)
p <- ggplot(df) +
geom_density(aes(myValues), fill = alpha("#335785", .6)) +
facet_wrap(~ myGroups)
p
Which returns:
(source: cerebralmastication.com)
It seems like this should be simple, but my Google Fu has been too poor to find an answer.
You can do this by including the scales="free" option in your facet_wrap call:
myGroups <- sample(c("Mo", "Larry", "Curly"), 100, replace=T)
myValues <- rnorm(300)
df <- data.frame(myGroups, myValues)
p <- ggplot(df) +
geom_density(aes(myValues), fill = alpha("#335785", .6)) +
facet_wrap(~ myGroups, scales="free")
p
Short answer: You can't do that. It might make sense with 3 graphs, but what if you had a big lattice of 32 graphs? That would look noisy and bad. GGplot's philosophy is about doing the right thing with a minimum of customization, which means, naturally, that you can't customize things as much as other packages.
Long answer: You could fake it by constructing three separate ggplot objects and combining them. But it's not a very general solution. Here's some code from Hadley's book that assumes you've created ggplot objects a, b, and c. It puts a in the top row, with b and c in the bottom row.
grid.newpage()
pushViewport(viewport(layout=grid.layout(2,2)))
vplayout<-function(x,y)
viewport(layout.pos.row=x,layout.pos.col=y)
print(a,vp=vplayout(1,1:2))
print(b,vp=vplayout(2,1))
print(c,vp=vplayout(2,2))