For the main y-axis and x-axis, I have generic titles like "Tank's Ratio" and "Counts". I want a second line of label where I specify the ratio and counts. eg. Just below "Tank's Ratio" I want "# in water/# in sand" in a smaller font but along the y-axis. Similarly for the x-axis.
Here is the basic code
data <- data.frame(set = c(1, 1, 1, 2, 2, 3, 3, 3, 3, 3, 4, 4), density = c(1, 3, 3, 1, 3, 1, 1, 1, 3, 3, 1, 3), counts = c(100, 2, 3, 76, 33, 12, 44, 13, 54, 36, 65, 1), ratio = c(1, 2, 3, 4, 1, 2, 3, 4, 5, 6, 90, 1))
library(ggplot2)
ggplot(data, aes(x = counts, y = ratio)) +
geom_point() +
ylab("Tank's Ratio") +
xlab("Counts")
You can add x and main titles.
EDIT: This is ridiculously slooow!
#library(extrafont)
#loadfonts(dev="win")
library(tidyverse)
data %>%
ggplot(aes(x=counts, y=ratio)) + geom_point() +
labs(y=expression(atop(bold("Tank's Ratio"),atop(italic("#in water #in sand")))))+
theme_minimal()+
theme(axis.title.y = element_text(size=15,family="Comic Sans MS"))
ORIGINAL:
library(tidyverse)
data %>%
ggplot(aes(x=counts, y=ratio)) + geom_point() +
labs(y="Tank's Ratio \n #in Water#in sand")
It's not the most elegant solution, but hope it helps:
library(ggplot2)
library(gridExtra)
library(grid)
First, create plot without ylab:
g <- ggplot(data, aes(x = counts, y = ratio)) +
geom_point() +
ylab("") +
xlab("Counts")
Then add subtitle for both axis:
g2 <- grid.arrange(g,
bottom = textGrob("in water/ # in sand",
x = 0.55, y = 1, gp = gpar(fontsize = 9)),
left = textGrob("in water/ # in sand", rot = 90,
x = 1.5, gp = gpar(fontsize = 9)))
And finally, add description of y-axis
grid.arrange(g2,
left = textGrob("Tank's Ratio", rot = 90,
x = 1.7, gp = gpar(fontsize = 12)))
You could use the following code, defining the margins, the axis titles and sub-titles yourself:
We use theme to increase the bottom and left margin, and to suppress the automatically generated axis titles.
We use annotate to generate the text that serves as axis title and sub-title, if necessary, the text is rotated.
We generate the plot, turn it in a grob, and with this grob we can turn of clipping, and show the plot.
g1 <- ggplot(data = data, aes(x = counts, y = ratio, group = 1)) +
geom_point() +
## increase margin size for left and bottom and
## remove the axis titles
theme(plot.margin = unit(c(1, 1, 4, 4), "lines"),
axis.title.y = element_blank(),
axis.title.x = element_blank() ) +
## define the plotting area to NOT include the annotations
coord_cartesian(xlim = c(0, 100), ylim= c(0, 100), expand = FALSE) +
## annotate y axis
annotate(geom = "text", x = -9, y = 50, label = "Tank's Ratio", angle = 90, size = 5) +
annotate(geom = "text", x = -5, y = 50, label = "#in water/#in sand", angle = 90, size = 4) +
## annotate x axis
annotate(geom = "text", x = 50, y = -5, label = "Counts", size = 5) +
annotate(geom = "text", x = 50, y = -9, label = "#in water/#in sand", size = 4)
## turn off clipping for axis extra labels
g2 <- ggplot_gtable(ggplot_build(g1))
g2$layout$clip[g2$layout$name == "panel"] <- "off"
grid::grid.draw(g2)
This yields the following picture:
Please let me know whether this is what you want.
Related
I'm trying to slightly reposition the labels of a discrete colorbar so that they don't overlap, without changing the values of the breaks themselves. In the below plot, the two center labels (bracketing the near-zero data) are too close together, so that it looks like '-11' instead of '-1' and '1'. I'd like to nudge them to either side, or change the justification of each half of the scale (left justify the negatives and right justify the positives), or anything to create more space between the labels while retaining the spacing of the actual colorbar. (Making the colorbar wider is not an option in my actual figure.)
Here is the code used to create this plot:
library(dplyr)
library(ggplot2)
library(scales)
df <- data.frame(
x = runif(1000),
y = runif(1000),
z1 = rnorm(100)*10
)
df %>% ggplot() +
geom_point(aes(x=x,y=y, color=z1)) +
scale_color_steps2(low = muted("darkblue"), mid = "white", high = muted("darkred"),
midpoint = 0, guide_colorbar(barwidth = 20),
breaks = c(-20, -10, -5, -1, 1, 5, 10, 20)) +
theme_minimal() +
theme(legend.position = 'bottom') +
labs(x='', y='', color='')
Always a bit hacky and you get a warning but one option would be to pass a vector to hjust argument of element_text to align the -1 to the right and the 1 to the left:
library(ggplot2)
set.seed(123)
df <- data.frame(
x = runif(1000),
y = runif(1000),
z1 = rnorm(100)*10
)
ggplot(df) +
geom_point(aes(x=x,y=y, color=z1)) +
scale_color_steps2(low = scales::muted("darkblue"), mid = "white", high = scales::muted("darkred"),
midpoint = 0, guide = guide_colorbar(barwidth = 20),# horizontal_legend,
breaks = c(-20, -10, -5, -1, 1, 5, 10, 20)) +
theme_minimal() +
theme(legend.position = 'bottom') +
labs(x='', y='', color='') +
theme(legend.text = element_text(hjust = c(rep(.5, 3), 1, 0, rep(.5, 3))))
#> Warning: Vectorized input to `element_text()` is not officially supported.
#> Results may be unexpected or may change in future versions of ggplot2.
I would like to modify the following forest plot:
library(ggplot2)
library(dplyr)
set.seed(123)
mydata <- data.frame(
subgroup = c("age < 60", "age > 60", "male", "female"),
n = c(76, 37, 55, 58),
HR = c(-2.12, 2.88, -0.91, 3.83),
CIlower = c(-5.64, 0.48, -2.78, 2.57),
CIupper = c(-0.37, 4.38, 0.47, 4.28),
pvalue = c(0.083, 0.438, 0.237, 0.683))
mydata %>%
ggplot(aes(x = subgroup, y = HR, ymin = CIlower, ymax = CIupper)) +
geom_pointrange() +
geom_hline(yintercept = 1, lty = 2) +
xlab("group") +
ylab("HR") +
coord_flip() +
theme_light() +
theme(plot.margin = unit(c(1, 4, 1, 1), "lines")) +
annotate("text", x = 4, y = 4, label = mydata$pvalue[4])
annotate("text", x = 3, y = 4, label = mydata$pvalue[3])
annotate("text", x = 2, y = 4, label = mydata$pvalue[2])
annotate("text", x = 1, y = 4, label = mydata$pvalue[1])
My attempt with annotate was only possible within my plot.
My plan is to add text that is relevant for the plot left or right of the plot area. I would like to place text with the count of the subgroup observation (stored in the variable "n" of mydata) and the HR with CI as well as the p-value (stored in the correspoding variables in mydata) right of the plot in line with the group and the data point. I know that this could be done with labels (https://newbedev.com/ggplot2-annotate-outside-of-plot, first code solution) - this works great with one label because the text is positioned according to the data points, but I have more than one label (n, HR/CI + p-value). The third solution with grid did not work for me as the y position differed when I enlarged the plot in my markdown (or I simply did something wrong).
Can anyone help me?
Thank you!
Do you want something like this?
ggplot(data = mtcars, aes(x = wt, y = mpg)) +
geom_point() +
theme(plot.margin = unit(c(1,3,1,1), "cm")) +
annotate("text", x = 7.7, y = 10, label = "text1") +
annotate("text", x = 8, y = 5, label = "text2") +
annotate("text", x = 8.5, y = 20, label = "text3") +
coord_cartesian(xlim = c(0,7), ylim = c(0, 35), clip = "off") #without this you can't print text labels outside the plot
I am trying to annotate both axes of my plot with some text, but when I do that, I am unable to position the text as I would like. By adding new text on one axis, the text on the other axis gets misplaced.
How to deal with that?
Here is an example to illustrate my issue:
set.seed(1234)
x <- rnorm(50, 5, 2)
y <- x + 1 + rnorm(50)
data <- cbind.data.frame(x,y)
#Create a plot in which I annotate in one axis (it works great)
plot <- ggplot(data = data, aes(x, y))+
geom_point() +
geom_hline(yintercept=median(data$x, na.rm = T), color = 'red') +
geom_vline(xintercept=median(data$y, na.rm = T), color = 'red') +
labs(y="Label y", x = "Label x") +
geom_smooth(method=lm, na.rm = TRUE, fullrange= TRUE,
aes(group=1),colour="black") +
theme_bw() +
theme(axis.title.y = element_text(margin = margin(t = 0, r = 30, b = 0, l = 0))) +
theme(axis.title.x = element_text(margin = margin(t = 30, r = 0, b = 0, l = 0))) +
annotate("text", x = 9, y = -3, label = "Helpful Text2") +
annotate("text", x = 0.5, y = -3, label = "Helpful Text1") +
coord_cartesian(ylim = c(0, 15), clip = "off")
#Trying to add annotation to the second axis (it alters the axis of the plot, thereby misplacing the annotation I have done prior)
plot + annotate("text", x = 0, y = 8.5, label = "Helpful Text3", angle = 90) +
annotate("text", x = 0, y = 2, label = "Helpful Text4", angle = 90) +
coord_cartesian(xlim = c(1, 9), clip = "off")
Ideas?
You could try:
plot + annotate("text", x = -1, y = 14, label = "Helpful Text3", angle = 90) +
annotate("text", x = -1, y = 0, label = "Helpful Text4", angle = 90) +
coord_cartesian(ylim = c(0, 15), xlim = c(0, 10), clip = "off")
Just make sure you set fullrange = FALSE in geom_smooth when defining your plot.
I am trying to visualise data on a graph with R.
The code below works perfectly but the gridlines seem to be lost (see the image below).
with(res_final, plot(position_aa, mean_res, main="Hydrophobicity",
xlab="Amino acid position",
ylab="Eisenberg scale"))
with(res_final, points(position_aa, mean_res, pch=10, cex=0.5))
.col <- rgb(0, 0, 0, .25) ## alpha .25 for transparency
abline(h=axTicks(3), lty=3, col=.col)
abline(v=seq(-10:14), lty=3, col=.col)
I have positions from -10 to 14. How can I make the x axis with every single position separately labelled?
How can I add the gridlines to the plot below so that it is visible for each position from the x axis?
You haven't provided any data,but the following is a reasonable approximation:
set.seed(69)
res_final <- data.frame(position_aa = seq(-10, 14, 1),
mean_res = c(runif(10, -0.5, 0.25),
runif(4, 0.5, 1.25),
runif(11, -0.5, 0.25)))
The main problem with your code is your use of seq, which isn't doing what you think it is. The way to get a sequence between -10 and 14 is seq(-10, 14, 1) or seq(-10, 14). This change will allow your grid lines to appear as expected.
For your second problem, you can add an axis call using pos = 1 and the at argument to specify the breaks on the axis. You'll need to ensure that the plot area is wide enough (or the axis text is small enough) that some of the numbers don't get suppressed.
with(res_final, plot(position_aa, mean_res, main = "Hydrophobicity",
xlab = "Amino acid position",
ylab = "Eisenberg scale"))
axis(pos = 1, at = seq(-10, 14, 1))
with(res_final, points(position_aa, mean_res, pch = 10, cex = 0.5))
.col <- rgb(0, 0, 0, .25)
abline(h = axTicks(3), lty = 3, col = .col)
abline(v = seq(-10, 14, 1), lty = 3, col = .col)
For completeness, the equivalent in ggplot would be:
library(ggplot2)
ggplot(res_final, aes(position_aa, mean_res)) +
geom_point(shape = 21, size = 5, fill = "white") +
geom_point(shape = 21, size = 2, fill = "black") +
scale_x_continuous(breaks = seq(-10, 14)) +
theme_bw() +
theme(panel.grid.minor = element_blank(),
text = element_text(size = 15),
plot.title.position = "plot",
plot.title = element_text(hjust = 0.5)) +
labs(title = "Hydrophobicity",
x = "Amino acid position",
y = "Eisenberg scale")
I am making a birds-on-wire plot using geom_linerange and geom_linerangeh to show subjects' treatment over time (wire) and the occurrence of some events (birds) during the treatment period. I am using the height of "birds" (i.e. length of vertical lines) to represent a certain characteristic of the "birds" (events). There are only 4 possible different lengths (see variable evt_type2) below. See mock data, code, and plot below.
library(tidyverse)
library(ggstance)
###Mock data###
#Treatment data
data_foo1 <- data.frame(subjectn = c(1, 1, 2, 3, 3, 3, 4, 5),
trt_start = c(1, 25, 1, 1, 50, 101, 1, 1),
trt_end = c(80, 60, 100, 25, 100, 200, 120, 90),
trt_type = as.factor(c(1, 2, 1, 3, 4, 5, 2, 4)),
stringsAsFactors = F)
#Some kind of events data
data_foo2 <- data.frame(subjectn = c(1, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 5),
evt_start = c(70, 20, 90, 92, 24, 50, 70, 120, 170, 69, 80, 90),
evt_type1 = as.factor(c(0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0)),
evt_type2 = c(0.2, 0.8, 0.2, 0.4, 0.4, 0.2, 0.2, 0.6, 0.4, 0.4, 0.6, 0.2))
###Plot###
data_foo2 %>%
ggplot() +
geom_linerange(aes(x = evt_start, y = subjectn, ymin = subjectn, ymax = subjectn + evt_type2, linetype = evt_type1), size=0.8, alpha = 0.5) +
geom_linerangeh(data = data_foo1, aes(x = trt_start, y = subjectn, xmin = trt_start, xmax = trt_end, color = trt_type), size = 1.2, alpha = 0.7) +
scale_y_continuous(breaks = c(1, 2, 3, 4, 5), labels = c("A001", "A002", "A003", "A004", "A005")) +
xlab("Time") + theme_bw()
See the resulting plot here
My question is, is it possible to add a legend for the 4 different vertical line lengths? THANK YOU!
As mentioned in the comment, showing lengths of lines in the legend is generally not easily possible. One option would be to create a fake legend - another plot, which you then add to your main plot.
But I struggle to find the visualisation very compelling. Line lengths are difficult to discern, expecially when you have different line types and a line can cut off weirdly (see subject A003). It would also not be clear in the legend how to map the respective line length to the legnth in the plot.
Thus, I recommend using a different aesthetic for visualising dimension event 2.
One way would be to draw rectangles instead of lines and use the fill. You can make this categorical (as in my example) or continuous, and the legend easily maps to your data - visually, in my opinion, you can better discern the four different event types.
library(tidyverse)
library(ggstance)
ggplot() +
geom_linerangeh(
data = data_foo1,
aes(
y = subjectn,
xmin = trt_start,
xmax = trt_end,
color = trt_type
),
size = 1.2, alpha = 0.7
) +
geom_rect(
data = data_foo2, aes(
xmin = evt_start - 2,
xmax = evt_start + 2,
ymin = subjectn,
ymax = subjectn + 0.5,
linetype = evt_type1,
fill = as.character(evt_type2)
),
size = 0.2, color = "black", alpha = 0.5
) +
scale_fill_brewer() +
scale_y_continuous(breaks = 1:5, labels = paste0("A00", 1:5)) +
theme_bw()
Or, you can keep the lines, and add a second color aesthetic with ggnewscale.
ggplot() +
geom_linerangeh(
data = data_foo1,
aes(
y = subjectn,
xmin = trt_start,
xmax = trt_end,
color = trt_type
),
size = 1.2, alpha = 0.7
) +
scale_y_continuous(breaks = 1:5, labels = paste0("A00", 1:5)) +
ggnewscale::new_scale_color()+
geom_linerange(data = data_foo2,
aes(x = evt_start,
y = subjectn,
ymin = subjectn,
ymax = subjectn + 0.5,
color = as.character(evt_type2),
linetype = evt_type1),
size=0.8) +
scale_color_brewer() +
theme_bw()
Created on 2020-04-26 by the reprex package (v0.3.0)
The colors come out quite "light", and if you want them "darker", you can use the shades packages, e.g, by wrapping your scale_color function into one of the brightness modifying functions, e.g. shades::brightness(scale_color_brewer(), shades::delta(-0.2))