-
Notifications
You must be signed in to change notification settings - Fork 26
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Extract y position of stat_dots? #208
Comments
Yeah, dot positions can't be known until draw time because they are determined dynamically based on the plot dimensions. To do this you have to pre-determine the binwidth and use a fixed coordinate system for the chart axes. Here's an example based on this comment: #182 (comment) library(dplyr)
library(ggplot2)
library(ggdist)
# determine the binwidth
# you could also skip this step and manually specify a binwidth... maxheight
# here is the max height of the chart assuming y units and x units are square,
# and is intended to get a chart with around a 3/2 aspect ratio
hp_over_wt = with(mtcars, hp/wt)
binwidth = find_dotplot_binwidth(hp_over_wt, maxheight = 2/3*diff(range(hp_over_wt)), heightratio = 1)
bin_df = bin_dots(x = hp_over_wt, y = 0, binwidth = binwidth, heightratio = 1)
# bin the dots
cbind(mtcars, bin_df) |>
ggplot(aes(x0 = x, y0 = y / binwidth, a = binwidth/2, b = 1/2, angle = 0)) +
ggforce::geom_ellipse() +
ggrepel::geom_text_repel(aes(label = rownames(mtcars), x = x, y = y/binwidth), min.segment.length = 0) +
coord_fixed(ratio = binwidth) To do multiple groups like in your plot you'd have to do multiple calls to bin_dots, one for each group, and manually offset their y positions. |
Forgot to point out you can supply the library(dplyr)
library(ggplot2)
library(ggdist)
# determine the binwidth
# you could also skip this step and manually specify a binwidth... maxheight
# here is the max height of the chart assuming y units and x units are square,
# and is intended to get a chart with around a 3/2 aspect ratio
binwidth = find_dotplot_binwidth(with(mtcars, hp/wt), maxheight = 2/3*diff(range(hp_over_wt)), heightratio = 1)
bin_df = bin_dots(x = with(mtcars, hp/wt), y = 0, binwidth = binwidth, heightratio = 1, layout = "swarm", side = "both")
# bin the dots
cbind(mtcars, bin_df) |>
ggplot(aes(x0 = x, y0 = y / binwidth, a = binwidth/2, b = 1/2, angle = 0)) +
ggforce::geom_ellipse() +
ggrepel::geom_text_repel(aes(label = rownames(mtcars), x = x, y = y/binwidth), min.segment.length = 0) +
coord_fixed(ratio = binwidth) |
And here's a different version that keeps things stacked within a height of 1 on the y axis if that's easier to use for stacking groups: library(dplyr)
library(ggplot2)
library(ggdist)
# determine the binwidth
# you could also skip this step and manually specify a binwidth... maxheight
# here is the max height of the chart assuming y units and x units are square,
# and is intended to get a chart with around a 3/2 aspect ratio
hr = 3/2/diff(range(hp_over_wt))
binwidth = find_dotplot_binwidth(with(mtcars, hp/wt), maxheight = 1, heightratio = hr)
bin_df = bin_dots(x = with(mtcars, hp/wt), y = 0, binwidth = binwidth, heightratio = hr, side = "both", layout = "swarm")
# bin the dots
cbind(mtcars, bin_df) |>
ggplot(aes(x0 = x, y0 = y, a = binwidth/2, b = binwidth*hr/2, angle = 0)) +
ggforce::geom_ellipse() +
ggrepel::geom_text_repel(aes(label = rownames(mtcars), x = x, y = y), min.segment.length = 0) +
coord_fixed(ratio = 1/hr) |
Incredible @mjskay! For posterity here is where I landed for the original use case.
That reference to #183 helps with another use case I've had as well. Thank you so much for this project it is crazy useful. Cheers, and close this if you'd like, or keep it open in case there is future work to be done |
Awesome, glad this worked!! I'll close this since I don't think this kind of thing is likely to become easier anytime soon unless I decide it's worth adding a specialized geom for it. It's really down to a limitation of ggplot's drawing model that we can't know dot positions until it's too late. |
I am trying to use
stat_dots
along with the very goodggrepel::geom_text_repel
to create a dot plot as well as label the points with a name. Here is a reprexWhich produces this:
where the anchor point for
ggrepel::geom_text_repel
is pointing to the baseline y for the factors rather than the true position of the dots.I tried to dig around in
layer_data
andlayer_grob
to see if I could find the position to extract, as well as trying to pick apart and recalculate thebin_dots
function call, but I couldn't quite make it work.Looking around it seems similar or related to #26 in that "it'd be cool but really hard".
Cheers!
The text was updated successfully, but these errors were encountered: