-
Notifications
You must be signed in to change notification settings - Fork 2k
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
TLC for polar coordinates: coord_radial()
#5334
Conversation
…nto polar_guides
R/guide-axis-theta.R
Outdated
GuideAxisTheta <- ggproto( | ||
"GuideAxisTheta", GuideAxis, | ||
|
||
# TODO: delete if minor ticks PR (#5287) gets merged |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This may be simplified once #5287 is merged.
@@ -41,7 +44,7 @@ | |||
#' | |||
#' # can also be used to add a duplicate guide | |||
#' p + guides(x = guide_axis(n.dodge = 2), y.sec = guide_axis()) | |||
guide_axis <- function(title = waiver(), check.overlap = FALSE, angle = NULL, | |||
guide_axis <- function(title = waiver(), check.overlap = FALSE, angle = waiver(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The default is now waiver()
because coord_polar2()
may overrule angle for display purposes, but NULL
still uses the theme's angle.
return(element_text(angle = NULL, hjust = NULL, vjust = NULL)) | ||
} | ||
|
||
# it is not worth the effort to align upside-down labels properly | ||
check_number_decimal(angle, min = -90, max = 90) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I very much did need some alignments for upside-down labels, so I have expanded this function to include this. Due to this, some angles in the svg snapshots have changed from e.g. 45 degrees to -315 degrees but that doesn't matter visually.
position <- params[[1]]$position %||% scale$position | ||
if (position != scale$position) { | ||
order <- rev(order) | ||
if (!is.null(params)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Layout doesn't know about theta/r guides, so had to avoid taking labels from NULL
params here that are returned when the x/y guide doesn't exist.
Also worth pointing out that interactions with e.g. {ggtext} aren't that horrible: devtools::load_all("~/packages/ggplot2/")
#> ℹ Loading ggplot2
library(ggtext)
labels <- c(
setosa = "<img src='https://upload.wikimedia.org/wikipedia/commons/thumb/8/86/Iris_setosa.JPG/180px-Iris_setosa.JPG'
width='100' /><br>*I. setosa*",
virginica = "<img src='https://upload.wikimedia.org/wikipedia/commons/thumb/3/38/Iris_virginica_-_NRCS.jpg/320px-Iris_virginica_-_NRCS.jpg'
width='100' /><br>*I. virginica*",
versicolor = "<img src='https://upload.wikimedia.org/wikipedia/commons/thumb/2/27/20140427Iris_versicolor1.jpg/320px-20140427Iris_versicolor1.jpg'
width='100' /><br>*I. versicolor*"
)
ggplot(iris, aes(Species, Sepal.Width)) +
geom_boxplot() +
scale_x_discrete(
name = NULL,
labels = labels
) +
coord_polar2(r_axis_inside = TRUE) +
theme(
axis.text.x = element_markdown(color = "black", size = 11),
axis.title.y = element_blank(),
plot.margin = margin(5,5,70,5)
) Created on 2023-06-25 with reprex v2.0.2 Note that you couldn't do this with regular |
Name suggestion: |
Latest changes:
Should be ready for review :) |
coord_radial()
I couldn't really use |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I approve this, but please fix the small style stuff I commented on
R/guide-axis-theta.R
Outdated
# We likely have a linear coord, so we match the text angles to | ||
# standard axes. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens if this axis is used with a non-radial coord?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It will draw a very normal looking axis with slightly inferior options for text justification.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
devtools::load_all("~/packages/ggplot2")
#> ℹ Loading ggplot2
ggplot(mpg, aes(displ, hwy)) +
geom_point() +
guides(x = "axis_theta", y = "axis_theta") +
theme(axis.line = element_line())
Created on 2023-11-20 with reprex v2.0.2
Thanks for the review Thomas! |
This PR fixes #4815, fixes #5059, fixes #3959, and fixes #4462
Briefly, this PR introduces a new coord system
coord_polar2()
with expanded options (name of function and arguments are up for discussion).Less briefly, this PR started out with a simpler goal of having
coord_polar()
use the axis system. Realising that this couldn't be done without breaking backward compatibility, this has instead becomecoord_polar2()
. This PR then started accumulating additional features and here we are today. I think it might be best to explain this PR with a visual walkthrough.If we use
coord_polar2()
plainly, we see it resemblescoord_polar()
with the following differences:panel.background
theme setting is applied to the circle that forms the background. You can still usepanel.border = element_rect(fill = NA)
in the theme if you need a frame for the plot.expand = TRUE
default argument so that the behaviour of scale expansion is more in line withcoord_cartesian()
than withcoord_polar()
.One feature is that we can also place the radius axis inside the circle. Admittedly, this looks a little bit awkward because it intersects with the theta axis, which is why this isn't the default when you have a full circle.
The next feature is that requested in #4462, namely to have partial polar coordinates. The following things are of note:
start
andend
arguments to control which sector of a circle the plot occupies.coord_polar2(r_axis_inside = FALSE)
to prevent this.Then the reason I started this PR: #3959. A few comments:
guide_axis_theta()
that can be used for the theta axis.guides(theta = "axis")
also throws a warning.angle
argument is set, either in a radius axis or theta axis, this is interpreted as a relative angle. Note that the theta text follows the curvature and that the radius text are projected from the tick marks.I then took a little bit of a liberty and decided on my own it would be fun to also be able to set a donut hole in polar coordinates. This is mostly just a convenience that doesn't force you to fiddle with the scale limits or expansions to not have all shapes disappear in a single point at the center. Also, it is the only circumstance I could ever imagine that you'd need a secondary theta axis.
Lastly, I also implemented #5059, since getting the (relative) angle right in text geoms in polar coordinates is a bit of pain. Text between 90 and 270 degrees is flipped for readability reasons.
Created on 2023-06-25 with reprex v2.0.2
A few closing remarks:
guide_axis_theta()
also works reasonably well with cartesian coordinates.guide_axis_theta()
does not respond tohjust/vjust
settings, mostly because text placement had given me enough headaches at this point and the theme's defaults translate horribly to the theta axis.theta
positions usesx.bottom
theme settings,theta.sec
usesx.top
,r
/r.sec
usey.left
/y.right
depending on thedirection
argument. In theory, we could change this, but it would involve some hairy adaptations toguide_axis()
as well.