以编程方式在 R ggplot2 中标记多个 ablines
Programmatically label multiple ablines in R ggplot2
关于在 ggplot2
中标记单个 geom_abline()
的现有问题:
- R ggplot2: Labelling a horizontal line on the y axis with a numeric value
- Add label to abline ggplot2 [duplicate]
None 其中的一个用例是我想将多条参考线添加到散点图,目的是允许对斜率范围内的点进行轻松分类。这是该图的可重现示例:
library(ggplot2)
set.seed(123)
df <- data.frame(
x = runif(100, 0, 1),
y = runif(100, 0, 1))
lines <- data.frame(
intercept = rep(0, 5),
slope = c(0.1, 0.25, 0.5, 1, 2))
p <- ggplot(df, aes(x = x, y = y)) +
geom_point() +
geom_abline(aes(intercept = intercept, slope = slope),
linetype = "dashed", data = lines)
p
由于我发现无法通过其他问题以编程方式执行此操作,因此我通过数据框“缩放”了手动方法,使用反复试验找出合理的标签位置。
labels <- data.frame(
x = c(rep(1, 3), 0.95, 0.47),
y = c(0.12, 0.28, 0.53, 1, 1),
label = lines$slope)
p + geom_text(aes(label = label), color = "red", data = labels)
有没有比反复试验更好的方法?虽然这不是 太 5 行坏,但我仍然不得不在导出时进一步重做我的调整,因为 R 会话中的原型制作与 R 会话中的原型制作之间的情节纵横比和间距不相同. 生成的图像。程序化标签将是一个巨大的帮助。
一些想法:
- 想知道参数是否可以沿着
c(0, 1)
的范围,来对应沿线的位置
- 是否可以从
ggplot2
对象内部(我不熟悉)中提取 min/max x/y 位置作为确定位置的“作弊”?本质上,如果我知道 (0, intercept)
的像素位置,我就已经知道斜率,所以对于这个例子,我只需要知道 max(x)
或 max(y)
的像素位置,这取决于我们在哪里击中外围
- 我觉得这与
ggrepel
相似,它弄清楚了如何在尝试避免重叠的同时标记点
这是查看新 geomtextpath
的好机会,它看起来真的很酷。它有一堆 geoms 可以沿着不同类型的路径放置文本,因此您可以将标签投影到线条上。
但是,我想不出一种按照您想要的方式设置 hjust 参数的好方法:文本是根据绘图的范围而不是文本所在的路径对齐的。在这种情况下,默认的 hjust = 0.5 意味着标签位于 x = 0.5(因为 x 范围是 0 到 1;不同的范围会有不同的位置)。你可以做一些调整,但我很快就让标签离开了绘图的范围。如果在中间或中间附近没问题,那么这个选项看起来很不错。
library(ggplot2)
library(geomtextpath)
library(dplyr)
# identical setup from the question
p +
geom_textabline(aes(intercept = intercept, slope = slope, label = as.character(slope)),
data = lines, gap = FALSE, offset = unit(0.2, "lines"), text_only = TRUE)
或者,由于您已经有了直线方程,您可以做一些代数运算来找到您的坐标。在 y 最大的地方求解 x,在 x 最大的地方求解 y;对于其中的每一个,使用 pmin
将它们限制在图表的范围内。例如斜率 = 0.5 的线在 x = 2 之前不会达到 y = 1,这在图表之外,因此将其限制为绘图的最大 x。你如何定义最大值可以不同:可以是数据中包含的最大值,你也可以从保存的绘图对象中提取(不确定是否存在这些不相同的情况),或者它可以从中提取面板布局或中断。或者在 How can I extract plot axes' ranges for a ggplot2 object? 上获得更多想法。由你决定。
# y = intercept + slope * x
xmax <- max(df$x)
# or layer_scales(p)$x$get_limits()[2] for data range
# or ggplot_build(p)$layout$panel_params[[1]]$y.range[2] for panel range
ymax <- max(df$y)
lines_calc <- lines %>%
mutate(xcalc = pmin((ymax - intercept) / slope, xmax),
ycalc = pmin(intercept + slope * xmax, ymax))
p +
geom_text(aes(x = xcalc, y = ycalc, label = as.character(slope)),
data = lines_calc, vjust = 0, nudge_y = 0.02)
添加一个答案作为对卡米尔第一个答案的轻微改进,或者“只是不同”,这取决于您的观点。这不是我自己的,只是在 this comment.
中重新创建了 geomtextpath
包创建者的那个
到目前为止,总共有四个解决方案:
- 我的试错手册方法
- camille 使用
geom_textabline
和默认 hjust=0.5
位置
- camille 正在寻找情节的极值,限制为 xmax 或 ymax,以先达到者为准
- 这个,它使用
scale_hjust_manual
将所需的试验和错误减少至少一半(只需要一个值而不是让 x 和 y 都正确)
# same setup as in question
library(geomtextpath)
p + geom_textabline(aes(intercept = intercept,
slope = slope,
label = as.character(slope),
hjust = as.character(slope)),
data = lines,
gap = FALSE,
text_only = TRUE,
offset = unit(0.2, "lines"),
color = "red") +
scale_hjust_manual(values = c(0.65, 0.65, 0.65, 0.65, 0.5))
对于任何想要跟进的人来说,这听起来像是 there is hope 通过 geomtextpath
的“真正的解决方案”,这将最终让 hjust 在幕后“做正确的事”。
关于在 ggplot2
中标记单个 geom_abline()
的现有问题:
- R ggplot2: Labelling a horizontal line on the y axis with a numeric value
- Add label to abline ggplot2 [duplicate]
None 其中的一个用例是我想将多条参考线添加到散点图,目的是允许对斜率范围内的点进行轻松分类。这是该图的可重现示例:
library(ggplot2)
set.seed(123)
df <- data.frame(
x = runif(100, 0, 1),
y = runif(100, 0, 1))
lines <- data.frame(
intercept = rep(0, 5),
slope = c(0.1, 0.25, 0.5, 1, 2))
p <- ggplot(df, aes(x = x, y = y)) +
geom_point() +
geom_abline(aes(intercept = intercept, slope = slope),
linetype = "dashed", data = lines)
p
由于我发现无法通过其他问题以编程方式执行此操作,因此我通过数据框“缩放”了手动方法,使用反复试验找出合理的标签位置。
labels <- data.frame(
x = c(rep(1, 3), 0.95, 0.47),
y = c(0.12, 0.28, 0.53, 1, 1),
label = lines$slope)
p + geom_text(aes(label = label), color = "red", data = labels)
有没有比反复试验更好的方法?虽然这不是 太 5 行坏,但我仍然不得不在导出时进一步重做我的调整,因为 R 会话中的原型制作与 R 会话中的原型制作之间的情节纵横比和间距不相同. 生成的图像。程序化标签将是一个巨大的帮助。
一些想法:
- 想知道参数是否可以沿着
c(0, 1)
的范围,来对应沿线的位置 - 是否可以从
ggplot2
对象内部(我不熟悉)中提取 min/max x/y 位置作为确定位置的“作弊”?本质上,如果我知道(0, intercept)
的像素位置,我就已经知道斜率,所以对于这个例子,我只需要知道max(x)
或max(y)
的像素位置,这取决于我们在哪里击中外围 - 我觉得这与
ggrepel
相似,它弄清楚了如何在尝试避免重叠的同时标记点
这是查看新 geomtextpath
的好机会,它看起来真的很酷。它有一堆 geoms 可以沿着不同类型的路径放置文本,因此您可以将标签投影到线条上。
但是,我想不出一种按照您想要的方式设置 hjust 参数的好方法:文本是根据绘图的范围而不是文本所在的路径对齐的。在这种情况下,默认的 hjust = 0.5 意味着标签位于 x = 0.5(因为 x 范围是 0 到 1;不同的范围会有不同的位置)。你可以做一些调整,但我很快就让标签离开了绘图的范围。如果在中间或中间附近没问题,那么这个选项看起来很不错。
library(ggplot2)
library(geomtextpath)
library(dplyr)
# identical setup from the question
p +
geom_textabline(aes(intercept = intercept, slope = slope, label = as.character(slope)),
data = lines, gap = FALSE, offset = unit(0.2, "lines"), text_only = TRUE)
或者,由于您已经有了直线方程,您可以做一些代数运算来找到您的坐标。在 y 最大的地方求解 x,在 x 最大的地方求解 y;对于其中的每一个,使用 pmin
将它们限制在图表的范围内。例如斜率 = 0.5 的线在 x = 2 之前不会达到 y = 1,这在图表之外,因此将其限制为绘图的最大 x。你如何定义最大值可以不同:可以是数据中包含的最大值,你也可以从保存的绘图对象中提取(不确定是否存在这些不相同的情况),或者它可以从中提取面板布局或中断。或者在 How can I extract plot axes' ranges for a ggplot2 object? 上获得更多想法。由你决定。
# y = intercept + slope * x
xmax <- max(df$x)
# or layer_scales(p)$x$get_limits()[2] for data range
# or ggplot_build(p)$layout$panel_params[[1]]$y.range[2] for panel range
ymax <- max(df$y)
lines_calc <- lines %>%
mutate(xcalc = pmin((ymax - intercept) / slope, xmax),
ycalc = pmin(intercept + slope * xmax, ymax))
p +
geom_text(aes(x = xcalc, y = ycalc, label = as.character(slope)),
data = lines_calc, vjust = 0, nudge_y = 0.02)
添加一个答案作为对卡米尔第一个答案的轻微改进,或者“只是不同”,这取决于您的观点。这不是我自己的,只是在 this comment.
中重新创建了geomtextpath
包创建者的那个
到目前为止,总共有四个解决方案:
- 我的试错手册方法
- camille 使用
geom_textabline
和默认hjust=0.5
位置 - camille 正在寻找情节的极值,限制为 xmax 或 ymax,以先达到者为准
- 这个,它使用
scale_hjust_manual
将所需的试验和错误减少至少一半(只需要一个值而不是让 x 和 y 都正确)
# same setup as in question
library(geomtextpath)
p + geom_textabline(aes(intercept = intercept,
slope = slope,
label = as.character(slope),
hjust = as.character(slope)),
data = lines,
gap = FALSE,
text_only = TRUE,
offset = unit(0.2, "lines"),
color = "red") +
scale_hjust_manual(values = c(0.65, 0.65, 0.65, 0.65, 0.5))
对于任何想要跟进的人来说,这听起来像是 there is hope 通过 geomtextpath
的“真正的解决方案”,这将最终让 hjust 在幕后“做正确的事”。