There are a few questions around how to create a 'type = b' look with ggplot (e.g. here and here)
The currently best solution is simply creating bigger dots in the color of the underlying background - which is admittedly very straight forward.
I am looking for a solution with geom_segment
- because the current solution does not allow for additional 'fanciness', in particular: error bands. See graph at the bottom. (I know that I can use lines for the confidence intervals, and this looks good, but the question is regarding the below)
I have made a simple function using basic trigonometry in order to calculate x and y for the segments in geom_segment
(see below - thanks to @moody_mudskipper to give the main ideas how to approach this). Now, this only works with coord_equal
(see below). My question is, how can I obtain the axis ratio from the plot which is created in order to use this ratio for calculation of the x/y segments?
library(ggplot2)
# function to get data frame with x and y parameters for geom_segment
get_segments <- function(df, x, y, param){
# hyp = hypotenuse of right triangle between x and y of dot plot
# sin_plot and cos_plot = sine and cosine of right triangle of dot plot
# diff_..._seg = hypotenuse of segment added to main dot plot
x <- df[[deparse(substitute(x))]]
y <- df[[deparse(substitute(y))]]
hyp <-sqrt(diff(x)^2 + diff(y)^2)
sin_plot <- diff(y) / hyp
cos_plot <- diff(x) / hyp
diff_x1_seg <- param * cos_plot
diff_x2_seg <- (hyp-param) * cos_plot
diff_y1_seg <- param * sin_plot
diff_y2_seg <- (hyp-param) * sin_plot
x1 <- c(head(x,-1) + diff_x1_seg)
x2 <- c(head(x,-1) + diff_x2_seg)
y1 <- c(head(y,-1) + diff_y1_seg)
y2 <- c(head(y,-1) + diff_y2_seg)
plot_data <- data.frame(x1,x2,y1,y2)
plot_data$x1 <- ifelse(plot_data$x1 > plot_data$x2, NA, x1)
plot_data
}
# Using the function on sample data
plot_data <-
get_segments(pressure, x = temperature, y = pressure, 15)
# Making the plot
p1 <- ggplot(pressure, aes(temperature, pressure)) +
geom_point() +
geom_segment(data = plot_data, mapping = aes(x = x1, xend = x2, y = y1, yend = y2))
Plot without coord_equal
- does not really work
p1
#> Warning: Removed 11 rows containing missing values (geom_segment).
Plot with coord_equal
- gives the right segments
p1 + coord_equal()
#> Warning: Removed 11 rows containing missing values (geom_segment).
Example what could be nice:
ggplot(pressure, aes(temperature, pressure)) +
geom_ribbon(aes(ymin = pressure - 50, ymax = pressure + 50), alpha = 0.2) +
geom_point() +
geom_segment(data = plot_data, mapping = aes(x = x1, xend = x2, y = y1, yend = y2))
#> Warning: Removed 11 rows containing missing values (geom_segment).
P.S. I know that I could just plot the ribbon above the plot, but this gets less nice when using different grey values. And again, this question is more about how to get the axis ratio...
Created on 2019-04-25 by the reprex package (v0.2.1)
Well, unless you manually set the axis ratio with for example
theme(aspect.ratio ...)
, orcoord_fixed()
you can't, since the plots adjust their positioning based on the size of the device.To check this, you can make your plot into a gtable by
ggplotGrob(myplot)
and look at the layout what graphical object is the panel.In that layout you can see the t (top) and l (left) position of the panel.
You can see above that the panel is the sixth grob in the list and has position 7 of the heights and position 5 of the widths.
The height and width of panels are usually defined in
null
units, which is a special unit that kind of tells the graphics device to calculate all other elements first and use the leftover space to place thenull
-sized graphical elements.Furthermore, the plot has a
respect
parameter that tells the graphics device wether the ratio betweennull
units should be 1:1 or are free. This parameters is set to true when there is a known aspect ratio, or byfacet_grid(space = ..., scale = ...)
parameters. Ifrespect == TRUE
, then a grob with a height of2null
and a width of1null
will have an aspect ratio of 2.I don't want to leave you with all bad news so I'm gonna point out that you can also use these widths and heights in the gtable to set them to your liking.
Which could help you plot the perfect
type = b
style plots.Off-topic but tangentially related, back at your previous question I also had a go at making the geometric interpretation of the plot (wasn't succesfull so didn't post it), without the point over point trick. I also had a lot of trouble with the aspect ratio, since the exact placing of the points changed on the device size. Under the hood, the grid package that makes graphical objects (grobs) by default use normalised parent coordinates (npc, see
?unit
). A thing that seemed to be pointing in the right direction was converting what you namedhyp - param
with the equivalent ofunit(hyp, "npc") - convertUnit(unit(param, "mm"), "npc", axisFrom = "y", typeFrom = "dimension")
(for the y-axis, I was already working withnpc
units for my coordinates). Now I wasn't able to implement this properly, but maybe it would help you get some ideas.