R: Drawing Arbitrary Partitions on a Graph - r

I am working with the R programming language. In a previous question (R: Erasing Lines on ggplot2 - drawing half rectangles), I learned how to make the following graph:
library(tidyverse)
var_1 = rnorm(1000,20,20)
var_2 = rnorm(1000,20,20)
my_data = data.frame(var_1, var_2)
ggplot(data=my_data, aes(x=var_1, y=var_2)) +
geom_point() +
geom_segment(aes(x = -50, xend = 0, y = 0, yend = 0), color = "red") +
geom_segment(aes(x = 0, xend = 0, y = 0, yend = -50), color = "red") +
geom_segment(aes(x = -50, xend = 50, y = 50, yend = 50), color = "red") +
geom_segment(aes(x = 50, xend = 50, y = 50, yend = -50), color = "red")
I want to change the above code so that "x", "xend", "y", "yend" can come from a data frame:
For instance, suppose I have the following data frame:
my_points = data.frame(x1 = c(-40, -41) , x2 = c(20, 21) , y1 = c(-30, -31), y2 = c(50, 51) )
> my_points
x1 x2 y1 y2
1 -40 20 -30 50
2 -41 21 -31 51
From here, I would like to make two graphs:
ggplot(data=my_data, aes(x=var_1, y=var_2)) +
geom_point() +
geom_segment(aes(x = my_points[1,1], xend = my_points[1,2], y = my_points[1,3], yend = my_points[1,4]), color = "red") +
geom_segment(aes(x = my_points[1,2], xend = my_points[1,1], y = my_points[1,4], yend = my_points[1,3]), color = "red") +
geom_segment(aes(x = my_points[1,1], xend = my_points[1,2], y = my_points[1,4], yend = my_points[1,3]), color = "red") +
geom_segment(aes(x = my_points[1,1], xend = my_points[1,2], y = my_points[1,4], yend = my_points[1,3]), color = "red") + ggtitle("graph 1")
ggplot(data=my_data, aes(x=var_1, y=var_2)) +
geom_point() +
geom_segment(aes(x = my_points[2,1], xend = my_points[2,2], y = my_points[2,3], yend = my_points[2,4]), color = "red") +
geom_segment(aes(x = my_points[2,2], xend = my_points[2,1], y = my_points[2,4], yend = my_points[2,3]), color = "red") +
geom_segment(aes(x = my_points[2,1], xend = my_points[2,2], y = my_points[2,4], yend = my_points[2,3]), color = "red") +
geom_segment(aes(x = my_points[2,1], xend = my_points[2,2], y = my_points[2,4], yend = my_points[2,3]), color = "red") + ggtitle("graph 2")
But this is not producing the same result as before:
Furthermore, Graph 2 also does not work:
Can someone please show me how to fix this?
Thanks!

If you will use a data.frame, you cand do everything in a single call of geom_segment.
library(tidyverse)
var_1 = rnorm(1000,20,20)
var_2 = rnorm(1000,20,20)
my_data = data.frame(var_1, var_2)
my_points = tibble::tribble(
~rowid, ~x1, ~x2, ~y1, ~y2,
"h1", -50, 50, 50, 50,
"v1", 50, 50, -50, 50,
"h2", -50, 0, 0, 0,
"v2", 0, 0, -50, 0
)
ggplot(data = my_data, aes(x = var_1, y = var_2)) +
geom_point() +
geom_segment(data = my_points, aes(x = x1, xend = x2, y = y1, yend = y2), color = 'red')
You can use this structure as well, but now you need two geom_segment() calls
my_points2 = tibble::tribble(
~rowid, ~x1, ~y1, ~x2, ~y2,
"Segment 1", -50, 50, 50, -50,
"Segment 2", -50, 0, 0, -50,
)
ggplot(data = my_data, aes(x = var_1, y = var_2)) +
geom_point() +
# Horizontal lines
geom_segment(data = my_points2, aes(x = x1, y = y1, xend = x2, yend = y1), color = 'red') +
# Vertical lines
geom_segment(data = my_points2, aes(x = x2, y = y2, xend = x2, yend = y1), color = 'red')

OP requested to expand on a previous question related to drawing "half-rectangles" on a plot. The previous question dealt with actually drawing the rectangles, and in this question, OP would like to have the half rectangles drawn based on a separate dataframe called my_points.
Additionally, the dataframe my_points contains data in columns x1, x2, y1, and y2, which can be used to draw a pair of half rectangles on the plot. One key feature requested is that each row in the data frame my_points should draw a separate pair of half rectangles.
As with the previous answer to the original question, I'll demonstrate using separate calls to geom_segment(). One half rectangle requires two lines, so we'll need 4 calls to geom_segment() to draw a pair of half rectangles. The key here is to understand that each line has one terminus that extends beyond the plot area and will therefore be -Inf at either x (for the horizontal lines) or y (for the vertical lines).
The Plot
p <-
ggplot(data=my_data, aes(x=var_1, y=var_2)) +
geom_point(size=0.6) +
# vertical lines
geom_segment(data=my_points, aes(x=x1, xend=x1, y=-Inf, yend=y1), color='red') +
geom_segment(data=my_points, aes(x=x2, xend=x2, y=-Inf, yend=y2), color='red') +
# horizontal lines
geom_segment(data=my_points, aes(x=-Inf, xend=x1, y=y1, yend=y1), color='red') +
geom_segment(data=my_points, aes(x=-Inf, xend=x2, y=y2, yend=y2), color='red') +
theme_bw()
p
Separating out the Rows
If OP wants to separate each pair of half rectangles, you can use faceting or apply an aesthetic to associate with rownames(my_points). For convenience, it might make sense to first create a column in my_points for this purpose, but it is not strictly required.
my_points$graph <- rownames(my_points)
p <-
ggplot(data=my_data, aes(x=var_1, y=var_2)) +
geom_point(size=0.6) +
# vertical lines
geom_segment(data=my_points, aes(x=x1, xend=x1, y=-Inf, yend=y1, color=graph)) +
geom_segment(data=my_points, aes(x=x2, xend=x2, y=-Inf, yend=y2, color=graph)) +
# horizontal lines
geom_segment(data=my_points, aes(x=-Inf, xend=x1, y=y1, yend=y1, color=graph)) +
geom_segment(data=my_points, aes(x=-Inf, xend=x2, y=y2, yend=y2, color=graph)) +
theme_bw()
p
Extending to more Half Rectangles
We can extend this answer to accommodate a larger dataframe of my_points by adding some additional rows to my_points and using faceting as an example to demonstrate the principles above even further.
# moar points!!!1!1!!111!1!
my_points <- rbind(
my_points,
c(-20, 40, -20, 40),
c(-10, 60, -10, 30)
)
# adding the column... or just reference color=rownames(my_points) instead.
my_points$graph <- rownames(my_points)
p <-
ggplot(data=my_data, aes(x=var_1, y=var_2)) +
geom_point(size=0.6, alpha=0.3) +
# vertical lines
geom_segment(data=my_points, aes(x=x1, xend=x1, y=-Inf, yend=y1, color=graph)) +
geom_segment(data=my_points, aes(x=x2, xend=x2, y=-Inf, yend=y2, color=graph)) +
# horizontal lines
geom_segment(data=my_points, aes(x=-Inf, xend=x1, y=y1, yend=y1, color=graph)) +
geom_segment(data=my_points, aes(x=-Inf, xend=x2, y=y2, yend=y2, color=graph)) +
facet_wrap(~graph) +
theme_bw()
p
The key to remember when working this question is to keep track of how to reference x, xend, y and yend in the aesthetics for geom_segment(). OP was referencing those incorrectly in their attempts posted (resulting in the "X" instead of the half-rectangle).

Related

R: Erasing Lines on ggplot2 - drawing half rectangles

I am working with the R programming language.
I generated some random data and plotted the following graph:
library(ggplot2)
var_1 = rnorm(1000,20,20)
var_2 = rnorm(1000,20,20)
my_data = data.frame(var_1, var_2)
ggplot(data=my_data, aes(x=var_1, y=var_2)) + geom_point()
I now want to make the following pattern on this graph:
I tried to do this with the following code, but this is the closest I could get:
a1 = ggplot(data=my_data, aes(x=var_1, y=var_2)) +
geom_point()+
geom_hline(yintercept=0, color = "red") +
geom_vline(xintercept=0, color = "red")
a2 = a1 + geom_point() +
geom_hline(yintercept=50, color = "red") +
geom_vline(xintercept=50, color = "red")
My Question: Could someone please show me a "direct" way to make this pattern on this graph? Is there some way to "erase" these extra lines?
Suppose I had a data frame ("my_points") that looked like this:
my_points = data.frame(var_1_point_1 = 0, var_1_point_2 = 50, var_2_point_1 = 0, var_2_point_2 = 50)
Could the graph be made using "my_data", and the lines be made by "referencing" the points in "my_points"? For example, something like this:
a1 = ggplot(data=my_data, aes(x=var_1, y=var_2)) +
geom_point()+
geom_hline(yintercept my_points[1,2], color = "red") +
geom_vline(xintercept=my_points[1,1], color = "red")
Thanks!
You'll need to use geom_segment instead of geom_hline or geom_vline since you'll need to specify xend and yend for each segment.
library(tidyverse)
var_1 = rnorm(1000,20,20)
var_2 = rnorm(1000,20,20)
my_data = data.frame(var_1, var_2)
ggplot(data=my_data, aes(x=var_1, y=var_2)) +
geom_point() +
geom_segment(aes(x = -50, xend = 0, y = 0, yend = 0), color = "red") +
geom_segment(aes(x = 0, xend = 0, y = 0, yend = -50), color = "red") +
geom_segment(aes(x = -50, xend = 50, y = 50, yend = 50), color = "red") +
geom_segment(aes(x = 50, xend = 50, y = 50, yend = -50), color = "red")
Created on 2022-03-21 by the reprex package (v2.0.1)
Update
Since OP wish to use an extra dataframe, here is the updated code:
library(ggplot2)
var_1 = rnorm(1000,20,20)
var_2 = rnorm(1000,20,20)
my_data = data.frame(var_1, var_2)
mypoint <- data.frame(var_1_point_1 = c(-50, 0),
var_1_point_2 = c(0, -50),
var_2_point_1 = c(-50, 50),
var_2_point_2 = c(50, -50))
ggplot(data=my_data, aes(x=var_1, y=var_2)) +
geom_point() +
geom_step(data = mypoint, aes(var_1_point_1, var_1_point_2), color = "red") +
geom_step(data = mypoint, aes(var_2_point_1, var_2_point_2), color = "red")
Created on 2022-03-22 by the reprex package (v2.0.1)
People tend to forget about geom_linerange - in vanilla ggplot sadly only available for vertical lines. But there is also ggstance::geom_linerangeh. Those would allow you to pass a data frame with your x/y coordinates and you will "only" need two geom layers for vertical and for horizontal lines (if your lines always start at the edge of the plot). You could apply the same idea with geom_segment of course, then without need of another package.
library(ggplot2)
library(ggstance)
## changed data frame my points:
x <- y <- c(0, 50)
my_points <- data.frame(x, y)
ggplot() +
geom_point(aes(x = var_1, y = var_2), data = my_data) +
geom_linerange(aes(x = x, ymin = -Inf, ymax = y), data = my_points, color = "red", size = 2) +
geom_linerangeh(aes(xmin = -Inf, xmax = x, y = y), data = my_points, color = "red", size = 2)
Another option would be to make your own stat and use this with geom_segment:
library(ggplot2)
var_1 <- rnorm(1000, 20, 20)
var_2 <- rnorm(1000, 20, 20)
my_data <- data.frame(var_1, var_2)
## changed data frame my points:
x <- y <- c(0, 50)
my_points <- data.frame(x, y)
StatEdge <- ggproto("StatEdge", Stat, compute_group = function(data, scales) {
x <- c(rep(-Inf, nrow(data)), data$x)
y <- c(data$y, rep(-Inf, nrow(data)))
xend <- rep(data$x, nrow(data))
yend <- rep(data$y, nrow(data))
data.frame(x, xend, y, yend)
})
## now you can use the new stat for your geom
ggplot() +
geom_point(aes(x = var_1, y = var_2), data = my_data) +
geom_segment(data = my_points, aes(x, y), stat = "edge", size = 2, color = "red")
Created on 2022-03-21 by the reprex package (v2.0.1)

How to break x-axis while two y axes on each side with different scales?

I have below provided an example of the problem that I am trying to solve. As you can see that I have the y-axes names in the middle of the graph. Is there any way to remove those y-axes names? Thanks in advance.
library(ggbreak)
library(patchwork)
library(ggplot2)
x = c(0,0.1,0.5, 2, 3, 5, 7, 10, 100)
y1 = c(892, 1059, 1004, 1020, 1097, 903, 881,1096, 910)
y2 = c(2070, 2183, 2381, 2406, 2675, 2639, 2662, 2523, 2453)
data = data.frame(x=x, y1 = y1, y2 = y2)
ggplot(data=data,aes(x = x ,y=y1))+
geom_point(aes(y=y1), color = "black")+
geom_point(data = data,aes(x=x,y=y2),colour="blue")+
scale_y_continuous("Y1", sec.axis = sec_axis(y2~ .*(5) , name = "Y2"))+
xlab("x") +
ylab("")+
expand_limits(x = 0, y = 0)+
scale_x_break(c(12, 90))
Instead of using ggbreak one option would be to use just ggplot2 and patchwork which gives you "full" control to style the axes, to add and remove axis labels, ... :
library(patchwork)
library(ggplot2)
p <- ggplot(data = data, aes(x = x, y = y1)) +
geom_point(aes(y = y1), color = "black") +
geom_point(data = data, aes(x = x, y = y2), colour = "blue") +
labs(x = "x", y = NULL) +
expand_limits(x = 0, y = 0)
p1 <- p +
scale_y_continuous("Y1", sec.axis = sec_axis(y2 ~ . * (5), name = NULL)) +
coord_cartesian(xlim = c(NA, 12))
p2 <- p +
scale_y_continuous(name = NULL, sec.axis = sec_axis(y2 ~ . * (5), name = "Y2")) +
coord_cartesian(xlim = c(90, NA)) +
theme(axis.text.y = element_blank(), axis.ticks.y = element_blank())
p1 + p2
Try:
+theme(axis.title.y = element_blank())

columns are not aligned with the data in ggplot geom_col

plotting some data to a figure with numerical data, one would expect the column border to line up with the grid. However, when plotting this data, you can see that there are some that line up correctly (10, 5), but others don't (2, 1).
Is this a bug or a feature?
Reproducible example
library(tidyverse, scales)
The data
x1 <- c("a", "b", "c", "d", "e")
y1 <- c(1, 10, 2, 1, 5)
xy <- data.frame(x1, y1)
The plot
xy %>%
ggplot(aes(x = fct_reorder(x1, desc(y1)),
y = y1)) +
geom_col() +
geom_text(aes(label = y1), vjust = 1.5, colour = "white") # to show the numbers
Some experiments
Correct
xy %>%
ggplot(aes(x = fct_reorder(x1, desc(y1)),
y = y1)) +
geom_col() +
scale_y_continuous(minor_breaks = seq(0, 10, .5)) +
# scale_y_continuous(labels = scales::number_format(accuracy = .5)) +
geom_text(aes(label = y), vjust = 1.5, colour = "white")
But then
Incorrect
xy %>%
ggplot(aes(x = fct_reorder(x1, desc(y1)),
y = y1)) +
geom_col() +
scale_y_continuous(minor_breaks = seq(0, 10, .5)) +
scale_y_continuous(labels = scales::number_format(accuracy = .5)) +
geom_text(aes(label = y), vjust = 1.5, colour = "white")
Also incorrect
xy %>%
ggplot(aes(x = fct_reorder(x1, desc(y1)),
y = y1)) +
geom_col() +
scale_y_continuous(minor_breaks = seq(0, 10, 1),
labels = scales::number_format(accuracy = 1)) +
geom_text(aes(label = y1), vjust = 1.5, colour = "white")
That 2 in yaxis is 2.5 and near 1 is 1.25 not 1.
xy %>%
ggplot(aes(x = fct_reorder(x1, desc(y1)),
y = y1)) +
geom_col() +
scale_y_continuous(breaks = seq(0,10,2)) +
geom_text(aes(label = y1), vjust = 1.5, colour = "white")
xy %>%
ggplot(aes(x = fct_reorder(x1, desc(y1)),
y = y1)) +
geom_col()
I don't know why you add accuracy = 1 but take a look at plot below.
xy %>%
ggplot(aes(x = fct_reorder(x1, desc(y1)),
y = y1)) +
geom_col() +
scale_y_continuous(breaks = seq(0,10,2))
This is a rounding error caused by your scales_y_continuous call. Use
ggplot(xy,aes(x = fct_reorder(x1, desc(y1)),
y = y1)) +
geom_col() +
scale_y_continuous(breaks=c(0,2,5,8,10)) +
geom_text(aes(label = y1), vjust = 1.5, colour = "white")
To get what you want.

ggplot2 - how to limit panel and axis?

I want to know how to turn this plot:
Into this plot:
As you can see the panel and axis on the 2nd plot are limited to the data extent. I made the second graph using design software but want to know the code.
Ive already limited the x and y axis using
xlim and ylim but no difference.
Please see my code below, sorry its so messy, first time using r studio. Thanks!
ggplot() +
geom_errorbar(data = U1483_Coiling_B_M_Removed_R, mapping = aes(x = `Age (Ma) Linear Age Model`, ymin = `Lower interval*100`, ymax = `Upper interval*100`), width = 0.025, colour = 'grey') +
geom_line(data = U1483_Coiling_B_M_Removed_R, aes(x = `Age (Ma) Linear Age Model`, y = `Percent Dextral`)) +
geom_point(data = U1483_Coiling_B_M_Removed_R, aes(x = `Age (Ma) Linear Age Model`, y = `Percent Dextral`), colour = 'red') +
geom_point(data = U1483_Coiling_B_M_Removed_R, aes(x = `Age (Ma) Linear Age Model`, y = `Lab?`)) +
theme(axis.text.x=element_text(angle=90, size=10, vjust=0.5)) +
theme(axis.text.y=element_text(angle=90, size=10, vjust=0.5)) +
theme_classic() +
theme(panel.background = element_rect(colour = 'black', size = 1)) +
xlim(0, 2.85) +
ylim(0, 100)
You can use expand when specifying axis scales, like so:
# Load library
library(ggplot2)
# Set RNG
set.seed(0)
# Create dummy data
df <- data.frame(x = seq(0, 3, by = 0.1))
df$y <- 100 - abs(rnorm(nrow(df), 0, 10))
# Plot results
# Original
ggplot(df, aes(x, y)) +
geom_line() +
geom_point(colour = "#FF3300", size = 5)
# With expand
ggplot(df, aes(x, y)) +
geom_line() +
geom_point(colour = "#FF3300", size = 5) +
scale_y_continuous(expand = c(0, 0))

ggplot - add lines to plot - between points, not going through points

I'm trying to add lines to an existing plot.
Just ignore the data that is not plotted.
geom_abline lets me add lines but they go through the whole graph.
How can I crop the lines that they are only plotted e.g. between (0,0) and (10,-10)?
library(ggplot2)
x <- c(2,4,6,4,7,5,3)
y <- c(4,5,6,7,8,6,4)
data <- data.frame(cbind(x,y))
ggplot(data, aes(x= x, y= y)) +
expand_limits(y = c(25, -60), x = c(20,-5)) +
geom_abline(intercept = 0, slope = -1) +
geom_abline(intercept = 0, slope = -.5, linetype="dotted")
Maybe like this:
library(ggplot2)
x <- c(2,4,6,4,7,5,3)
y <- c(4,5,6,7,8,6,4)
data <- data.frame(cbind(x,y))
ggplot(data, aes(x= x, y= y)) +
expand_limits(y = c(25, -60), x = c(20,-5)) +
geom_segment(aes(x = 0, xend = 10, y = 0, yend = 0 - 1*10)) +
geom_segment(aes(x = 0, xend = 10, y = 0, yend = 0 - 0.5*10),
linetype = 2)

Resources