使用ggplot、gtable和cowplot固定图例框的宽度

2023-12-23

我想用 R 制作一个绘图,看起来像用 Mac 的 Numbers 制作的示例。我正在努力处理情节和图例框之间的空间。这是我想要实现的目标的示例:

在一些用户的帮助下(请参阅帖子末尾以供参考),我已经非常接近了。这是我当前的功能:

library(tidyverse)
library(cowplot)
library(gtable)
library(grid)
library(patchwork)


custom_barplot <- function(dataset, x_value, y_value, fill_value, nfill, xlab, ylab, y_limit, y_steps,legend_labels) {
# Example color set to choose from
colors=c("#CF232B","#942192","#000000","#f1eef6","#addd8e","#d0d1e6","#31a354","#a6bddb")

# user function for adjusting the size of key-polygons in legend
draw_key_polygon2 <- function(data, params, size) {
  lwd <- min(data$size, min(size) / 4)
  
  grid::rectGrob(
    width = grid::unit(0.8, "npc"),
    height = grid::unit(0.8, "npc"),
    gp = grid::gpar(
      col = data$colour,
      fill = alpha(data$fill, data$alpha),
      lty = data$linetype,
      lwd = lwd * .pt,
      linejoin = "mitre"
    ))
}
# user function for the plot itself
plot <- function(dataset, x_value, y_value, fill_value, nfill, xlab, ylab, y_limit, y_steps,legend,legend_labels) 
{ggplot(data=dataset, mapping=aes(x={{x_value}}, y={{y_value}}, fill={{fill_value}})) +
    geom_col(position=position_dodge(width=0.85),width=0.8,key_glyph="polygon2",show.legend=legend) + 
    geom_smooth(aes(color={{fill_value}}),method="lm",formula=y~x, se=FALSE,show.legend=legend, linetype="dashed") +
    labs(x=xlab,y=ylab) +
    theme(text=element_text(size=9,color="black"),
          panel.background = element_rect(fill="white"),
          panel.grid = element_line(color = "black",linetype="solid",size= 0.3),
          panel.grid.minor = element_blank(),
          panel.grid.major.x=element_blank(),
          axis.text=element_text(size=9),
          axis.line.x=element_line(color="black"),
          axis.ticks= element_blank(),
          legend.text=element_text(size=9),
          legend.position = "right",
          legend.justification = "top",
          legend.title = element_blank(),
          legend.key.size = unit(4,"mm"),
          legend.key = element_rect(fill="white"),
          plot.margin=unit(c(1,0.25,0.5,0.5),"cm")) +
    scale_y_continuous(breaks= seq(from=0, to=y_limit,by=y_steps),
                       limits=c(0,y_limit+1), 
                       expand=c(0,0)) +
    scale_x_continuous(breaks=min(data[,deparse(ensym(x_value))],na.rm=TRUE):max(data[,deparse(ensym(x_value))],na.rm=TRUE)) +
    scale_fill_manual(values = colors[1:nfill],labels={{legend_labels}})+
    scale_color_manual(values= colors[1:nfill],labels=paste("Trend ",{{legend_labels}},sep=""))+
    guides(color=guide_legend(override.aes=list(fill=NA),order=2),fill=guide_legend(override.aes = list(linetype=0),order=1))}

# taking the legend of the plot and removing the first column of the gtable within the legend
p_legend <- #cowplot::get_legend(plot(dataset, {{x_value}}, {{y_value}}, {{fill_value}}, nfill, xlab, ylab, y_limit, y_steps,legend=TRUE))
  gtable_squash_cols(cowplot::get_legend(plot(dataset, {{x_value}}, {{y_value}}, {{fill_value}},nfill, xlab, ylab, y_limit, y_steps,legend=TRUE,legend_labels)),1)

# printing the plot without legend
p_main <- plot(dataset, {{x_value}}, {{y_value}}, {{fill_value}}, nfill, xlab, ylab, y_limit, y_steps,legend=FALSE,legend_labels = NULL)

#joining it all together
Obj<- p_main+plot_spacer() + p_legend +
  plot_layout(widths=c(12.5,1.5,4))

return(Obj)

}

我的问题是,图例框的宽度似乎会根据标签的大小进行调整,因此绘图和图例之间的距离不会保持不变。

示例数据:

set.seed(9)
data <- data.frame(Cat=c(rep("A",times=5),rep("B",times=5),rep("C", times=5)),
                   year=rep(c(2015,2016,2017,2018,2019),times=3),
                   count=c(sample(seq(60,80),replace=TRUE,size=5),sample(seq(100,140),replace=TRUE,size=5),sample(seq(20,30),replace=TRUE,size=5)))

我制作了四个图,其中只有标签不同:

plt <- custom_barplot(dataset=data %>% filter(year %in% c(2015,2016,2017)), 
     x_value=year,
     y_value=count, 
     fill_value=Cat, 
     nfill=3, 
     xlab="Year",
     ylab="Count",
     y_limit=140, 
     y_steps=20,
     legend_labels=c("A","B","C"))


plt_2 <- custom_barplot(dataset=data %>% filter(year %in% c(2015,2016,2017)), 
                        x_value=year,
                        y_value=count, 
                        fill_value=Cat, 
                        nfill=3, 
                        xlab="Year",
                        ylab="Count",
                        y_limit=140, 
                        y_steps=20,
                        legend_labels=c("Long Label A","Long Label B","Long Label C"))

plt_3 <- custom_barplot(dataset=data %>% filter(year %in% c(2015,2016,2017)), 
                        x_value=year,
                        y_value=count, 
                        fill_value=Cat, 
                        nfill=3, 
                        xlab="Year",
                        ylab="Count",
                        y_limit=140, 
                        y_steps=20,
                        legend_labels=c("Xtra Long Label A","Xtra Long Label B","Xtra Long Label C"))

plt_4 <- custom_barplot(dataset=data %>% filter(year %in% c(2015,2016,2017)), 
                        x_value=year,
                        y_value=count, 
                        fill_value=Cat, 
                        nfill=3, 
                        xlab="Year",
                        ylab="Count",
                        y_limit=140, 
                        y_steps=20,
                        legend_labels=c("Super Xtra Long Label A","Super Xtra Long Label B","Super Xtra Long Label C"))

The resulting plots look like this: enter image description here enter image description here enter image description here enter image description here

我需要情节和图例之间的空间保持不变,不管图例中标签的长度。我宁愿不完全显示该标签(所以我认为我必须缩短它)。这些图表用于文档中簇绒讲义风格图例应与注释位于同一区域。

您知道如何保持空间恒定吗?

参考:

  • 基本方法通过tjebo https://stackoverflow.com/a/66925859/14027466在这个post https://stackoverflow.com/q/66918748/14027466
  • 情节和图例之间的空间的一般调整stefan https://stackoverflow.com/a/67029094/14027466在这个post https://stackoverflow.com/q/67026849/14027466

我认为最简单的解决方案是简单地对图例中的文本进行换行。您可以使用以下方法执行此操作stringr::str_wrap()给出如下结果:

这是对函数的一个非常小的编辑,它允许用户控制文本换行:


custom_barplot <- function(dataset, x_value, y_value, fill_value, nfill, xlab, ylab, y_limit, y_steps, legend_labels, wrap_labels = 20) {
  # Example color set to choose from
  colors <- c("#CF232B", "#942192", "#000000", "#f1eef6", "#addd8e", "#d0d1e6", "#31a354", "#a6bddb")

  # user function for adjusting the size of key-polygons in legend
  draw_key_polygon2 <- function(data, params, size) {
    lwd <- min(data$size, min(size) / 4)

    grid::rectGrob(
      width = grid::unit(0.8, "npc"),
      height = grid::unit(0.8, "npc"),
      gp = grid::gpar(
        col = data$colour,
        fill = alpha(data$fill, data$alpha),
        lty = data$linetype,
        lwd = lwd * .pt,
        linejoin = "mitre"
      )
    )
  }
  # user function for the plot itself
  plot <- function(dataset, x_value, y_value, fill_value, nfill, xlab, ylab, y_limit, y_steps, legend, legend_labels) {
    ggplot(data = dataset, mapping = aes(x = {{ x_value }}, y = {{ y_value }}, fill = {{ fill_value }})) +
      geom_col(position = position_dodge(width = 0.85), width = 0.8, key_glyph = "polygon2", show.legend = legend) +
      geom_smooth(aes(color = {{ fill_value }}), method = "lm", formula = y ~ x, se = FALSE, show.legend = legend, linetype = "dashed") +
      labs(x = xlab, y = ylab) +
      theme(
        text = element_text(size = 9, color = "black"),
        panel.background = element_rect(fill = "white"),
        panel.grid = element_line(color = "black", linetype = "solid", size = 0.3),
        panel.grid.minor = element_blank(),
        panel.grid.major.x = element_blank(),
        axis.text = element_text(size = 9),
        axis.line.x = element_line(color = "black"),
        axis.ticks = element_blank(),
        legend.text = element_text(size = 9),
        legend.position = "right",
        legend.justification = "top",
        legend.title = element_blank(),
        legend.key.size = unit(4, "mm"),
        legend.key = element_rect(fill = "white"),
        plot.margin = unit(c(1, 0.25, 0.5, 0.5), "cm")
      ) +
      scale_y_continuous(
        breaks = seq(from = 0, to = y_limit, by = y_steps),
        limits = c(0, y_limit + 1),
        expand = c(0, 0)
      ) +
      scale_x_continuous(breaks = min(data[, deparse(ensym(x_value))], na.rm = TRUE):max(data[, deparse(ensym(x_value))], na.rm = TRUE)) +
      scale_fill_manual(values = colors[1:nfill], labels = stringr::str_wrap({{ legend_labels }}, wrap_labels)) +
      scale_color_manual(values = colors[1:nfill], labels = stringr::str_wrap(paste("Trend ", {{ legend_labels }}, sep = ""), wrap_labels)) +
      guides(color = guide_legend(override.aes = list(fill = NA), order = 2), fill = guide_legend(override.aes = list(linetype = 0), order = 1))
  }

  # taking the legend of the plot and removing the first column of the gtable within the legend
  p_legend <- # cowplot::get_legend(plot(dataset, {{x_value}}, {{y_value}}, {{fill_value}}, nfill, xlab, ylab, y_limit, y_steps,legend=TRUE))
    gtable_squash_cols(cowplot::get_legend(plot(dataset, {{ x_value }}, {{ y_value }}, {{ fill_value }}, nfill, xlab, ylab, y_limit, y_steps, legend = TRUE, legend_labels)), 1)

  # printing the plot without legend
  p_main <- plot(dataset, {{ x_value }}, {{ y_value }}, {{ fill_value }}, nfill, xlab, ylab, y_limit, y_steps, legend = FALSE, legend_labels = NULL)

  # joining it all together
  Obj <- p_main + plot_spacer() + p_legend +
    plot_layout(widths = c(12.5, 1.5, 4))

  return(Obj)
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用ggplot、gtable和cowplot固定图例框的宽度 的相关文章

  • 在 R 的 stargazer 表中设置注释格式

    我在用stargazer包来生成 回归输出 表 一切都在奇迹般地进行 直到我开始编辑笔记 First 换行很难 但是 Bryansuggests https stackoverflow com questions 21720264 star
  • 将从数据透视表包生成的数据透视表转换为数据帧

    我正在尝试制作一个数据透视表pivottabler包裹 我想将数据透视表对象转换为数据框 以便我可以将其转换为数据表 带有 DT 并在 Shiny 应用程序中渲染它 以便可以下载 library pivottabler pt qpvt mt
  • R data.table:在当前测量之前对出现次数进行计数

    我有一组在几天内进行的测量结果 测量次数通常为 4 任何测量中可以捕获的数字范围为 1 5 在现实生活中 给定测试集 范围可能高达 100 或低至 20 我想每天计算每个值在当天之前发生的次数 让我用一些示例数据来解释 test data
  • 将整数“20160119”转换为“日”“年”“月”的不同列

    如何将一列整数转换为日期 DATE PRCP 1 19490101 25 2 19490102 5 3 19490118 18 4 19490119 386 5 19490202 38 到这样的表 days month years PRCP
  • R - 对矩阵的每行/列应用具有不同参数值的函数

    我试图将函数应用于矩阵的每一行或每一列 但我需要为每一行传递不同的参数值 我以为我熟悉 lapply mapply 等 但可能还不够 举个简单的例子 gt a lt matrix 1 100 ncol 10 gt a 1 2 3 4 5 6
  • 将 XML 的所有字段(和子字段)导入为数据框

    为了进行一些分析 我想使用 R 和 XML 包将 XML 导入数据帧 XML 文件示例
  • 使用 R 中“rpart”包中的生存树来预测新的观察结果

    我正在尝试使用 R 中的 rpart 包来构建生存树 并且我希望使用这棵树来对其他观察结果进行预测 我知道有很多涉及 rpart 和预测的问题 但是 我还没有找到任何解决 我认为 特定于将 rpart 与 Surv 对象一起使用的问题的方法
  • 在 R 中,如何让 PRNG 在平台之间给出相同的浮点数?

    在 R 4 1 1 中运行以下代码会在平台之间产生不同的结果 set seed 1 x lt rnorm 3 3 print x 22 0 83562861241004716 intel windows 0 8356286124100471
  • 在 Microsoft Windows 上安装 RQuantLib

    我需要安装R包RQuantLib在 Microsoft Windows 计算机上 这个包没有二进制文件 所以我下载了 tar 源 我打开它 它包含 QuantLib C 库 所以我需要编译这个包 我不想安装 Visual Studio 我使
  • Quanteda 包,朴素贝叶斯:如何预测不同特征的测试数据?

    I used quanteda textmodel NB创建一个模型 将文本分类为两个类别之一 我将模型拟合到去年夏天的训练数据集上 现在 我今年夏天尝试使用它对我们在工作中收到的新文本进行分类 我尝试这样做并收到以下错误 Error in
  • 按元素名称组合/合并列表

    我有两个列表 其元素的名称部分重叠 我需要将其逐个元素合并 组合成一个列表 gt lst1 lt list integers c 1 7 letters letters 1 5 words c two strings gt lst2 lt
  • 我们如何获取R中的商品价格?

    正如标题 我知道我们可以使用quantmod包来获取股票价格 但我们如何检索黄金 石油或农产品等商品价格 Use Quandl包 这里有一些例子 Gold lt Quandl LBMA GOLD WTI lt Quandl CHRIS CM
  • 滚动最小值,固定起点[重复]

    这个问题在这里已经有答案了 好的 我想计算数据框中的滚动最小值 向下滚动列 到目前为止 我无法确定该系列的起点并滚动到结尾 我努力了 mins lt c 10 5 6 10 6 6 7 8 2 12 roll min expected lt
  • 在水平条形图中绘制连续分布

    这是我之前的question https stackoverflow com questions 71318781 multiple variable distribution plot using ggplot2使用多重分布解决了这个问题
  • 在R中重新排序字母数字年龄组

    假设这就是 R 给我的 df1 data frame grp c lt 2 2 5 21 26 27 32 6 10 val rep 0 5 grp val 1 lt 2 0 2 2 5 0 3 21 26 0 4 27 32 0 5 6
  • 如何在 ifelse 中使用示例

    我有以下清单 x rep a 100 如果我使用下表 ifelse x a sample c 1 100 1 0 当我第一次运行时 我得到以下输出 1 22 22 22 22 22 22 22 22 22 22 22 22 22 22 22
  • 读取 csv 文件时出错

    我有一个 xlsx 文件 为了从 Rstudio 读取 我将其保存为 csv 文件 现在 当我尝试从 Rstudio 读取文件时 收到以下错误 setwd D DATA SCIENCE CCPP Linear regression ccpp
  • scale_y_discrete 忽略中断/标签

    漏洞 可能相关对此 https github com tidyverse ggplot2 issues 1589 dat data frame x 1 4 y ordered c 4 gt 5 1 1 levels c 1 5 gt 5 g
  • Predict.randomForest 中的错误

    我希望有人能够帮助我解决 R 中 randomForest 包的预测函数遇到的问题 当我尝试预测测试数据时 我不断收到相同的错误 到目前为止 这是我的代码 extractFeatures lt function RCdata feature
  • 在R中读写csv.gz文件

    有非常similar https stackoverflow com questions 9548630 read gzipped csv directly from a url in r关于这个主题的问题 但非在 R 下非常精确地处理这个

随机推荐

  • Rails 路由(root :to => ...)

    我知道如何将 Rails 应用程序的路由根设置为控制器和操作 但是如何添加id呢 pages show 1应该是根 我该如何设置这个 遇到了同样的问题 这对我有用 root to gt pages show id gt 1
  • 在谷歌colab中加载图像

    我的 Jupyter Notebook 有以下代码可将图像上传到 Colab from google colab import files uploaded files upload 系统提示我输入该文件 哪个被上传 我使用以下命令验证文件
  • 如何在 Next.js 中为非默认语言环境生成动态路径?

    我正在使用 next i18next 构建一个具有国际化功能的 Next js 应用程序 为我网站的所有页面生成英语和法语页面 但具有动态路由的页面除外 即 blog id blog title 对于具有动态路由的页面 会生成英语页面 但不
  • 将 url 扩展添加到 Laravel 路由

    是否可以像这样向 laravel 路由添加扩展 http www mywebsite com members login html 和另一个具有不同扩展名的页面 http www mywebsite com contactus htm 我正
  • 如何将自定义工具链添加到 eclipse CDT

    我有一个基于 gnu arm 的自定义工具链 我已经下载了带 CDT 的 eclipse IDE 我想知道如何使用 eclipse 添加我的工具链 它有一个通用工具链 即Linux GCC 除此之外就没有什么了 我想添加我的 我没有找到任何
  • 如何生成所有 Tetromino 的列表?

    如何生成所有 Tetromino 的列表 或者 更一般地说 如何生成仅限于多个单元格的多联骨牌子集 有很多方法可以做到这一点 我发现效果很好的一种选择是递归地 更普遍地思考它 尤其 单个矩形是 1 多米诺骨牌 对于任何 n 型骨牌 您可以通
  • Java FX 模块化应用程序,未找到模块(Java 11、Intellij)

    您好 我的模块化 Java FX 应用程序有问题 首先 我使用 Intellij 向导创建了一个 JavaFX 项目 我添加了 Java FX 库 JavaFX 模块得到了认可 我的模块信息 java 我还添加了虚拟机选项 但我总是收到此错
  • Xcode:需要将游戏锁定为仅纵向

    我刚刚向应用商店发布了一款游戏 然后意识到我完全忘记将其仅锁定为纵向 我需要提交一个可以做到这一点的更新版本 此时 只需转到 常规 gt 部署信息 并取消选中除 肖像 之外的所有内容 然后将其作为新版本提交就足够了吗 或者我还需要对代码做一
  • 帮助 PHP call_user_func 并将函数集成到类中?

    下面是我大约一年前发现的一个函数 它应该对内存缓存键加锁 这样您就可以更新它的值 而不会出现 2 个请求同时尝试更新键的麻烦 这是非常基本的 但我需要一些帮助来弄清楚如何 100 使用它 我不确定的部分是它在哪里传递 update函数然后传
  • 解码 Angular 6 中的 html 实体

    我正在寻找一个可以在 Angular 6 中解码 HTML 实体的库 我试图找到一些东西 我在 Angular 2 中找到了一个名为 trustashtml 的函数 但我认为 6 版本不可用 下面你可以在 html 模板中找到我的代码 di
  • 使用静态构建curl链接项目

    我正在使用 CMake 和 MinGW32 在 C 中做一个小项目 它需要 libcurl 库 但是当我尝试链接静态构建 libcurl a 时 出现未定义的引用错误 undefined reference to imp curl easy
  • Kendo UI 网格在初始读取时不显示微调器/加载图标

    我已经设置了 kendo ui 网格来从返回 JSON 的 MVC 操作中读取数据 由于成本原因 我使用的是 Kendo 的免费版本 而不是特定的 MVC 问题是 当页面加载并进行网格的初始填充时 它不会显示加载微调器 填充网格后 我转到另
  • 如何在sequelize连接对象中设置应用程序名称?

    Summary 我想改变application name of the connection string当初始化一个新的sequelize对象时 基于这个计算器问题 https stackoverflow com questions 40
  • 在 Ruby on Rails 中将表单路由到新的控制器操作

    我对 Ruby on Rails 比较陌生 并且正在尝试在现有控制器上设置一个具有新操作的表单 我现有的模型和控制器称为 项目 我在控制器中创建了一个名为 队列 的新操作 目标是用户可以使用 queue username 过滤不同用户的项目
  • 测试 .NET 应用程序中的内存泄漏

    是否有任何好的 且免费 工具可以分析静态源或运行程序来帮助检测内存泄漏 我已经构建了一些 Windows 服务 并希望确保如果我让它们连续运行数周 它们不会消耗内存 不符合你对免费的要求 但 Red Gate 的一个我认为值得推荐 ANTS
  • 在构造函数中使用重写方法的替代方案,Java

    在我正在编码的 Java 项目中 我最终使用了在构造函数中重写的方法 就像是 class SuperClass SuperClass intialise protected void initialise Do some stuff com
  • 实时显示 mathjax 输出

    如何修改这个 mathjax 示例以在打字时进行实时预览 现在它只在我按下回车键后才显示结果 我想调整它 使其工作方式类似于 stackoverflow math stackexchange 在输入问题时显示预览的方式
  • 通过 ASP.NET 菜单控件禁用 javascript 生成

    在我的网站中 我使用标准 ASP NET 菜单控件 我已经编写了一个自定义控制适配器来摆脱由默认控制适配器生成的相当俗气的 html 输出 但有一件事一直困扰着我 不知何故 ASP NET 生成了我的菜单控件不需要的额外 JavaScrip
  • Google 地理编码 API 错误:超出查询限制。 - 导轨

    我知道有人问过这个问题 但大多数答案都是几年前的 而且并非全部针对 Ruby on Rails 项目 在我当前的项目中 我使用 Geocode gem 通过 Ruby on Rails 任何人都可以按用户的位置搜索用户 我还使用 Carme
  • 使用ggplot、gtable和cowplot固定图例框的宽度

    我想用 R 制作一个绘图 看起来像用 Mac 的 Numbers 制作的示例 我正在努力处理情节和图例框之间的空间 这是我想要实现的目标的示例 在一些用户的帮助下 请参阅帖子末尾以供参考 我已经非常接近了 这是我当前的功能 library