合并两个 ggplots

huangapple go评论66阅读模式
英文:

Combining two ggplots

问题

你想要将这两个ggplot图表合并成一个图表,以便表示所有事件,你可以使用grid.arrange函数从gridExtra包来实现这一目标。以下是如何执行此操作的代码:

# 首先,确保你已经安装了gridExtra包
# 如果没有安装,请运行 install.packages("gridExtra") 来安装它

library(gridExtra)

# 将两个图表合并成一个
combined_plot <- grid.arrange(timeline_plot, timeline_plot2, ncol=1)

# 打印合并后的图表
print(combined_plot)

这将帮助你将两个ggplot图表垂直堆叠在一起,以便你可以获得一个包含所有事件的图表。

英文:

I want to create a chart that shows the chronological progression of several events. These are two different types of events, firstly events that have only taken place on one day and secondly events that have taken place on several consecutive days, i.e. over a period of several days. So far I have created a ggplot for each of the two types of events. Since the number of events for the two types is not identical, I have already added an appropriate number of NA observations so that the ggplots can be combined. I have already tried to combine the ggplots with the operator +, but have not been successful so far.

library(ggplot2)
library(scales)
library(dplyr)
library(tibble)

df &lt;- data.frame(c(&quot;2022-02-05&quot;, &quot;2022-02-15&quot;, &quot;2022-03-09&quot;, &quot;2022-05-12&quot;, &quot;2022-08-27&quot;),
                   c(&quot;2022-02-05&quot;, &quot;2022-03-08&quot;, &quot;2022-03-09&quot;, &quot;2022-05-12&quot;, &quot;2022-08-28&quot;),
                   c(&quot;event 1&quot;, &quot;event 2&quot;, &quot;event 3&quot;, &quot;event 4&quot;, &quot;event 5&quot;)
        )
colnames(df) &lt;- c(&quot;start&quot;,&quot;end&quot;, &quot;event&quot;)

df$start &lt;- as.Date(df$start)
df$end &lt;- as.Date(df$end)

# Split the data frame depending on whether the observations are a point in time or a time span
dftp &lt;- filter(df,df$start == df$end)
dftp &lt;- dftp %&gt;%
  rename(&quot;date&quot; = &quot;start&quot;)
dfts &lt;- filter(df,df$start != df$end)

# Add NA row such that both data frames have the same size
n &lt;- nrow(dfts)
dfts[(n+1),] &lt;- NA


# vary height and direction of the lines
dfts$position &lt;- c(1,2,3)
positions &lt;- c(0.5, -0.5, 1.0, -1.0)
directions &lt;- c(1,-1)
line_pos &lt;- data.frame(
  &quot;date&quot;=unique(dftp$date),
  &quot;position&quot;=rep(positions, length.out=length(unique(dftp$date))),
  &quot;direction&quot;=rep(directions, length.out=length(unique(dftp$date)))
)

dftp&lt;- merge(x=dftp, y=line_pos, by=&quot;date&quot;, all = TRUE)
dftp &lt;- dftp[with(dftp, order(date)), ]

text_offset &lt;- 0.05
dftp$month &lt;- as.numeric(format(dftp$date, &quot;%m&quot;))
dftp$month_count &lt;- ave(dftp$date==dftp$date, dftp$date, FUN=cumsum)
dftp$text_position &lt;- (dftp$month_count * text_offset * dftp$direction) + dftp$position

# change range of the plotted days
day_buffer &lt;- 30
day_date_range &lt;- dftp$date
day_format &lt;- format(day_date_range, &#39;%d %b&#39;)
day_df &lt;- data.frame(day_date_range, day_format)




### 1. Plot (with time points)
timeline_plot&lt;-ggplot(dftp,aes(x=date,y=0))
timeline_plot&lt;-timeline_plot+theme_classic()

# Plot horizontal black line for timeline
timeline_plot&lt;-timeline_plot+geom_hline(yintercept=0, 
                                        color = &quot;black&quot;, linewidth=0.3)

# Plot vertical segment lines for events
timeline_plot&lt;-timeline_plot+geom_segment(data=dftp[dftp$month_count == 1,], aes(y=position,yend=0,xend=date), color=&#39;black&#39;, linewidth=0.2)

# Plot scatter points at zero and date
timeline_plot&lt;-timeline_plot+geom_point(aes(y=0), size=2)

# Don&#39;t show axes
timeline_plot&lt;-timeline_plot+theme(axis.line.y=element_blank(),
                                   axis.text.y=element_blank(),
                                   axis.title.x=element_blank(),
                                   axis.title.y=element_blank(),
                                   axis.ticks.y=element_blank(),
                                   axis.text.x =element_blank(),
                                   axis.ticks.x =element_blank(),
                                   axis.line.x =element_blank(),
                                   legend.position = &quot;bottom&quot;
)

# Show day text
timeline_plot&lt;-timeline_plot+geom_text(data=day_df, aes(x=day_date_range,y=-0.1,label=day_format),size=2.5,vjust=0.5, color=&#39;black&#39;, angle=90)

# Show text for each event
timeline_plot&lt;-timeline_plot+geom_text(aes(y=text_position, label=event),size=2.5)


### 2. Plot (with time spnans)
timeline_plot2&lt;-ggplot(data=dfts,aes(x=start,y=position))+geom_segment(aes(xend=end,yend=position),linewidth=1)

timeline_plot2&lt;-timeline_plot2+geom_text(aes(label=event, hjust=1.1),size=2)


# Print plots
print(timeline_plot)
print(timeline_plot2)

My question now is how I can combine these two ggplots in such a way that I get a diagram in which all events are represented.

答案1

得分: 0

你可以通过 geom 函数的 data= 参数很容易地实现你的目标,即可以使用 + geom_xxx(data = dfts, ..) 将第二个图的图层添加到第一个图中。此外,你可以简化你的代码,特别是数据整理部分。

库(ggplot2)
库(dplyr)

df &lt;- df |&gt;
  mutate(across(c(start, end), as.Date)) |&gt;
  mutate(is_tp = start == end) |&gt;
  group_by(is_tp) |&gt;
  mutate(
    position = if_else(is_tp, .5 * ((row_number() + 1) %/% 2), row_number()),
    direction = if_else(is_tp, -sign((row_number() + 1) %% 2 - .5), 1)
  ) |&gt;
  ungroup()

dftp &lt;- filter(df, is_tp)
dfts &lt;- filter(df, !is_tp)

ggplot(dftp, aes(x = start, y = position * direction)) +
  geom_hline(yintercept = 0, linewidth = 0.3) +
  geom_point(aes(y = 0), size = 2) +
  geom_segment(
    aes(yend = 0, xend = start),
    linewidth = 0.2
  ) +
  geom_label(
    aes(label = event),
    size = 2.5, label.size = 0, label.padding = unit(5, &quot;pt&quot;)
  ) +
  geom_text(
    aes(y = 0, label = format(start, &quot;%d %b&quot;)),
    size = 2.5, vjust = 0.5, color = &quot;black&quot;, angle = 90, nudge_y = -.1
  ) +
  geom_segment(
    data = dfts, aes(xend = end, yend = position * direction),
    linewidth = 1
  ) +
  geom_label(
    data = dfts, aes(label = event), hjust = 1, size = 2.5,
    label.size = 0, label.padding = unit(5, &quot;pt&quot;)
  ) +
  theme_void() +
  theme(plot.margin = margin(5.5, 5.5, 5.5, 5.5))

[![点击此处输入图片描述][1]][1]


<details>
<summary>英文:</summary>

You could achieve your result quite easily via the `data=` argument of the `geom`s, i.e. you could do `+ geom_xxx(data = dfts, ..)` to add the layers from your second plot to the first. Moreover, you could simplify your code and especially the data wrangling part considerably.

library(ggplot2)
library(dplyr)

df <- df |>
mutate(across(c(start, end), as.Date)) |>
mutate(is_tp = start == end) |>
group_by(is_tp) |>
mutate(
position = if_else(is_tp, .5 * ((row_number() + 1) %/% 2), row_number()),
direction = if_else(is_tp, -sign((row_number() + 1) %% 2 - .5), 1)
) |>
ungroup()

dftp <- filter(df, is_tp)
dfts <- filter(df, !is_tp)

ggplot(dftp, aes(x = start, y = position * direction)) +
geom_hline(yintercept = 0, linewidth = 0.3) +
geom_point(aes(y = 0), size = 2) +
geom_segment(
aes(yend = 0, xend = start),
linewidth = 0.2
) +
geom_label(
aes(label = event),
size = 2.5, label.size = 0, label.padding = unit(5, "pt")
) +
geom_text(
aes(y = 0, label = format(start, "%d %b")),
size = 2.5, vjust = 0.5, color = "black", angle = 90, nudge_y = -.1
) +
geom_segment(
data = dfts, aes(xend = end, yend = position * direction),
linewidth = 1
) +
geom_label(
data = dfts, aes(label = event), hjust = 1, size = 2.5,
label.size = 0, label.padding = unit(5, "pt")
) +
theme_void() +
theme(plot.margin = margin(5.5, 5.5, 5.5, 5.5))


[![enter image description here][1]][1]


  [1]: https://i.stack.imgur.com/Ls74G.png

</details>



huangapple
  • 本文由 发表于 2023年4月17日 01:20:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/76029269.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定