在多级ggplot2图中用标签替换图例
Replacing legend with labels in multilevel ggplot2 plot
我创建了这张图表。标签占用太多space,很难看出是哪个状态。所以我想用图表内的州代码标签或 x 轴下方的标签替换图例。有没有简单的方法可以做到这一点?
图表:
生成它的代码:
url <- 'https://www.dropbox.com/s/f046jroutvt8ctk/SO_example_data_put_labels_in_graph.csv?raw=1'
d <- read_csv(url)
d %>%
ggplot(aes(x=popNb,y=tx_atendimento)) +
geom_rect(aes(xmin=pop1b,xmax=popNb,
ymin=tx0,ymax=tx_atendimento,
fill=UF)) +
geom_segment(aes(x=pop1b,xend=popNb,
y=tx_atendimento_UF,yend=tx_atendimento_UF)) +
theme(legend.position = "bottom", legend.direction = "horizontal" ) +
ggtitle('Daycare provision rate per state and municipality in Brazil (2014)') +
ggsave('plot_rec_bar_needs_labels.png')
解释:
请注意,这不是正常的条形图。每个城市(数据集中的行)由一个矩形表示,其宽度对应于该年龄段的儿童数量,高度对应于供应率。我创建了 x 值,因此市政当局首先按州 (UF) 的平均供应率排列,其次按该州各城市 (cod_mun6) 的相同比率排列。我还添加了显示每个城市平均值的条形图,尽管这些数据仅在每个城市的第一次观察中可用。
所以这个情节混合了市级和州级的信息(尽管它们 "denormalized" 只有一个 data.frame。
我知道可以通过以下方式删除图例:+ theme(legend.position = "none", )
我尝试添加标签:
+ geom_label(aes(x=mean_popNb_uf,label=UF2), nudge_y =.4,label.size
= 0.05 )
+ geom_text(aes(label=UF2))
但是生成的标签看起来很杂乱,而且定位看起来很奇怪。
我也尝试了 ggrepel
包中的 geom_text_repel(aes(label=UF2))
,但没有显示标签。以前用过directlabels
这个包,不知道在这种情况下怎么用。
最好的方法可能是使用 facet_wrap
设置为 1 行来分隔状态。请注意,某些州似乎缺少数据,因此需要将其过滤掉(否则 facet_wrap
在尝试为空图设置 x 轴限制时失败:
d %>%
filter(!is.na(pop1b)
, !is.na(popNb)) %>%
ggplot(aes(x=popNb,y=tx_atendimento)) +
geom_rect(aes(xmin=pop1b,xmax=popNb,
ymin=tx0,ymax=tx_atendimento
)) +
geom_segment(aes(x=pop1b,xend=popNb,
y=tx_atendimento_UF,yend=tx_atendimento_UF)) +
theme(axis.text.x = element_blank()) +
ggtitle('Daycare provision rate per state and municipality in Brazil (2014)') +
facet_wrap(~UF, scales = "free_x", nrow = 1, switch = "x") +
theme_minimal()
请注意,如果您想更改排序,则需要将 UF
列的因子水平设置为您希望的任何顺序。
如果您想要显示状态的 "size",您可以像这样使用 facet_grid
和 space = "free"
d %>%
filter(!is.na(pop1b)
, !is.na(popNb)) %>%
ggplot(aes(x=popNb,y=tx_atendimento)) +
geom_rect(aes(xmin=pop1b,xmax=popNb,
ymin=tx0,ymax=tx_atendimento
)) +
geom_segment(aes(x=pop1b,xend=popNb,
y=tx_atendimento_UF,yend=tx_atendimento_UF)) +
ggtitle('Daycare provision rate per state and municipality in Brazil (2014)') +
# facet_wrap(~UF, scales = "free_x", nrow = 1, switch = "x") +
facet_grid(~UF, scales = "free_x", switch = "x", space = "free") +
theme_minimal() +
theme(axis.text.x = element_blank()
, panel.margin.x = unit(0,"in"))
但请注意,如果某些状态太窄以至于标签无法容纳,您可能需要填充它们。
我继续添加代码以将所有州填充到任意所需的宽度并对值进行排序:
library(dplyr)
library(ggplot2)
library(magrittr)
url <- 'https://www.dropbox.com/s/f046jroutvt8ctk/SO_example_data_put_labels_in_graph.csv?raw=1'
# d <- read.csv(url)
desiredWidth <- 350000
toPlot <-
d %>%
filter(!is.na(pop1b)
, !is.na(popNb)
, !is.na(UF)) %>%
split(.$UF) %>%
lapply(function(thisState){
# thisState <- d %>% filter(UF == "AC")
# Find current range:
currRange <-
thisState %>%
{max(.$popNb, na.rm = TRUE) -
min(.$pop1b, na.rm = TRUE)}
spacing <- (desiredWidth - currRange)/2
# Add the spacing
temp <- thisState[1:2,]
temp$pop1b <-
c(min(thisState$pop1b, na.rm = TRUE) - spacing
, max(thisState$popNb, na.rm = TRUE) + 1
)
temp$popNb <-
c(min(thisState$pop1b, na.rm = TRUE) - 1
, max(thisState$popNb, na.rm = TRUE) + spacing
)
temp$tx_atendimento <- 0
return(rbind(thisState , temp))
}) %>%
bind_rows %>%
filter(!is.na(UF)) %>%
droplevels
# summary values
sumVal <-
toPlot %>%
group_by(UF) %>%
summarise(sumVal = tx_atendimento_UF[1])
# Sort the states:
toPlot$UF <-
factor(
toPlot$UF
, levels = as.character(sumVal$UF)[order(sumVal$sumVal)]
)
toPlot %>%
ggplot(aes(x=popNb,y=tx_atendimento)) +
geom_rect(aes(xmin=pop1b,xmax=popNb,
ymin=tx0,ymax=tx_atendimento
)) +
geom_segment(aes(x=pop1b,xend=popNb,
y=tx_atendimento_UF,yend=tx_atendimento_UF)) +
ggtitle('Daycare provision rate per state and municipality in Brazil (2014)') +
# facet_wrap(~UF, scales = "free_x", nrow = 1, switch = "x") +
facet_grid(~UF, scales = "free_x", switch = "x", space = "free") +
theme_minimal() +
theme(axis.text.x = element_blank()
, panel.margin.x = unit(0,"in"))
我创建了这张图表。标签占用太多space,很难看出是哪个状态。所以我想用图表内的州代码标签或 x 轴下方的标签替换图例。有没有简单的方法可以做到这一点?
图表:
生成它的代码:
url <- 'https://www.dropbox.com/s/f046jroutvt8ctk/SO_example_data_put_labels_in_graph.csv?raw=1'
d <- read_csv(url)
d %>%
ggplot(aes(x=popNb,y=tx_atendimento)) +
geom_rect(aes(xmin=pop1b,xmax=popNb,
ymin=tx0,ymax=tx_atendimento,
fill=UF)) +
geom_segment(aes(x=pop1b,xend=popNb,
y=tx_atendimento_UF,yend=tx_atendimento_UF)) +
theme(legend.position = "bottom", legend.direction = "horizontal" ) +
ggtitle('Daycare provision rate per state and municipality in Brazil (2014)') +
ggsave('plot_rec_bar_needs_labels.png')
解释:
请注意,这不是正常的条形图。每个城市(数据集中的行)由一个矩形表示,其宽度对应于该年龄段的儿童数量,高度对应于供应率。我创建了 x 值,因此市政当局首先按州 (UF) 的平均供应率排列,其次按该州各城市 (cod_mun6) 的相同比率排列。我还添加了显示每个城市平均值的条形图,尽管这些数据仅在每个城市的第一次观察中可用。
所以这个情节混合了市级和州级的信息(尽管它们 "denormalized" 只有一个 data.frame。
我知道可以通过以下方式删除图例:+ theme(legend.position = "none", )
我尝试添加标签:
+ geom_label(aes(x=mean_popNb_uf,label=UF2), nudge_y =.4,label.size = 0.05 )
+ geom_text(aes(label=UF2))
但是生成的标签看起来很杂乱,而且定位看起来很奇怪。
我也尝试了 ggrepel
包中的 geom_text_repel(aes(label=UF2))
,但没有显示标签。以前用过directlabels
这个包,不知道在这种情况下怎么用。
最好的方法可能是使用 facet_wrap
设置为 1 行来分隔状态。请注意,某些州似乎缺少数据,因此需要将其过滤掉(否则 facet_wrap
在尝试为空图设置 x 轴限制时失败:
d %>%
filter(!is.na(pop1b)
, !is.na(popNb)) %>%
ggplot(aes(x=popNb,y=tx_atendimento)) +
geom_rect(aes(xmin=pop1b,xmax=popNb,
ymin=tx0,ymax=tx_atendimento
)) +
geom_segment(aes(x=pop1b,xend=popNb,
y=tx_atendimento_UF,yend=tx_atendimento_UF)) +
theme(axis.text.x = element_blank()) +
ggtitle('Daycare provision rate per state and municipality in Brazil (2014)') +
facet_wrap(~UF, scales = "free_x", nrow = 1, switch = "x") +
theme_minimal()
请注意,如果您想更改排序,则需要将 UF
列的因子水平设置为您希望的任何顺序。
如果您想要显示状态的 "size",您可以像这样使用 facet_grid
和 space = "free"
d %>%
filter(!is.na(pop1b)
, !is.na(popNb)) %>%
ggplot(aes(x=popNb,y=tx_atendimento)) +
geom_rect(aes(xmin=pop1b,xmax=popNb,
ymin=tx0,ymax=tx_atendimento
)) +
geom_segment(aes(x=pop1b,xend=popNb,
y=tx_atendimento_UF,yend=tx_atendimento_UF)) +
ggtitle('Daycare provision rate per state and municipality in Brazil (2014)') +
# facet_wrap(~UF, scales = "free_x", nrow = 1, switch = "x") +
facet_grid(~UF, scales = "free_x", switch = "x", space = "free") +
theme_minimal() +
theme(axis.text.x = element_blank()
, panel.margin.x = unit(0,"in"))
但请注意,如果某些状态太窄以至于标签无法容纳,您可能需要填充它们。
我继续添加代码以将所有州填充到任意所需的宽度并对值进行排序:
library(dplyr)
library(ggplot2)
library(magrittr)
url <- 'https://www.dropbox.com/s/f046jroutvt8ctk/SO_example_data_put_labels_in_graph.csv?raw=1'
# d <- read.csv(url)
desiredWidth <- 350000
toPlot <-
d %>%
filter(!is.na(pop1b)
, !is.na(popNb)
, !is.na(UF)) %>%
split(.$UF) %>%
lapply(function(thisState){
# thisState <- d %>% filter(UF == "AC")
# Find current range:
currRange <-
thisState %>%
{max(.$popNb, na.rm = TRUE) -
min(.$pop1b, na.rm = TRUE)}
spacing <- (desiredWidth - currRange)/2
# Add the spacing
temp <- thisState[1:2,]
temp$pop1b <-
c(min(thisState$pop1b, na.rm = TRUE) - spacing
, max(thisState$popNb, na.rm = TRUE) + 1
)
temp$popNb <-
c(min(thisState$pop1b, na.rm = TRUE) - 1
, max(thisState$popNb, na.rm = TRUE) + spacing
)
temp$tx_atendimento <- 0
return(rbind(thisState , temp))
}) %>%
bind_rows %>%
filter(!is.na(UF)) %>%
droplevels
# summary values
sumVal <-
toPlot %>%
group_by(UF) %>%
summarise(sumVal = tx_atendimento_UF[1])
# Sort the states:
toPlot$UF <-
factor(
toPlot$UF
, levels = as.character(sumVal$UF)[order(sumVal$sumVal)]
)
toPlot %>%
ggplot(aes(x=popNb,y=tx_atendimento)) +
geom_rect(aes(xmin=pop1b,xmax=popNb,
ymin=tx0,ymax=tx_atendimento
)) +
geom_segment(aes(x=pop1b,xend=popNb,
y=tx_atendimento_UF,yend=tx_atendimento_UF)) +
ggtitle('Daycare provision rate per state and municipality in Brazil (2014)') +
# facet_wrap(~UF, scales = "free_x", nrow = 1, switch = "x") +
facet_grid(~UF, scales = "free_x", switch = "x", space = "free") +
theme_minimal() +
theme(axis.text.x = element_blank()
, panel.margin.x = unit(0,"in"))