Vertical lines between points with ggplot2 - r

I am new to ggplot2 and cannot figure out how to draw vertical dotted grey lines between
the points/dots along the x-axis. Here's my example code:
d1 <- runif(10,10,15)
d2 <- runif(10,25,30)
d3 <- rep(1:10,2)
df <- data.frame(x = d3, y = c(d1,d2))
ggplot(df, aes(x=x, y=y)) +
geom_point()

If your actual data is structured like the one used for your example, just add geom_line(aes(group = d3)) to the plot.
ggplot(df, aes(x=x, y=y)) +
geom_point() + geom_line(aes(group = d3))

There's definitely better ways than this but:
d1 <- runif(10,10,15)
d2 <- runif(10,25,30)
d3 <- rep(1:10,2)
df <- data.frame(x = d3, y = c(d1,d2))
df$place <- rep(c("min", "max") , each=10)
df_wide <- reshape(df, direction = "wide", v.names="y", timevar="place", idvar="x")
ggplot(df, aes(x=x, y=y)) +
geom_segment(aes(x=x, xend=x, y=y.min, yend=y.max),
size=1, data=df_wide, colour="grey70", linetype="dotted") +
geom_point()
Though I'm not sure what you mean by "along the x axis", maybe you want it to extend top to bottom not just between the points.

You should be using geom_vline() to do this.
d1 <- runif(10,10,15)
d2 <- runif(10,25,30)
d3 <- rep(1:10,2)
df <- data.frame(x = d3, y = c(d1,d2))
ggplot(df, aes(x=x, y=y)) + geom_point() +
geom_vline(xintercept = df$x, linetype= 3, colour = "#919191")

Related

In R, how do you stack figures made using ggplot2 on top of each other?

I have made two figures in ggplot that I now want to stack on top of each other. I can get them to stack using grid.arrange(p1, p2, ncol =1) function in the gridExtra package however, both figures get horizontally stretched out becoming the shape of rectangles. Any idea on how to keep both figures square (x and y-axes the same overall length).
library(ggplot2)
library(gridExtra)
x1 <- rnorm(20)
y1 <- rnorm(20)
x2 <- rnorm(20)
y2 <- rnorm(20)
dat1 <- data.frame(x1, y1)
dat2 <- data.frame(x2, y2)
p1 <- ggplot(data = dat1, aes(x=x1, y=y1)) + geom_point()
p2 <- ggplot(data = dat2, aes(x=x2, y=y2)) + geom_point()
grid.arrange(p1,p2, ncol=1)
I have tried adjusting the width by using the widths argument but I keep getting the error message Error in arrangeGrob(...) : length(widths) == ncol is not TRUE.
grid.arrange(p1,p2, ncol=1, widths = c(1,1))
The patchwork package is built for this.
Plot1 + Plot2 # side by side
Plot1/Plot2 # top over bottom
I'm a big fan of patchwork for arranging plots. You get square plots by setting the dimensions as you export the figure.
library(patchwork)
p3 <- p1/p2 + plot_layout(ncol = 1, heights = c(1,1))
ggsave("test.png", p3, width = 10, height = 20, units = c("cm"))
Thanks for the responses but I actually figured it out using the packages I mentioned. What I had to do was add theme(aspect.ratio = 1) to both figures.
p1 <- ggplot(data = dat1, aes(x=x1, y=y1)) + geom_point() + theme(aspect.ratio = 1)
p2 <- ggplot(data = dat2, aes(x=x2, y=y2)) + geom_point() + theme(aspect.ratio = 1)
grid.arrange(p1,p2, ncol=1)
How about this:
library(ggplot2)
library(gridExtra)
x1 <- rnorm(20)
y1 <- rnorm(20)
x2 <- rnorm(20)
y2 <- rnorm(20)
dat1 <- data.frame(x1, y1)
dat2 <- data.frame(x2, y2)
p1 <- ggplot(data = dat1, aes(x=x1, y=y1)) + geom_point()
p2 <- ggplot(data = dat2, aes(x=x2, y=y2)) + geom_point()
grid.arrange(p1,p2, ncol=1, widths = unit(10, c("cm")), heights = c(unit(10, c("cm")), unit(10, c("cm"))))

is it possible to create a ggMarginal plot without desaggredating the data?

I have a data frame with some points and their frequency of occurrence and I want to plot points (balls) using their frequency to represent their size. But I also want to use ggMarginal to create the marginal plots. The code bellow creates the marginal without taking in account their frequencies.
library(ggplot2)
df <- data.frame("x" = 1:5, "y" = c(5,8,8,12,10), "f" = c(4,5,8,8,5))
p <- ggplot(df, aes(x=x, y=y, size=f)) + geom_point() + theme_bw()
ggExtra::ggMarginal(p, data=df, type = "histogram")
I don't want to create another data frame with disaggregated data. But it would lead to the right marginals. As presented bellow:
# disaggregated data
df2 <- df[ rep(1:nrow(df), df$f), c("x", "y") ]
p <- ggplot(df2, aes(x=x, y=y)) + geom_point() + theme_bw()
ggExtra::ggMarginal(p, data=df2, type = "histogram")
But even if I try to use both data frames, the resulting marginals still go wrong.
p <- ggplot(df, aes(x=x, y=y, size=f)) + geom_point() + theme_bw()
ggExtra::ggMarginal(p, data=df2, type = "histogram")
Is it possible to create the marginals with disaggregating the data? How?
If 1. is not possible, how to do it anyway, since none of the examples above provided the desired plot?
It can be done with cowplot package.
library(tidyverse)
library(cowplot)
df <- data.frame("x" = 1:5,
"y" = c(5,8,8,12,10),
"f" = c(4,5,8,8,5))
df2 <- df[rep(1:nrow(df), df$f), c("x", "y") ]
p <-
ggplot(df, aes(x=x, y=y, size=f)) +
geom_count() +
theme_bw()
xhist <-
axis_canvas(p, axis = "x") +
geom_histogram(data = df2, aes(x = x), color = 'lightgray')
yhist <-
axis_canvas(p, axis = "y", coord_flip = TRUE) +
geom_histogram(data = df2, aes(x = y), color = 'lightgray') +
coord_flip()
p %>%
insert_xaxis_grob(xhist, grid::unit(1, "in"), position = "top") %>%
insert_yaxis_grob(yhist, grid::unit(1, "in"), position = "right") %>%
ggdraw()

ggplot2: Dodge points with categorical axis and overlaying points

Consider the following graph
d1 = data.frame(x=LETTERS[1:2],y=c(1.9,2.3))
d2 = data.frame(x=LETTERS[1:2],y=c(1.9,3))
ggplot(d1, aes(x=x,y=y)) + geom_point(data=d1, color="red") +
geom_point(data=d2, color="blue")
The goal is to dodge the blue toward the right and the red dots toward the left. One way would be to merge the two data.frames
d1$category=1
d2$category=2
d = rbind(d1,d2)
d$category = as.factor(d$category)
ggplot(d, aes(x=x,y=y, color=category)) +
geom_point(data=d, position=position_dodge(0.3)) +
scale_color_manual(values=c("red","blue"))
Is there a another solution (a solution that does not require merging the data.frames)?
You can use position_nudge():
library(ggplot2)
d1 <- data.frame(x = LETTERS[1:2], y = c(1.9, 2.3))
d2 <- data.frame(x = LETTERS[1:2], y = c(1.9, 3))
ggplot(d1, aes(x, y)) +
geom_point(d1, color = "red", position = position_nudge(- 0.05)) +
geom_point(d2, color = "blue", position = position_nudge(0.05))

Vertically align faceted ggplots of different heights when using coord_equal()

I am trying to combine two FACETED ggplot objects with coord_equal() using cowplot::plot_grid() or egg::ggarrange() and vertically align them.
The egg::ggarrange() approach works fine for UNFACETED plots, with the solution posted here.
However, the egg::ggarrange() solution breaks down when faceting is included. The plots are correctly aligned, but the units of the y-axes are twice as large as those of the x-axes. Any suggestions for how to generalize this for faceting?
dat1 <- data.frame(x = rep(1:10, 2), y = 1:20, z = rep(c("A", "B"), 10))
dat2 <- data.frame(x = 1:10, y = 1:10, z = rep(c("A", "B"), 5))
plot1 <- ggplot(dat1, aes(x=x, y=y)) +
geom_point() + coord_equal() + facet_wrap(~z)
plot2 <- ggplot(dat2, aes(x=x, y=y)) +
geom_point() + coord_equal() + facet_wrap(~z)
egg::ggarrange(plot1, plot2, ncol = 1)
it seems to be a simple fix,
library(egg)
b <- body(gtable_frame)
b[6] <- parse(text="if (fixed_ar) {
ar <- as.numeric(g$heights[tt[1]]) / as.numeric(g$widths[ll[1]])
height <- width * (ar / length(ll))
g$respect <- FALSE
}")
body(gtable_frame) <- b
assignInNamespace("gtable_frame", gtable_frame, ns = 'egg')
The main problem is that plot1 and plot2 have different aspect ratios.
This is plot1:
And this plot2:
You can try to keep the aspect ratio using, i.e. theme(aspect.ratio=1) instead of coord_equal():
require(ggplot2)
dat1 <- data.frame(x = rep(1:10, 2), y = 1:20, z = rep(c("A", "B"), 10))
dat2 <- data.frame(x = 1:10, y = 1:10, z = rep(c("A", "B"), 5))
plot1 <- ggplot(dat1, aes(x=x, y=y)) + geom_point() + theme(aspect.ratio=1)+
facet_wrap(~z)
plot2 <- ggplot(dat2, aes(x=x, y=y)) + geom_point() + theme(aspect.ratio=1)+
facet_wrap(~z)
egg::ggarrange(plot1, plot2, ncol = 1,heights = c(1,10))
Hope it serves.

Ggplot2 and incrementing numbers in titles of a series of plots

When you create a series of plots with ggplot2, how can you programmatically add a number in the plot title to show which plot it is in the series? The examples below have Plot 1, Plot 2 and Plot 3 hard coded in the title; how can ggplot put in 1, 2, 3, etc.? The plots will be inserted in a document at different places.
df <- data.frame(var1 = seq(1:10), var2 = seq(3:12))
p1 <- ggplot(df, aes(x = var1, y = var2)) + geom_point() + ggtitle("Plot 1")
p2 <- ggplot(df, aes(x = var1, y = var2)) + geom_point() + ggtitle("Plot 2")
p3 <- ggplot(df, aes(x = var1, y = var2)) + geom_point() + ggtitle("Plot 3")
http://cran.r-project.org/doc/FAQ/R-FAQ.html#How-can-I-substitute-into-a-plot-label_003f addresses variables and expressions but I need some kind of incremental counter.
How to add a title to a ggplot when the title is a variable name? doesn't seem to help
Is something like the following possible?
plot_counter <- 1
p2 <- ggplot(df, aes(x = var1, y = var2)) + geom_point() + ggtitle(paste("Plot", plot_counter + 1")
I'm not sure I get what you are trying to do. This does what I understood from your question:
df <- data.frame(var1 = seq(1:10), var2 = seq(3:12))
i <- 0
library(ggplot2)
p1 <- ggplot(df, aes(x = var1, y = var2)) + geom_point() +
ggtitle(paste("Plot", i <- i+1))
p2 <- ggplot(df, aes(x = var1, y = var2)) + geom_point() +
ggtitle(paste("Plot", i <- i+1))
p3 <- ggplot(df, aes(x = var1, y = var2)) + geom_point() +
ggtitle(paste("Plot", i <- i+1))
print(p1)
print(p2)
print(p3)
Are you using knitr? That might change the answer.

Resources