r - 如何将图例从颜色条更改为 "regular legend",仍然使用颜色渐变

标签 r ggplot2 plotly

shinyscreenshot无法打印plotly颜色条(shiny screenshot appears with colorless legend),所以我正在寻找一种仍然使用颜色渐变但将图例显示为的方法如果它被因式分解。


示例

带颜色条的原点图

enter image description here

目标

enter image description here

图例中是否有 4、5 或 X 个数据点并不重要。


MWE

library(ggplot2)
library(plotly)

ggplotly(
  ggplot(data=mtcars,
         aes(x=mpg, y=cyl, color=qsec)) +
    geom_point()
)

最佳答案

Plotly 不会为您制作离散的图例,但您仍然可以实现它。

首先,我将 ggplotggplotly 分配给对象。

plt <- ggplotly(
  ggplot(data=mtcars,
         aes(x=mpg, y=cyl, color=qsec)) +
    geom_point()
)

g <- ggplot(data=mtcars,
            aes(x=mpg, y=cyl, color=qsec)) +
  geom_point()

接下来,使用ggplot对象背后的数据,结合mtcars,通过qsec数据框获取颜色,以便您知道什么颜色与什么值相配。

colByVal <- cbind(ggplot_build(g)$data[[1]], mtcars) %>% 
  as.data.frame() %>% 
  select(colour, qsec) %>% arrange(qsec) %>% 
  group_by(colour) %>% 
  summarise(qsec = median(qsec)) %>% as.data.frame()

我认为四个或五个值是理想的。我只是使用 summary 来选择它们。然而,这不是必要的。显然,您可以选择任意数量的值。这些是我将在图例中显示的值。

parts <- summary(colByVal$qsec)
# drop the mean or median (the same color probably)
parts <- parts[-4]

接下来,使用 DescTools::Closest 查找最接近汇总值的 qsec 值。

vals <- lapply(parts, function(k) {
  DescTools::Closest(colByVal$qsec, k)[1]
}) %>% unlist(use.names = F)

使用这些 qsec 值以及按颜色显示值的数据框来获取与这些值关联的颜色。

cols <- colByVal %>% 
  filter(qsec %in% vals) %>% select(colour) %>% 
  unlist(use.names = F)

使用颜色和值(图例标签)、形状和注释(圆圈和文本)来重建图例。每个图例项之间只有一个元素需要更改,即图例条目的 y 位置。

ys <- seq(from = .7, by = .07, length.out = length(cols))

有两个功能:形状和注释。使用lapply,通过这些函数遍历值、颜色和 y 值以创建形状和注释。

# create shapes
shp <- function(y, cr) { # y0, and fillcolor
  list(type = "circle",
       xref = "paper", x0 = 1.1, x1 = 1.125,
       yref = "paper", y0 = y, y1 = y + .025,
       fillcolor = cr, yanchor = "center",
       line = list(color = cr))
}
# create labels
ano <- function(ya, lab) { # y and label
  list(x = 1.13, y = ya + .035, text = lab, 
       xref = "paper", yref = "paper", 
       xanchor = "left", yanchor = 'top', 
       showarrow = F)
}
# the shapes list
shps <- lapply(1:length(cols),
               function(j) {
                 shp(ys[j], cols[j])
               })
# the labels list
labs <- lapply(1:length(cols),
               function(i) {
                 ano(ys[i], as.character(vals[i]))
               })

当您使用 ggplotly 时,由于某种原因,它会以空形状结束 ggplotly 对象。这会干扰在 layout 中调用 shapes 的能力(这是正确的方法)。你必须用形状来解决这个问题。此外,图例栏需要消失。一旦您放下图例栏,Plotly 将调整绘图边距。如果您不重新添加边距,则使用形状和注释创建的图例将被隐藏。

# ggplot > ggplotly adds an empty shape; this conflicts with calling it in
#   layout(); we'll replace 'shapes' first
plt$x$layout$shapes <- shps
plt %>% hide_colorbar() %>% 
  layout(annotations = labs, showlegend = F, 
         margin = list(t = 30, r = 100, l = 50, b = 30, pad = 3))

enter image description here

所有代码都集中在一个 block 中:

library(tidyverse)
library(plotly)
# original plot
plt <- ggplotly(
  ggplot(data=mtcars,
         aes(x=mpg, y=cyl, color=qsec)) +
    geom_point()
)
g <- ggplot(data=mtcars,
            aes(x=mpg, y=cyl, color=qsec)) +
  geom_point()
# color by qsec values frame
colByVal <- cbind(ggplot_build(g)$data[[1]], mtcars) %>% 
  as.data.frame() %>% 
  select(colour, qsec) %>% arrange(qsec) %>% 
  group_by(colour) %>% 
  summarise(qsec = median(qsec)) %>% as.data.frame()

parts <- summary(colByVal$qsec)
# drop the mean or median (the same color probably)
parts <- parts[-4]

vals <- lapply(parts, function(k) {
  DescTools::Closest(colByVal$qsec, k)[1]
}) %>% unlist(use.names = F)

cols <- colByVal %>% 
  filter(qsec %in% vals) %>% select(colour) %>% 
  unlist(use.names = F)

ys <- seq(from = .7, by = .07, length.out = length(cols))

# create shapes
shp <- function(y, cr) { # y0, and fillcolor
  list(type = "circle",
       xref = "paper", x0 = 1.1, x1 = 1.125,
       yref = "paper", y0 = y, y1 = y + .025,
       fillcolor = cr, yanchor = "center",
       line = list(color = cr))
}
# create labels
ano <- function(ya, lab) { # y and label
  list(x = 1.13, y = ya + .035, text = lab, 
       xref = "paper", yref = "paper", 
       xanchor = "left", yanchor = 'top', 
       showarrow = F)
}
# the shapes list
shps <- lapply(1:length(cols),
               function(j) {
                 shp(ys[j], cols[j])
               })
# the labels list
labs <- lapply(1:length(cols),
               function(i) {
                 ano(ys[i], as.character(vals[i]))
               })
# ggplot > ggplotly adds an empty shape; this conflicts with calling it in
#   layout(); we'll replace 'shapes' first
plt$x$layout$shapes <- shps
plt %>% hide_colorbar() %>% 
  layout(annotations = labs, showlegend = F, 
         margin = list(t = 30, r = 100, l = 50, b = 30, pad = 3))

关于r - 如何将图例从颜色条更改为 "regular legend",仍然使用颜色渐变,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74502777/

相关文章:

python - 使用 "plotnine"库绘制表面 3D 图

python - plotly : plotly 表达 add_vrect 到图的问题

python - 单击 matplotlib(或可能是 plotly)中的阶梯图子图点时如何使标 checkout 现?

R:rCharts 和 Shiny,运行时图表不会显示

r - 如何根据ggplot中的第三个因子变量维护变量的顺序?

r - R : constrOptim contraints 中的优化

r - 在使用 geom_abline 创建的线之间绘制带状图

python - 从 R 到 python pandas : create id key series in order on duplicates

r - X轴日期不按时间顺序排列

r - sf 对象在 R data.table 中创建为列表