R:将geom_text()相对于绘图边框而不是绘图上的固定位置

时间:2017-09-22 18:31:24

标签: r ggplot2 geom-text

我在R中使用ggplot2创建了许多图,并想要一种标准化截止线实现的方法。我有大约10年时间内四个城市的许多不同措施的数据。我将它们绘制为线图,每个城市在给定图表中使用不同的颜色。我将为每个不同的测量(大约20个)创建一个图。

在每个图表上,我需要在两个截止线(旁边有一个单词)上表示某些策略的实现,以便阅读图表的人可以轻松识别实现前后的性能差异。以下是我目前正在使用的代码。

gg_plot1<- ggplot(data=ggdata, aes(x=Year, y=measure1, group=Area, color=Area)) +
  geom_vline(xintercept=2011, color="#EE0000") +
  geom_text(aes(x=2011, label="City1\n", y=0.855), color="#EE0000", angle=90, hjust=0, family="serif") +
  geom_vline(xintercept=2007, color="#000099") +
  geom_text(aes(x=2007, label="City2", y=0.855), color="#000099", angle=0, hjust=1, family="serif") +
  geom_line(size=.75) +
  geom_point(size=1.5) +
  scale_y_continuous(breaks=round(seq(min(ggdata$measure1, na.rm=T), max(ggdata$measure1, na.rm=T), by=0.01), 2)) +
  scale_x_continuous(breaks=min(ggdata$Year):max(ggdata$Year)) +
  scale_color_manual(values=c("#EE0000", "#00DDFF", "#009900", "#000099")) +
  theme(axis.text.x = element_text(angle=90, vjust=1),
        panel.background = element_rect(fill="white", color="white"),
        panel.grid.major = element_line(color="grey95"),
        text = element_text(size=11, family="serif"))

此实现的问题在于它依赖于将两个geom_text()放在特定图表上的特定位置。这些不同的测量都有不同的范围,所以为了做到这一点,我需要按照情节绘图并找到放置它们的位置。我喜欢做的就是强制每个绘图的范围减少X%并将geom_text()对齐到范围的底部。线条不应该调整(每个图中的同一年),只需要调整文本的位置。我在这里发现了一些类似的问题,但没有一个与在不同范围的不同图表上放置相同位置的具体问题有关。

有没有办法做我想要的事情?如果我不得不猜测,那就是使用相对定位而不是绝对定位,但我还没有能够在ggplot中找到它。为了记录,我知道这两个geom_text()的方向不同。我这样做是为了比较我们所喜欢的但是为你们所有人留下的。我们最终将使用文本旋转90度的那个。此外,其中一些将被拼接在一起,因此可能会提供额外的难度。哈文还没到达那一点。

补充工具栏:另一种可视化方法是在截止年份将线条从实线更改为点线。这可能吗?我不确定客户是否会想要这样,但我很乐意将它作为一种选择,如果有人能指出我在哪里学习如何做到这一点。

编辑添加:

示例数据,显示使用不同的y范围运行时会发生什么

ggdata <- data.frame(Area=rep(c("City1", "City2", "City3", "City4"), times=7),
                     Year=c(rep(2006,4), rep(2007,4), rep(2008,4), rep(2009,4), rep(2010,4), rep(2011,4), rep(2012,4)),
                     measure1=rnorm(28,10,2),
                     measure2=rnorm(28,50,10))

示例图中geom_text() s位于正确的位置,但这是使用上面的代码在图中使用固定位置完成的。当我使用具有不同y范围的不同度量复制代码时,它最终会拉伸绘图窗口。 Sample plot

1 个答案:

答案 0 :(得分:3)

您可以使用数据的y范围定位到文本标签。我在下面的示例中明确设置了y限制,但这并非绝对必要,除非您想要从默认值中更改它们。您还可以使用数据的x范围调整文本标签的x位置。无论数据的y范围如何,下面的代码都会将标签定位在图表的底部。

我也从geom_text切换到annotategeom_text多次覆盖文本标签,对数据中的每一行进行一次。 annotate将标签绘制一次。

ypos = min(ggdata$measure1) + 0.005*diff(range(ggdata$measure1))
xv = 0.02
xh = 0.01
xadj = diff(range(ggdata$Year))

ggplot(data=ggdata, aes(x=Year, y=measure1, group=Area, color=Area)) +
  geom_vline(xintercept=2011, color="#EE0000") +
  geom_vline(xintercept=2007, color="#000099") +
  geom_line(size=.75) +
  geom_point(size=1.5) +
  annotate(geom="text", x=2011 - xv*xadj, label="City1", y=ypos, color="#EE0000", angle=90, hjust=0, family="serif") +
  annotate(geom="text", x=2007 - xh*xadj, label="City2", y=ypos, color="#000099", angle=0, hjust=1, family="serif") +
  scale_y_continuous(limits=range(ggdata$measure1),
                     breaks=round(seq(min(ggdata$measure1, na.rm=T), max(ggdata$measure1, na.rm=T), by=1), 0)) +
  scale_x_continuous(breaks=min(ggdata$Year):max(ggdata$Year)) +
  scale_color_manual(values=c("#EE0000", "#00DDFF", "#009900", "#000099")) +
  theme(axis.text.x = element_text(angle=90, vjust=1),
        panel.background = element_rect(fill="white", color="white"),
        panel.grid.major = element_line(color="grey95"),
        text = element_text(size=11, family="serif"))

enter image description here

更新:要回复您的评论,您可以在此处为数据框中的每个“度量”列创建单独的图表。

首先,我们使用三个度量列创建可重现的数据:

library(ggplot2)
library(gridExtra)
library(scales)

set.seed(4)
ggdata <- data.frame(Year=rep(2006:2012,each=4),
                     Area=rep(paste0("City",1:4), 7),
                     measure1=rnorm(28,10,2),
                     measure2=rnorm(28,50,10),
                     measure3=rnorm(28,-50,5))

现在,我们从上面获取代码并将其打包到函数中。该函数采用名为measure_var的参数。这是作为character_string提供的数据列,它将为绘图提供y值。请注意,我们现在在aes_string内使用aes而不是ggplot

plot_func = function(measure_var) {

  ypos = min(ggdata[ , measure_var]) + 0.005*diff(range(ggdata[ , measure_var]))
  xv = 0.02
  xh = 0.01
  xadj = diff(range(ggdata$Year))

  ggplot(data=ggdata, aes_string(x="Year", y=measure_var, group="Area", color="Area")) +
    geom_vline(xintercept=2011, color="#EE0000") +
    geom_vline(xintercept=2007, color="#000099") +
    geom_line(size=.75) +
    geom_point(size=1.5) +
    annotate(geom="text", x=2011 - xv*xadj, label="City1", y=ypos, 
             color="#EE0000", angle=90, hjust=0, family="serif") +
    annotate(geom="text", x=2007 - xh*xadj, label="City2", y=ypos, 
             color="#000099", angle=0, hjust=1, family="serif") +
    scale_y_continuous(limits=range(ggdata[ , measure_var]),
                       breaks=pretty_breaks(5)) +
    scale_x_continuous(breaks=min(ggdata$Year):max(ggdata$Year)) +
    scale_color_manual(values=c("#EE0000", "#00DDFF", "#009900", "#000099")) +
    theme(axis.text.x = element_text(angle=90, vjust=1),
          panel.background = element_rect(fill="white", color="white"),
          panel.grid.major = element_line(color="grey95"),
          text = element_text(size=11, family="serif")) +
    ggtitle(paste("Plot of", measure_var))
}

我们现在可以像这样运行一次函数:plot_func("measure1")。但是,让我们使用lapply一次性在所有度量列上运行它。我们为lapply提供了一个带有度量列名称(names(ggdata)[grepl("measure", names(ggdata))])的向量,它依次在每个列上运行plot_func,将结果图存储在列表{{1 }}

plot_list

现在,如果我们愿意,我们可以使用plot_list = lapply(names(ggdata)[grepl("measure", names(ggdata))], plot_func) 将它们全部放在一起。在这种情况下,我们只需要一个图例,而不是每个图的单独图例,因此我们将图例作为单独的图形对象提取出来,并将其放在三个图旁边。

grid.arrange

enter image description here