ggplot图例与geom_tile和geom_line

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

ggplot legend with geom_tile and geom_line

问题

我试图制作一个带有两个垂直轴的ggplot图表,用户可以决定在每一侧使用哪种geom。选项有lines、points和bars。当在左侧添加bars和右侧添加lines时,我在图例中无法获得正确的形状

使用线条和点正常工作

# 准备图例指南
legguides <- guides(color = guide_legend(title.position = "top",
                                         override.aes = list(shape = c(NA, NA, 20, 20),
                                                             linetype = c(1, 1, 0, 0))))

# 准备geoms
gglines <- geom_line(aes(x = Date, y = Val1, color = ID, group = ID), na.rm = TRUE)
ggpoints <- geom_point(aes(x = Date, y = Val2_scl, color = ID, group = ID), na.rm = TRUE)

# 生成ggplot
ggplot(dfAll) + gglines + ggpoints +
  scale_y_continuous(sec.axis = dup_axis(breaks = rev(brks2), labels = rev(labs2), name = "Val2")) +
  coord_cartesian(ylim = ylim1) + ylab("Val1") +
  legguides

使用bars和点也正常工作

# 准备图例指南
legguides <- guides(color = guide_legend(title.position = "top",
                                         override.aes = list(shape = c(15, 15, 20, 20),
                                                             linetype = c(0, 0, 0, 0))))

# 准备geoms
ggtiles <- geom_tile(aes(x = Date, y = Val1/2, height = Val1, fill = ID, group = ID),
                     na.rm = TRUE, stat = "identity", position = position_dodge(preserve = "single"),
                     show.legend = FALSE)

# 生成ggplot
ggplot(dfAll) + ggtiles + ggpoints +
  scale_y_continuous(sec.axis = dup_axis(breaks = rev(brks2), labels = rev(labs2), name = "Val2")) +
  coord_cartesian(ylim = ylim1) + ylab("Val1") +
  legguides

使用bars和lines时,在图例中未显示任何形状

# 准备图例指南
legguides <- guides(color = guide_legend(title.position = "top",
                                         override.aes = list(shape = c(15, 15, NA, NA),
                                                             linetype = c(0, 0, 1, 1))))

# 准备geoms
gglines <- geom_line(aes(x = Date, y = Val2_scl, color = ID, group = ID), na.rm = TRUE)

# 生成ggplot
ggplot(dfAll) + ggtiles + gglines +
  scale_y_continuous(sec.axis = dup_axis(breaks = rev(brks2), labels = rev(labs2), name = "Val2")) +
  coord_cartesian(ylim = ylim1) + ylab("Val1") +
  legguides

我尝试了在guide_legend()中使用不同的shape值,但图表似乎忽略了该属性。我认为这与前两个示例使用了geom_point()调用,而最后一个示例没有使用有关。shapegeom_point()对象的属性之一,但不是geom_line()的属性。

如果有人想到使用geom_bar()而不是geom_tile()的解决方案,请注意,我在这里使用后者是基于这个SO答案,它帮助我在其中一个轴反转时绘制倒置的bars。

英文:

I'm trying to produce a ggplot chart with two vertical axes where the user can decide which geom to use at each side. The options are lines, points and bars. I'm having troubles to have the correct shape in the legend when adding bars at the left and lines at the right.


MRE

library(ggplot2)
library(dplyr)
library(plotly)

# prepare raw data
df1 &lt;- data.frame(ID = c(&quot;A&quot;, &quot;A&quot;, &quot;A&quot;, &quot;A&quot;, &quot;B&quot;, &quot;B&quot;, &quot;B&quot;, &quot;B&quot;), 
                  Date = structure(c(19078, 19085, 19092, 19099, 19078, 19085, 19092, 19099), class = &quot;Date&quot;),
                  Val = c(236, 221, 187, 136, 77, 100, 128, 180))

df2 &lt;- data.frame(ID = c(&quot;J&quot;, &quot;J&quot;, &quot;J&quot;, &quot;J&quot;, &quot;K&quot;, &quot;K&quot;, &quot;K&quot;, &quot;K&quot;), 
                  Date = structure(c(19078, 19085, 19092, 19099, 19078, 19085, 19092, 19099), class = &quot;Date&quot;),
                  Val = c(478, 500, 549, 479, 73, 5, 15, 74))

# prepare y2 scaled data
ylim1 &lt;- range(df1$Val)
ylim2 &lt;- range(df2$Val)
scale_y2.1 &lt;- function(y, ylim1, ylim2) {
  ylim1[1] + (ylim1[2] - ylim1[1]) *(y - ylim2[1])/(ylim2[2] - ylim2[1])
}
dfAll &lt;- full_join(df1, df2, by = c(&quot;ID&quot;, &quot;Date&quot;), suffix = c(&quot;1&quot;, &quot;2&quot;))
y2.scl &lt;- scale_y2.1(dfAll$Val2, ylim1, ylim2)
dfAll &lt;- dfAll %&gt;% mutate(Val2_scl = y2.scl)

# prepare y2 ticks and scaled breaks
labs2 &lt;- pretty(ylim2)
brks2 &lt;- scale_y2.1(labs2, ylim1, ylim2)

With lines and points it works fine

# prepare legend guides
legguides &lt;- guides(color = guide_legend(title.position = &quot;top&quot;,
                                         override.aes = list(shape = c(NA, NA, 20, 20),
                                                             linetype = c(1, 1, 0, 0))))

# prepare geoms
gglines &lt;- geom_line(aes(x = Date, y = Val1, color = ID, group = ID), na.rm = TRUE)
ggpoints &lt;- geom_point(aes(x = Date, y = Val2_scl, color = ID, group = ID), na.rm = TRUE)

# generate ggplot
ggplot(dfAll) + gglines + ggpoints +
  scale_y_continuous(sec.axis = dup_axis(breaks = rev(brks2), labels = rev(labs2), name = &quot;Val2&quot;)) +
  coord_cartesian(ylim = ylim1) + ylab(&quot;Val1&quot;) +
  legguides

ggplot图例与geom_tile和geom_line

With bars and points it works fine too

# prepare legend guides
legguides &lt;- guides(color = guide_legend(title.position = &quot;top&quot;,
                                         override.aes = list(shape = c(15, 15, 20, 20),
                                                             linetype = c(0, 0, 0, 0))))

# prepare geoms
ggtiles &lt;- geom_tile(aes(x = Date, y = Val1/2, height = Val1, fill = ID, group = ID),
                     na.rm = TRUE, stat = &quot;identity&quot;, position = position_dodge(preserve = &quot;single&quot;),
                     show.legend = FALSE)

# generate ggplot
ggplot(dfAll) + ggtiles + ggpoints +
  scale_y_continuous(sec.axis = dup_axis(breaks = rev(brks2), labels = rev(labs2), name = &quot;Val2&quot;)) +
  coord_cartesian(ylim = ylim1) + ylab(&quot;Val1&quot;) +
  legguides

ggplot图例与geom_tile和geom_line

With bars and lines it fails to show any shape for the bars in the legend

# prepare legend guides
legguides &lt;- guides(color = guide_legend(title.position = &quot;top&quot;,
                                         override.aes = list(shape = c(15, 15, NA, NA),
                                                             linetype = c(0, 0, 1, 1))))

# prepare geoms
gglines &lt;- geom_line(aes(x = Date, y = Val2_scl, color = ID, group = ID), na.rm = TRUE)

# generate ggplot
ggplot(dfAll) + ggtiles + gglines +
  scale_y_continuous(sec.axis = dup_axis(breaks = rev(brks2), labels = rev(labs2), name = &quot;Val2&quot;)) +
  coord_cartesian(ylim = ylim1) + ylab(&quot;Val1&quot;) +
  legguides

ggplot图例与geom_tile和geom_line

I've tried with different shape values in the guide_legend() but the plot just seems to ignore that property. I think it has something to do with the fact that the two first examples use a geom_point() call, while the last one doesn't. The shape is one of the properties of a geom_point() object, but not of a geom_line() one.

I know I've read in a SO answer to a question about a legend that someone suggested to use a dummy geom_something() call just to have a shape added to the legend. Maybe that could work here using geom_point(), but I cannot get to find that thread or documentation on how to add an empty/dummy geom.

In case someone thinks of a solution using geom_bar() instead of geom_tile() note that I'm using the later here based on this SO answer which helped me get the bars to be plotted inverted when one of the axes is reversed.

答案1

得分: 1

以下是翻译好的部分:

"我不知道是否有一个解决这个问题的方法,实际上并不是一种权宜之计,但至少我们可以像你提到的那样使用虚拟的 geom_point() 来创建图例。

因此,我们可以使用上面示例中的 ggpoints 的定义,并将其透明度设置为 alpha = 0.0,以使点不再可见。请注意,我们还必须在 overwrite.aes() 中覆盖 alpha,以使图例中的条形图可见。

ggplot图例与geom_tile和geom_line

编辑后的代码部分:

# 准备几何对象
ggpoints <-
    geom_point(aes(
        x = Date,
        y = Val2_scl,
        color = ID,
        group = ID
    ),
    na.rm = TRUE,
    alpha = 0.0)

# 准备图例指南
legguides <- guides(color = guide_legend(
    title.position = "top",
    override.aes = list(
        shape = c(15, 15, NA, NA),
        linetype = c(0, 0, 1, 1),
        alpha = 1.0
    )
))

# 生成 ggplot 图
ggplot(dfAll) + ggtiles + gglines + ggpoints +
    scale_y_continuous(sec.axis = dup_axis(
        breaks = rev(brks2),
        labels = rev(labs2),
        name = "Val2"
    )) +
    coord_cartesian(ylim = ylim1) + ylab("Val1") +
    legguides
英文:

I don't know whether there is a solution for this problem which does not in fact is a workaround, but we can at least create the legend using a dummy geom_point() as already mentioned by you.

Therefore, we can use the definition of ggpoints from the above examples and set its transparency to alpha = 0.0 such that the points are not visible any more. Note that we then additionally have to overwrite alpha in overwrite.aes() in order to make the bars visible in the legend.

ggplot图例与geom_tile和geom_line

Edited code parts:

# prepare geoms
ggpoints &lt;-
    geom_point(aes(
        x = Date,
        y = Val2_scl,
        color = ID,
        group = ID
    ),
    na.rm = TRUE,
    alpha = 0.0)

# prepare legend guides
legguides &lt;- guides(color = guide_legend(
    title.position = &quot;top&quot;,
    override.aes = list(
        shape = c(15, 15, NA, NA),
        linetype = c(0, 0, 1, 1),
        alpha = 1.0
    )
))

# generate ggplot
ggplot(dfAll) + ggtiles + gglines + ggpoints +
    scale_y_continuous(sec.axis = dup_axis(
        breaks = rev(brks2),
        labels = rev(labs2),
        name = &quot;Val2&quot;
    )) +
    coord_cartesian(ylim = ylim1) + ylab(&quot;Val1&quot;) +
    legguides

huangapple
  • 本文由 发表于 2023年7月6日 19:25:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/76628328.html
匿名

发表评论

匿名网友

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

确定