在线图上的程序标签以避免行ggplot2
Program labels on line graph to avoid line ggplot2
我很好奇是否有办法在 ggplot2 的折线图上叠加标签以避免穿过直线。我使用过 vjust,它在大多数情况下都有效,但是当两个日期之间有很大的增加或减少时,该行会穿过标签,使其难以阅读。我将把我目前正在使用的情节和代码放在下面。在这种情况下,我想移动 920; 1,467;和 1,480 下线。我正在通过 Reporters 包将情节导出到 powerpoint,所以我可以手动移动它,我只是想知道是否有办法避免这种情况。
剧情:
代码:
library("ggplot2")
library("scales")
line_data <- c(276, 475, 753, 840, 931, 962, 801, 920, 1467, 1840, 1737, 1638, 1789, 1733, 1480, 1464, 1538)
year_data <- c(2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016,
2017)
line_data_total <- as.data.frame(cbind(line_data, year_data))
limit_func <- function(x) {
if (nchar(max(x)) == 2){
round(max(x +5), digits = -1)
} else if (nchar(max(x)) == 3){
round(max(x +50), digits = -2)
} else if (nchar(max(x)) == 4){
round(max(x +500), digits = -3)
}
}
ggplot(data = line_data_total, aes(x = year_data, y = line_data, group = 1)) +
geom_line(color = "red", size = 1.2)+
geom_point(color = "red", fill = "red", shape = 23, size = 1.75) +
geom_text(aes(label = paste0(format(round(as.numeric(line_data), 1), nsmall = 0, big.mark = ","))),
size = 3, fontface = "bold", vjust = -2) +
labs(x = '', y = '') +
expand_limits(y = c(0, limit_func(line_data_total$line_data))) +
scale_x_continuous(breaks = seq(min(line_data_total$year_data), max(line_data_total$year_data), 1)) +
scale_y_continuous(labels = comma) +
theme(panel.grid.major.x = element_blank() ,
panel.grid.major.y = element_line( size=.1, color="light gray"),
panel.background = element_rect(fill = "transparent"),
plot.background = element_rect(fill = "transparent"),
axis.text.x = element_text(face = "bold", size = 10),
axis.text.y = element_text(face = "bold", size = 10),
axis.ticks.y = element_blank())
如何使用 ggplot2
扩展 ggrepel
:
require(ggrepel)
将您的 geom_text()
行替换为:
geom_text_repel(aes(label = paste0(format(round(as.numeric(line_data), 1), nsmall = 0, big.mark = ","))),
size = 3, fontface = "bold", nudge_y=150)
nudge_y
是将标签推下线的原因,您可以结合使用 nudge_x
和 nudge_y
进行更多控制。并查看包小插图:https://github.com/slowkow/ggrepel/blob/master/vignettes/ggrepel.md
在不摆弄 geom_text_repel
的设置的情况下,我想尝试一种针对像这样的时间序列进行推广的解决方案。我写了一个函数,它查看两个 x 相邻点并计算它们之间的斜率以及中间点是较低、较高还是在 x-邻居之间=]y方向.
- 如果一个点在y-它的x-邻居之间,标签将沿对角线偏移,远离斜率连接它们的线。
- 如果该点在其 x 邻居的 y 下方,则标签居中,但向下移动。
- 如果该点在其 x 邻居上方 y,则标签居中,但向上移动。
library(dplyr)
adjust_away_from_line <- function(df, x, y, vextend = 0.5) {
if(!is.data.frame(df)) {return(df)}
x <- enquo(x)
y <- enquo(y)
if(!(quo_name(x) %in% names(df))) {
warning(paste0("Column '", quo_name(x), "' not found in data."))
return(df)
}
if(!(quo_name(y) %in% names(df))) {
warning(paste0("Column '", quo_name(y), "' not found in data."))
return(df)
}
df %>% arrange(!!x) %>%
mutate(nb.slope = case_when(
is.na(lead(!!y)) ~ ( (!!y) - lag(!!y))/( (!!x) - lag(!!x)),
is.na(lag(!!y)) ~ (lead(!!y) - (!!y))/(lead(!!x) - (!!x)),
TRUE ~ (lead(!!y) - lag(!!y))/(lead(!!x) - lag(!!x))
),
nb.pos = case_when(
is.na(lead(!!y)) ~ -sign(nb.slope),
is.na(lag(!!y)) ~ -sign(nb.slope),
(lead(!!y) >= (!!y)) & (lag(!!y) >= (!!y)) ~ 1.1,
!(lead(!!y) >= (!!y)) & !(lag(!!y) >= (!!y)) ~ -1.1,
TRUE ~ -1
),
hjust = case_when(
nb.pos > 1 ~ 0.5,
nb.pos < -1 ~ 0.5,
nb.slope > 0 ~ 1,
nb.slope < 0 ~ 0,
TRUE ~ 0.5
),
vjust = scales::rescale(round(nb.pos), to = c(0-vextend, 1+vextend))) %>%
select(-nb.slope, -nb.pos)
}
因为它需要一个数据帧作为它的第一个参数,你可以在管道中使用这个函数,给它你的 x 变量和 y 的裸名 顺序变量:
data.frame(line_data = c(276, 475, 753, 840, 931, 962, 801, 920, 1467,
1840, 1737, 1638, 1789, 1733, 1480, 1464, 1538),
year_data = c(2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
2011, 2012, 2013, 2014, 2015, 2016, 2017)
) %>%
adjust_away_from_line(year_data, line_data) %>%
ggplot(aes(year_data, line_data)) +
geom_line() +
geom_point() +
geom_text(aes(label = line_data, hjust = hjust, vjust = vjust))
如果您想将标签进一步向上和向下移动,远离线条,您可以使用 adjust_away_from_line(..., vextend = ##)
参数来实现。默认值为 0.5,但在不同的应用程序中您可能需要 0.75 或 1。
我很好奇是否有办法在 ggplot2 的折线图上叠加标签以避免穿过直线。我使用过 vjust,它在大多数情况下都有效,但是当两个日期之间有很大的增加或减少时,该行会穿过标签,使其难以阅读。我将把我目前正在使用的情节和代码放在下面。在这种情况下,我想移动 920; 1,467;和 1,480 下线。我正在通过 Reporters 包将情节导出到 powerpoint,所以我可以手动移动它,我只是想知道是否有办法避免这种情况。
剧情:
代码:
library("ggplot2")
library("scales")
line_data <- c(276, 475, 753, 840, 931, 962, 801, 920, 1467, 1840, 1737, 1638, 1789, 1733, 1480, 1464, 1538)
year_data <- c(2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016,
2017)
line_data_total <- as.data.frame(cbind(line_data, year_data))
limit_func <- function(x) {
if (nchar(max(x)) == 2){
round(max(x +5), digits = -1)
} else if (nchar(max(x)) == 3){
round(max(x +50), digits = -2)
} else if (nchar(max(x)) == 4){
round(max(x +500), digits = -3)
}
}
ggplot(data = line_data_total, aes(x = year_data, y = line_data, group = 1)) +
geom_line(color = "red", size = 1.2)+
geom_point(color = "red", fill = "red", shape = 23, size = 1.75) +
geom_text(aes(label = paste0(format(round(as.numeric(line_data), 1), nsmall = 0, big.mark = ","))),
size = 3, fontface = "bold", vjust = -2) +
labs(x = '', y = '') +
expand_limits(y = c(0, limit_func(line_data_total$line_data))) +
scale_x_continuous(breaks = seq(min(line_data_total$year_data), max(line_data_total$year_data), 1)) +
scale_y_continuous(labels = comma) +
theme(panel.grid.major.x = element_blank() ,
panel.grid.major.y = element_line( size=.1, color="light gray"),
panel.background = element_rect(fill = "transparent"),
plot.background = element_rect(fill = "transparent"),
axis.text.x = element_text(face = "bold", size = 10),
axis.text.y = element_text(face = "bold", size = 10),
axis.ticks.y = element_blank())
如何使用 ggplot2
扩展 ggrepel
:
require(ggrepel)
将您的 geom_text()
行替换为:
geom_text_repel(aes(label = paste0(format(round(as.numeric(line_data), 1), nsmall = 0, big.mark = ","))),
size = 3, fontface = "bold", nudge_y=150)
nudge_y
是将标签推下线的原因,您可以结合使用 nudge_x
和 nudge_y
进行更多控制。并查看包小插图:https://github.com/slowkow/ggrepel/blob/master/vignettes/ggrepel.md
在不摆弄 geom_text_repel
的设置的情况下,我想尝试一种针对像这样的时间序列进行推广的解决方案。我写了一个函数,它查看两个 x 相邻点并计算它们之间的斜率以及中间点是较低、较高还是在 x-邻居之间=]y方向.
- 如果一个点在y-它的x-邻居之间,标签将沿对角线偏移,远离斜率连接它们的线。
- 如果该点在其 x 邻居的 y 下方,则标签居中,但向下移动。
- 如果该点在其 x 邻居上方 y,则标签居中,但向上移动。
library(dplyr)
adjust_away_from_line <- function(df, x, y, vextend = 0.5) {
if(!is.data.frame(df)) {return(df)}
x <- enquo(x)
y <- enquo(y)
if(!(quo_name(x) %in% names(df))) {
warning(paste0("Column '", quo_name(x), "' not found in data."))
return(df)
}
if(!(quo_name(y) %in% names(df))) {
warning(paste0("Column '", quo_name(y), "' not found in data."))
return(df)
}
df %>% arrange(!!x) %>%
mutate(nb.slope = case_when(
is.na(lead(!!y)) ~ ( (!!y) - lag(!!y))/( (!!x) - lag(!!x)),
is.na(lag(!!y)) ~ (lead(!!y) - (!!y))/(lead(!!x) - (!!x)),
TRUE ~ (lead(!!y) - lag(!!y))/(lead(!!x) - lag(!!x))
),
nb.pos = case_when(
is.na(lead(!!y)) ~ -sign(nb.slope),
is.na(lag(!!y)) ~ -sign(nb.slope),
(lead(!!y) >= (!!y)) & (lag(!!y) >= (!!y)) ~ 1.1,
!(lead(!!y) >= (!!y)) & !(lag(!!y) >= (!!y)) ~ -1.1,
TRUE ~ -1
),
hjust = case_when(
nb.pos > 1 ~ 0.5,
nb.pos < -1 ~ 0.5,
nb.slope > 0 ~ 1,
nb.slope < 0 ~ 0,
TRUE ~ 0.5
),
vjust = scales::rescale(round(nb.pos), to = c(0-vextend, 1+vextend))) %>%
select(-nb.slope, -nb.pos)
}
因为它需要一个数据帧作为它的第一个参数,你可以在管道中使用这个函数,给它你的 x 变量和 y 的裸名 顺序变量:
data.frame(line_data = c(276, 475, 753, 840, 931, 962, 801, 920, 1467,
1840, 1737, 1638, 1789, 1733, 1480, 1464, 1538),
year_data = c(2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
2011, 2012, 2013, 2014, 2015, 2016, 2017)
) %>%
adjust_away_from_line(year_data, line_data) %>%
ggplot(aes(year_data, line_data)) +
geom_line() +
geom_point() +
geom_text(aes(label = line_data, hjust = hjust, vjust = vjust))
如果您想将标签进一步向上和向下移动,远离线条,您可以使用 adjust_away_from_line(..., vextend = ##)
参数来实现。默认值为 0.5,但在不同的应用程序中您可能需要 0.75 或 1。