ggplot2 带引导线的堆叠条形图标签
ggplot2 stacked bar chart labels with leader lines
我正在尝试创建一个带标签的堆叠条形图,其中只有 1 个条形图。我的堆栈并不总是大到足以容纳文本,所以我希望引导线指向堆栈右侧的标签,用于无法放入堆栈的标签。或者,如果所有标签都位于带前导线的堆栈右侧也可以。
我的 data.frame 看起来像这样:
Regional.District Municipality Population.2010 mp
Metro Bowen Island 3678 1839.0
Metro Coquitlam 126594 66975.0
Metro Delta 100000 180272.0
Metro Langley City 25858 243201.0
Metro Maple Ridge 76418 294339.0
Metro New West 66892 365994.0
Metro North Vancouver (City) 50725 424802.5
Metro Port Coquitlam 57431 478880.5
Metro Port Moody 33933 524562.5
Metro Surrey 462345 772701.5
Metro West Vancouver 44058 1025903.0
Metro White Rock 19278 1057571.0
Metro Anmore 2203 1068311.5
Metro Belcarra 690 1069758.0
Metro Burnaby 227389 1183797.5
Metro Langley (Town) 104697 1349840.5
Metro Lions Bay 1395 1402886.5
Metro Metro Vancouver-uninc 24837 1416002.5
Metro North Vancouver (District) 88370 1472606.0
Metro Pitt Meadows 18136 1525859.0
Metro Richmond 196858 1633356.0
Metro Vancouver (City) 642843 2053206.5
这是我目前的工作:
这就是我想要开始工作的:
这是我的代码:
library(ggplot2)
ggplot(muns, aes(x = Regional.District, y = Population.2010, fill = Municipality)) +
geom_bar(stat = 'identity', colour = 'gray32', width = 0.6, show_guide = FALSE) +
geom_text(aes(y = muns$mp, label = muns$Municipality), colour = 'gray32')
这可以自动化吗?我可以不使用 ggplot2 来完成此操作。
谢谢!
这是一种可能。我认为这项工作确实需要一些手动工作,尽管您可以自动化一些流程。我最初调查了哪些标签必须留在栏外。然后,我看到一些标签相互重叠。我的解决方案是移动栏左侧的一些标签。 Anmore
是一个棘手的问题。我手动将它的 y 位置移高一点,这样它就不会与 White Rock
.
重叠
gg1
是基础图形。您在栏内有标签。 gg2
的创建是为了获取应添加到栏右侧的标签。在 dan
中,我查看了 ggplots 使用的数据并修改了 x 值(即 x = 1.35)。我在这里也删除了三个地方。 emo
和dan2
中的三个地方也做了类似的工作。在 gg3
中,我添加了标签。最后的工作是添加段。我创建了三个新的数据框来绘制线段。
library(dplyr) # I use the dev version (dplyr 0.4)
library(ggplot2)
# as_data_frame() is available in dplyr 0.4
mydf <- as_data_frame(list(Regional.District = rep("Metro", times = 22),
Municipality = c("Bowen Island", "Coquitlam", "Delta",
"Langley City", "Maple Ridge", "New West",
"North Vancouver (City)", "Port Coquitlam", "Port Moody",
"Surrey", "West Vancouver", "White Rock",
"Anmore", "Belcarra", "Burnaby", "Langley (Town)",
"Lions Bay", "Metro Vancouver-uninc",
"North Vancouver (District)", "Pitt Meadows",
"Richmond", "Vancouver (City)"),
Population = c(3678, 126594, 100000, 25858, 76418, 66892, 50725,
57431, 33933, 462345, 44058, 19278, 2203, 690,
227389, 104697, 1395, 24837, 88370, 18136, 196858,
642843),
mp = c(1839.0, 66975.0, 180272.0, 243201.0, 294339.0, 365994.0,
424802.5, 478880.5, 524562.5, 772701.5, 1025903.0, 1057571.0,
1068311.5, 1069758.0, 1183797.5, 1349840.5, 1402886.5, 1416002.5,
1472606.0, 1525859.0, 1633356.0, 2053206.5)))
# Get label for places which has more than or less than 60,000 people
ana <- mutate(mydf, foo = ifelse(Population > 60000, Municipality, NA))
bob <- mutate(mydf, foo = ifelse(Population > 60000, NA, Municipality))
# Plot with places which have more than 60,000 people
gg1 <- ggplot(mydf, aes(x = Regional.District, y = Population, fill = Municipality)) +
geom_bar(stat = "identity", colour = "gray32", width = 0.4, show_guide = FALSE) +
geom_text(aes(y = ana$mp, label = ana$foo), colour = "gray32", size = 3)
# Plot with places which have less than 60,000 people
gg2 <- ggplot(mydf, aes(x = Regional.District, y = Population, fill = Municipality)) +
geom_bar(stat = "identity", colour = "gray32", width = 0.4, show_guide = FALSE) +
geom_text(aes(y = bob$mp, label = bob$foo), colour = "gray32")
# Label for right
dan <- na.omit(ggplot_build(gg2)$data[[2]]) %>%
filter(!label %in% c("Belcarra", "Metro Vancouver-uninc", "Anmore")) %>%
mutate(x = 1.35)
# Label for left
emo <- filter(ggplot_build(gg2)$data[[2]],
label %in% c("Belcarra", "Metro Vancouver-uninc")) %>%
mutate(x = 0.65)
# Special label for right
dan2 <- filter(ggplot_build(gg2)$data[[2]], label == "Anmore") %>%
mutate(x = 1.35, y = 1098312)
# Add labels
gg3 <- gg1 +
annotate("text", x = dan$x, y = dan$y, label = dan$label, colour = "gray32", size = 3) +
annotate("text", x = emo$x, y = emo$y, label = emo$label, colour = "gray32", size = 3) +
annotate("text", x = dan2$x, y = dan2$y, label = dan2$label, colour = "gray32", size = 3)
# Create data frames for segments
# right seg
r.seg <- data.frame(x = rep(1.2, times = 9),
xend = rep(1.25, times = 9),
y = dan$y,
yend = dan$y)
# left seg
l.seg <- data.frame(x = rep(0.76, times = 2),
xend = rep(0.8, times = 2),
y = emo$y,
yend = emo$y)
# Anmore seg
a.seg <- data.frame(x = 1.2,
xend = 1.25,
y = 1068312,
yend = dan2$y)
# Draw the segments
gg3 +
annotate("segment", x = r.seg$x, xend = r.seg$xend, y = r.seg$y, yend = r.seg$yend) +
annotate("segment", x = l.seg$x, xend = l.seg$xend, y = l.seg$y, yend = l.seg$yend) +
annotate("segment", x = a.seg$x, xend = a.seg$xend, y = a.seg$y, yend = a.seg$yend)
我正在尝试创建一个带标签的堆叠条形图,其中只有 1 个条形图。我的堆栈并不总是大到足以容纳文本,所以我希望引导线指向堆栈右侧的标签,用于无法放入堆栈的标签。或者,如果所有标签都位于带前导线的堆栈右侧也可以。
我的 data.frame 看起来像这样:
Regional.District Municipality Population.2010 mp
Metro Bowen Island 3678 1839.0
Metro Coquitlam 126594 66975.0
Metro Delta 100000 180272.0
Metro Langley City 25858 243201.0
Metro Maple Ridge 76418 294339.0
Metro New West 66892 365994.0
Metro North Vancouver (City) 50725 424802.5
Metro Port Coquitlam 57431 478880.5
Metro Port Moody 33933 524562.5
Metro Surrey 462345 772701.5
Metro West Vancouver 44058 1025903.0
Metro White Rock 19278 1057571.0
Metro Anmore 2203 1068311.5
Metro Belcarra 690 1069758.0
Metro Burnaby 227389 1183797.5
Metro Langley (Town) 104697 1349840.5
Metro Lions Bay 1395 1402886.5
Metro Metro Vancouver-uninc 24837 1416002.5
Metro North Vancouver (District) 88370 1472606.0
Metro Pitt Meadows 18136 1525859.0
Metro Richmond 196858 1633356.0
Metro Vancouver (City) 642843 2053206.5
这是我目前的工作:
这就是我想要开始工作的:
这是我的代码:
library(ggplot2)
ggplot(muns, aes(x = Regional.District, y = Population.2010, fill = Municipality)) +
geom_bar(stat = 'identity', colour = 'gray32', width = 0.6, show_guide = FALSE) +
geom_text(aes(y = muns$mp, label = muns$Municipality), colour = 'gray32')
这可以自动化吗?我可以不使用 ggplot2 来完成此操作。 谢谢!
这是一种可能。我认为这项工作确实需要一些手动工作,尽管您可以自动化一些流程。我最初调查了哪些标签必须留在栏外。然后,我看到一些标签相互重叠。我的解决方案是移动栏左侧的一些标签。 Anmore
是一个棘手的问题。我手动将它的 y 位置移高一点,这样它就不会与 White Rock
.
gg1
是基础图形。您在栏内有标签。 gg2
的创建是为了获取应添加到栏右侧的标签。在 dan
中,我查看了 ggplots 使用的数据并修改了 x 值(即 x = 1.35)。我在这里也删除了三个地方。 emo
和dan2
中的三个地方也做了类似的工作。在 gg3
中,我添加了标签。最后的工作是添加段。我创建了三个新的数据框来绘制线段。
library(dplyr) # I use the dev version (dplyr 0.4)
library(ggplot2)
# as_data_frame() is available in dplyr 0.4
mydf <- as_data_frame(list(Regional.District = rep("Metro", times = 22),
Municipality = c("Bowen Island", "Coquitlam", "Delta",
"Langley City", "Maple Ridge", "New West",
"North Vancouver (City)", "Port Coquitlam", "Port Moody",
"Surrey", "West Vancouver", "White Rock",
"Anmore", "Belcarra", "Burnaby", "Langley (Town)",
"Lions Bay", "Metro Vancouver-uninc",
"North Vancouver (District)", "Pitt Meadows",
"Richmond", "Vancouver (City)"),
Population = c(3678, 126594, 100000, 25858, 76418, 66892, 50725,
57431, 33933, 462345, 44058, 19278, 2203, 690,
227389, 104697, 1395, 24837, 88370, 18136, 196858,
642843),
mp = c(1839.0, 66975.0, 180272.0, 243201.0, 294339.0, 365994.0,
424802.5, 478880.5, 524562.5, 772701.5, 1025903.0, 1057571.0,
1068311.5, 1069758.0, 1183797.5, 1349840.5, 1402886.5, 1416002.5,
1472606.0, 1525859.0, 1633356.0, 2053206.5)))
# Get label for places which has more than or less than 60,000 people
ana <- mutate(mydf, foo = ifelse(Population > 60000, Municipality, NA))
bob <- mutate(mydf, foo = ifelse(Population > 60000, NA, Municipality))
# Plot with places which have more than 60,000 people
gg1 <- ggplot(mydf, aes(x = Regional.District, y = Population, fill = Municipality)) +
geom_bar(stat = "identity", colour = "gray32", width = 0.4, show_guide = FALSE) +
geom_text(aes(y = ana$mp, label = ana$foo), colour = "gray32", size = 3)
# Plot with places which have less than 60,000 people
gg2 <- ggplot(mydf, aes(x = Regional.District, y = Population, fill = Municipality)) +
geom_bar(stat = "identity", colour = "gray32", width = 0.4, show_guide = FALSE) +
geom_text(aes(y = bob$mp, label = bob$foo), colour = "gray32")
# Label for right
dan <- na.omit(ggplot_build(gg2)$data[[2]]) %>%
filter(!label %in% c("Belcarra", "Metro Vancouver-uninc", "Anmore")) %>%
mutate(x = 1.35)
# Label for left
emo <- filter(ggplot_build(gg2)$data[[2]],
label %in% c("Belcarra", "Metro Vancouver-uninc")) %>%
mutate(x = 0.65)
# Special label for right
dan2 <- filter(ggplot_build(gg2)$data[[2]], label == "Anmore") %>%
mutate(x = 1.35, y = 1098312)
# Add labels
gg3 <- gg1 +
annotate("text", x = dan$x, y = dan$y, label = dan$label, colour = "gray32", size = 3) +
annotate("text", x = emo$x, y = emo$y, label = emo$label, colour = "gray32", size = 3) +
annotate("text", x = dan2$x, y = dan2$y, label = dan2$label, colour = "gray32", size = 3)
# Create data frames for segments
# right seg
r.seg <- data.frame(x = rep(1.2, times = 9),
xend = rep(1.25, times = 9),
y = dan$y,
yend = dan$y)
# left seg
l.seg <- data.frame(x = rep(0.76, times = 2),
xend = rep(0.8, times = 2),
y = emo$y,
yend = emo$y)
# Anmore seg
a.seg <- data.frame(x = 1.2,
xend = 1.25,
y = 1068312,
yend = dan2$y)
# Draw the segments
gg3 +
annotate("segment", x = r.seg$x, xend = r.seg$xend, y = r.seg$y, yend = r.seg$yend) +
annotate("segment", x = l.seg$x, xend = l.seg$xend, y = l.seg$y, yend = l.seg$yend) +
annotate("segment", x = a.seg$x, xend = a.seg$xend, y = a.seg$y, yend = a.seg$yend)