Adding horizontal lines in the plot of a step function - r

I attach graphic, image.jpg, in which I want to draw the line y=0 for x<3 and the line y=1 for x>=8, i.e. the result would be image2.jpg.
These are the instructions for image.jpg.
df <- data.frame(x=Asignaturas, y=solF)
df$xend <- c(df$x[2:nrow(df)],NA)
df$yend <- df$y
p <- (ggplot(df, aes(x=x, y=y, xend=xend, yend=yend)) +
geom_vline(aes(xintercept=x), linetype=2,color="grey") +
geom_point() + # Solid points to left
geom_point(aes(x=xend, y=y), shape=1) + # Open points to right
geom_segment() + # Horizontal line
geom_text(aes(label = paste0(solF,''),vjust = -0.5), color = "black") +
ylab("Función de distribucción") +
xlab("Asignaturas"))
p
Does anyone know how to do it?
Thanks

An option using base R.
plot(df$x, df$y, xlim=c(2.5, max(df$x) + .5), ylim=c(0, 1.075), pch=19)
points(df$x + 1, df$y, pch=1)
segments(df$x, df$y, df$x + 1)
text(df$x, df$y + .05, df$y)
sapply(0:1, \(x) lines(2:3 + x*6, rep(x, 2), col='red'))
Or just
plot(df$x, df$y, type='s', xlim=c(2.5, max(df$x) + .5), ylim=c(0, 1.075))
text(df$x, df$y + .05, df$y)
sapply(0:1, \(x) lines(2:3 + x*6, rep(x, 2), col='red'))
Data:
df <- structure(list(y = c(0, 0.14, 0.31, 0.48, 0.67, 0.82, 1), x = c(2,
3, 4, 5, 6, 7, 8)), class = "data.frame", row.names = c(NA, -7L
))

If you want to stick with ggplot2, the geom_segment() will give what you're looking for. Make a data.frame of the parameters and then add the geom_segment().
extraLines <- data.frame(x = c(-Inf, max(df$x)), xend = c(min(df$x), Inf), y = c(2, max(df$y)), yend = c(2, max(df$y)))
p +
geom_segment(data = extraLines, aes(x = x, xend = xend, y = y, yend = yend), colour = "red") +
geom_point(data = filter(extraLines, x > 0), aes(x = x, y=y), colour = "red") +
geom_point(data = filter(extraLines, x < max(df$x)), aes(x=xend, y=y), shape = 1, colour = "red")

Related

Convert plot to ggplot and add horizontal lines until specific points

I have creted the plot below using the base R plot() function but I would like to convert it to ggplot() and also add horizontal lines like in the example picture but until the crossing with the graphs and not a full continuing horizontal line until the end.
# Figure 3.1 & 3.2
# curve(logistic(pnorm(x), a=1, d=0),-3,3,ylab="Probability of x",
# main="Logistic transform of x",xlab="z score units")
# #logistic with a=1.702 is almost the same as pnorm
# curve(logistic(pnorm(x), d=1),add=TRUE)
# Set x-axis values
theta <- seq(from = -10, to = 10, by = 0.001)
# Code for plot1
B_i <- 1
B_j <- -1
P_item1_rasch <- NULL
P_item2_rasch <- NULL
for (i in 1:length(theta)){
P_item1_rasch[i] <- (exp((theta[i]-B_i)))/(1+(exp((theta[i]-B_i))))
P_item2_rasch[i] <- (exp((theta[i]-B_j)))/(1+(exp((theta[i]-B_j))))
}
#select the colors that will be used
library(RColorBrewer)
#all palette available from RColorBrewer
display.brewer.all()
#we will select the first 4 colors in the Set1 palette
cols<-brewer.pal(n=4,name="Set1")
#cols contain the names of four different colors
plot(theta, P_item1_rasch, xlim=c(-4,4), ylim=c(0,1))
lines(theta, P_item2_rasch,col=cols[2])
# Add lines at the values below, but only half as in the example Figures
# abline(h=0.5)
# abline(v=-1)
# abline(v=1)
Perhaps something like this?
theta <- seq(from = -10, to = 10, by = 0.001)
# Code for plot1
B_i <- 1
B_j <- -1
P_item0_rasch <- NULL
P_item1_rasch <- NULL
P_item2_rasch <- NULL
for (i in 1:length(theta)){
P_item0_rasch[i] <- (exp((theta[i])))/(1+(exp((theta[i]))))
P_item1_rasch[i] <- (exp((theta[i]-B_i)))/(1+(exp((theta[i]-B_i))))
P_item2_rasch[i] <- (exp((theta[i]-B_j)))/(1+(exp((theta[i]-B_j))))
}
df <- data.frame(theta = rep(theta, 3),
P_item_rasch = c(P_item0_rasch, P_item1_rasch, P_item2_rasch),
number = factor(rep(1:3, each = length(theta))))
library(ggplot2)
ggplot(df, aes(theta, P_item_rasch, color = number)) +
geom_line() +
lims(x = c(-6, 6)) +
geom_segment(x = -1, xend = 1, y = 0.5, yend = 0.5, lty = 2) +
geom_vline(xintercept = c(-1, 0, 1), lty = 2) +
scale_color_manual(values = RColorBrewer::brewer.pal(4, "Set1")[-1]) +
theme_classic() +
theme(legend.position = "none")
#> Warning: Removed 24000 row(s) containing missing values (geom_path).
Edit
The OP changed the question to alter the requirements. Here is a way to achieve them:
ggplot(df, aes(theta, P_item_rasch)) +
geom_line(aes(color = number)) +
lims(x = c(-6, 6)) +
# Line between curves
geom_segment(x = -1, xend = 1, y = 0.5, yend = 0.5, lty = 2) +
# Optional line on left
geom_segment(x = -Inf, xend = -1, y = 0.5, yend = 0.5, lty = 2) +
# Lower lines
geom_segment(data = data.frame(theta = c(-1, 0, 1), P_item_rasch = rep(-Inf, 3)),
aes(xend = theta, yend = 0.5), lty = 2) +
# Upper lines
#geom_segment(data = data.frame(theta = c(-1, 0, 1), P_item_rasch = rep(Inf, 3)),
# aes(xend = theta, yend = 0.5), lty = 2) +
scale_color_manual(values = RColorBrewer::brewer.pal(4, "Set1")[-1]) +
theme_classic() +
theme(legend.position = "none")
Created on 2020-12-06 by the reprex package (v0.3.0)

Lines on top and bottom of ggplot plot area

I want to add a line on the top and bottom of my plots (bottom line below the x label and axis) created using ggplot2. So far I have added a rectangle around the plot, but I do not want the lines on the sides.
x <- 1:10
y <- rnorm(10,mean = x)
df <- data.frame(x,y)
library(ggplot2)
ggplot(data = df, mapping = aes(x,y)) + geom_point() +
theme(plot.background = element_rect(size = 1, color = 'blue'))
I hope you guys have a solution.
Will something similar to this work?
x <- 1:10
y <- rnorm(10,mean = x)
df <- data.frame(x,y)
ggplot(data = df, mapping = aes(x,y)) + geom_point() +
annotate(geom = 'segment',
y = Inf,
yend = Inf,
x = -Inf,
xend = Inf,
size = 2) +
theme(axis.line.x = element_line(size = 1))
Not a perfect, but working solution. You have to plot huge "-" (size = 1000) outside plot area. This solution is not perfect as you have to manually adjust position of "-" on the y-axis.
df <- data.frame(x = 1:10, y = 1:10)
library(ggplot2)
ggplot(df, aes(x, y)) +
geom_point() +
# Y position adjusted manually
geom_text(aes(5, 2.9, label = "-"), color = "blue", size = 1000) +
# Y position adjusted manually
geom_text(aes(5, 21.2, label = "-"), color = "blue", size = 1000) +
# Plot outside plot area
coord_cartesian(ylim = c(0, 10), clip = "off")
I am not completely happy with the solution as I don't fully grasp
how to change the size of the lines
why they are not perfectly aligned with top and bottom when using patchwork::wrap_plots()
why it does not show the top line using ggpubr::ggarrange() or cowplot::plot_grid()
but based on this code, I suggest the following solution:
library(ggplot2)
df <- data.frame(x = 1:5, y = 1:5)
p <- ggplot(data = df) + aes(x, y) + geom_point()
top_line <- grid::grobTree(grid::linesGrob(x = grid::unit(c(0, 1), "npc"), y = grid::unit(1, "npc")))
bot_line <- grid::grobTree(grid::linesGrob(x = grid::unit(c(0, 1), "npc"), y = grid::unit(0, "npc")))
patchwork::wrap_plots(top_line, p, bot_line,
ncol = 1, nrow = 3,
heights = c(0, 1, 0))
ggpubr::ggarrange(top_line, p, bot_line,
ncol = 1, nrow = 3,
heights = c(0, 1, 0))
cowplot::plot_grid(top_line, p, bot_line,
ncol = 1, nrow = 3,
rel_heights = c(0, 1, 0))
Created on 2022-08-25 with reprex v2.0.2

I'd like to paint an area but i don't know how to

I mean, I'd want to paint only the square area P1 X (Q1-Q2).
Not the trapezoid (P2+P1) X (Q1-Q2/2).
Here's code that I used. I used ggplot and dplyr. How can I solve this problem?
How can I paint the only square area not the trapezoied area!!!!
library(ggplot2)
library(dplyr)
supply <- Hmisc::bezier(x = c(1, 8, 9),
y = c(1, 5, 9)) %>%
as_data_frame()
demand <- Hmisc::bezier(c(1, 3, 9),
c(9, 3, 1)) %>%
as_data_frame()
fun_supply <- approxfun(supply$x, supply$y, rule = 2)
fun_supply(c(2, 6, 8))
fun_demand <- approxfun(demand$x, demand$y, rule = 2)
intersection_funs <- uniroot(function(x) fun_supply(x) - fun_demand(x), c(1, 9))
intersection_funs
y_root <- fun_demand(intersection_funs$root)
curve_intersect <- function(curve1, curve2) {
# Approximate the functional form of both curves
curve1_f <- approxfun(curve1$x, curve1$y, rule = 2)
curve2_f <- approxfun(curve2$x, curve2$y, rule = 2)
# Calculate the intersection of curve 1 and curve 2 along the x-axis
point_x <- uniroot(function(x) curve1_f(x) - curve2_f(x),
c(min(curve1$x), max(curve1$x)))$root
# Find where point_x is in curve 2
point_y <- curve2_f(point_x)
# Finish
return(list(x = point_x, y = point_y))
}
intersection_xy <- curve_intersect(supply, demand)
intersection_xy
intersection_xy_df <- intersection_xy %>% as_data_frame()
demand2 <- Hmisc::bezier(c(1.5, 3.5, 9.5),
c(9.5, 3.5, 1.5)) %>%
as_data_frame()
supply2 <- Hmisc::bezier(c(1,7,8),
c(3,7,11)) %>%
as_data_frame()
#Make a data frame of the intersections of the supply curve and both demand curves
intersections <- bind_rows(curve_intersect(supply, demand),
curve_intersect(supply2, demand2))
plot_labels <- data_frame(label = c("S", "D","S[1]","D[1]"),
x = c(9, 1, 6.5, 3),
y = c(8, 8, 8, 8))
ggplot(mapping = aes(x = x, y = y)) +
geom_path(data = supply, color = "#0073D9", size = 1, linetype = "dashed") +
geom_path(data = demand, color = "#FF4036", size = 1, linetype = "dashed") +
geom_path(data = demand2, color = "#FF4036", size = 1) +
geom_path(data = supply2, color = "#0073D9", size = 1) +
geom_segment(data = intersections,
aes(x = x, y = 0, xend = x, yend = y), lty = "dotted") +
geom_segment(data = intersections,
aes(x = 0, y = y, xend = x, yend = y), lty = "dotted") +
geom_segment(data = intersections,
aes(x = x, y = y, xend = x, yend= y), lty = "dotted") +
geom_point(data = intersections, size = 3) +
geom_text(data = plot_labels,
aes(x = x, y = y, label = label), parse = TRUE) +
scale_x_continuous(expand = c(0, 0), breaks = intersections$x,
labels = expression(Q[1], Q[2])) +
scale_y_continuous(expand = c(0, 0), breaks = intersections$y,
labels = expression(P[1], P[2]))+
labs(x = "Quantity", y = "Price") +
geom_area(data =intersections, fill="#9999FF", alpha=0.5) +
theme_classic() +
coord_equal()
Could you help me to paint the area that I mentioned.
You might try adding geom_rect(data=intersections[1,], aes(xmin=0, xmax=x, ymin=0, ymax=y),fill='green', alpha=0.5) to your plot call.
So we have:
ggplot(mapping = aes(x = x, y = y)) +
geom_path(data = supply, color = "#0073D9", size = 1, linetype = "dashed") +
geom_path(data = demand, color = "#FF4036", size = 1, linetype = "dashed") +
geom_path(data = demand2, color = "#FF4036", size = 1) +
geom_path(data = supply2, color = "#0073D9", size = 1) +
geom_segment(data = intersections,
aes(x = x, y = 0, xend = x, yend = y), lty = "dotted") +
geom_segment(data = intersections,
aes(x = 0, y = y, xend = x, yend = y), lty = "dotted") +
geom_segment(data = intersections,
aes(x = x, y = y, xend = x, yend= y), lty = "dotted") +
geom_point(data = intersections, size = 3) +
geom_text(data = plot_labels,
aes(x = x, y = y, label = label), parse = TRUE) +
scale_x_continuous(expand = c(0, 0), breaks = intersections$x,
labels = expression(Q[1], Q[2])) +
scale_y_continuous(expand = c(0, 0), breaks = intersections$y,
labels = expression(P[1], P[2]))+
labs(x = "Quantity", y = "Price") +
geom_area(data =intersections, fill="#9999FF", alpha=0.5) +
theme_classic() +
coord_equal()+
geom_rect(data=intersections[1,], aes(xmin=0, xmax=x, ymin=0, ymax=y),fill='green', alpha=0.5)
Edit based on comment:
geom_rect(data=intersections, aes(xmin=x[2], xmax=x[1], ymin=0, ymax=y[1]),fill='green', alpha=0.5)
Though the answer from J Con is in depth and does provide a solution, a cleaner approach in ggplot2 may be to use the annotate function, with geom and other arguments set appropriately. (See link for help page.)
This is because using something like geom_rect involves passing positions and so on as a data.frame, which is a bit more of a hack as, conceptually, from a grammar of graphics perspective, the data layer and the annotation layer are distinct: the act of mapping data variables to graphical aesthetics in a systematic and objective way, and of marking up features within the dataset in a piecemeal and subjective way, are separate activities, and using annotate explicitly for the latter purpose makes this divide clearer in terms of the code and concepts.
Edit
To be more specific, the annotate equivalent of the following:
geom_rect(data=intersections, aes(xmin=x[2], xmax=x[1], ymin=0, ymax=y[1]),fill='green', alpha=0.5)
Would likely be as follows
annotate(
geom = "rect",
xmin = intersections$x[2], x = intersections$x[1],
ymin = 0, ymax = intersections$y[1],
fill = 'green', alpha = 0.5
)
Functionally this is exactly the same, but conceptually it makes the separation between the data layer and the annotation layer much clearer in the code expressed.
Note: Annotate could also be used for the points and text.

Draw segment below density plot using relative y?

I want to draw a segment below a density plot and I would like to have the distance be a constant number of pixels. Is this possible? I Know how to hardcode the distance. For example:
set.seed(40816)
library(ggplot2)
df.plot <- data.frame(x = rnorm(100, 0, 1))
ggplot(df.plot, aes(x = x)) + geom_density() +
geom_segment(aes(x = -1, y = -0.05, xend = 1, yend = -0.05),
linetype = "longdash")
produces :
But
df.plot <- data.frame(x = rnorm(100, 0, 4))
ggplot(df.plot, aes(x = x)) + geom_density() +
geom_segment(aes(x = -1, y = -0.025, xend = 1, yend = -0.025),
linetype = "longdash")
produces a plot with the segment much further away from the density
You could use annotation_grob,
set.seed(40816)
library(ggplot2)
df.plot <- data.frame(x = rnorm(100, 0, 1))
strainerGrob <- function(pos=unit(2,"mm"), gp=gpar(lty=2, lwd=2))
segmentsGrob(0, unit(1,"npc") - pos, 1, unit(1,"npc") - pos, gp=gp)
ggplot(df.plot, aes(x = x)) + geom_density() +
annotation_custom(strainerGrob(), xmin = -1, xmax = 1, ymin=-Inf, ymax=0) +
expand_limits(y=-0.1)

how to overlay a line plot with a density plot? (R, ggplot2)

Hi how do I overlap the following curves in one graph? Any help's appreciated. Thank you!
library(ggplot2)
x = -10:10
y = dnorm(x, mean=0, sd=3)
df.norm = data.frame('x'=x, 'y'=y)
ggplot(data=df.norm, aes(x=x, y=y)) +
geom_line() +
geom_point()
random = data.frame('x'=rnorm(1000, mean = 0, sd = 3))
ggplot(random, aes(x=x)) +
geom_density(size=1)
I tried the following and it didn't work
ggplot(data=df.norm, aes(x=x, y=y)) +
geom_line() +
geom_point() +
geom_density(random, aes(x=x), size=1)
library(ggplot2)
x = -10:10
y = dnorm(x, mean=0, sd=3)
df.norm = data.frame('x'=x, 'y'=y)
random = data.frame('x'=rnorm(1000, mean = 0, sd = 3))
ggplot() +
geom_line(data=df.norm, aes(x=x, y=y)) +
geom_point(data=df.norm, aes(x=x, y=y)) +
geom_density(data=random, aes(x=x), size=1)
ggplot2
A more concise version in ggplot2 using the argument inherit.aes = FALSE inside geom_density to override the default aesthetics used in the previous two layers.
library(ggplot2)
set.seed(2017)
x = -10:10
y = dnorm(x, mean = 0, sd = 3)
df.norm = data.frame('x' = x, 'y' = y)
random = data.frame('x' = rnorm(1000, mean = 0, sd = 3))
ggplot(data = df.norm, aes(x = x, y = y)) +
geom_line() +
geom_point() +
geom_density(data = random,
aes(x = x),
inherit.aes = FALSE,
size = 1)
Base
Adapting the solution provided by scoa to the base package:
plot(df.norm, type = "l", bty = "n", las = 1)
points(df.norm, pch= 19)
lines(density(random$x), lwd = 2)
Adding a legend, and a different colour for the density curve:
plot(df.norm, type = "l", bty="n", las = 1)
points(df.norm, pch= 19)
lines(density(random$x), lwd =2, col = 'orange')
legend(x = "topleft",
c("df.norm", "Density plot"),
col = c("black", "orange"),
lwd = c(2, 2),
bty = "n")

Resources