【问题标题】:Is it possible to change the alignment of only 1 facet title是否可以仅更改 1 个方面标题的对齐方式
【发布时间】:2020-09-16 03:15:25
【问题描述】:

假设我有一个这样的多面 ggplot:

data(iris)
ggplot(iris, aes(x = Petal.Width, y = Sepal.Length)) +
  facet_grid(. ~ Species) +
  geom_point()

问题:

是否可以仅将第一个构面标签(“setosa”)向左对齐,而将其他标签保持居中?

我对直接ggplot 没有任何运气,所以我尝试转换为 gtable(代码如下),我可以看到我可能需要修改的元素是 tableGrb #13 - strip-t-1,但我不知道该怎么做。我尝试将 gt$layout$lgt$layout$r 的值更改为 4(原为 5),但这会将标题完全移出刻面。

pl <- ggplot(iris, aes(x = Petal.Width, y = Sepal.Length)) +
  facet_grid(. ~ Species) +
  geom_point()
gt <- ggplotGrob(pl)

gt$layout[gt$layout$name == 'strip-t-1', c('l', 'r')] <- c(4, 4) # my attempt
grid.newpage()
grid.draw(gt)

有谁知道这是否可行?

【问题讨论】:

标签: r ggplot2 facet-grid ggtext


【解决方案1】:

你有正确的想法,但不是正确的位置。基本上你需要做这样的事情:

library('ggplot2')
library('grid')

data(iris)
pl <- ggplot(iris, aes(x = Petal.Width, y = Sepal.Length)) +
  facet_grid(. ~ Species) +
  geom_point()
gt <- ggplotGrob(pl)

gt$grobs[[13]]$grobs[[1]]$children$strip.text.x.top..titleGrob.186$children$GRID.text.184$x <- unit(0.1, 'npc')
grid.newpage()
grid.draw(gt)

但这对你不起作用......自从每次使用 gt &lt;- ggplotGrob(pl) 时,titleGrob.xxxGRID.text.xxx 都会发生变化,它甚至不会对我起作用。

所以尝试一种不同的方法,并按照你指出的那样知道你需要编辑的位置(它在第一个 strip 中):

gp <- ggplotGrob(pl)
grid.ls(grid.force(gp))

# layout
#   background.1-13-13-1
#   panel-1-1.8-5-8-5
# ...
#   strip-t-1.7-5-7-5                        <- here
#     strip.1-1-1-1
#       strip.background.x..rect.533
#       strip.text.x.top..titleGrob.525
#         GRID.text.523
#   strip-t-2.7-7-7-7
#     strip.1-1-1-1
#       strip.background.x..rect.533
#       strip.text.x.top..titleGrob.528
#         GRID.text.526
#   strip-t-3.7-9-7-9
#     strip.1-1-1-1
#       strip.background.x..rect.533
#       strip.text.x.top..titleGrob.531
#         GRID.text.529
#   axis-t-1.6-5-6-5
# ...
#   title.3-9-3-5
#   caption.11-9-11-5
#   tag.2-2-2-2

您可以使用gPath 获取路径,而无需事先知道GRID.text.xxx。请注意,在您的示例中,我们可以只编辑第一个GRID.text,如果global = FALSE 它将起作用,即如果global = TRUE,它们都会改变。

g1 <- editGrob(
  grid.force(gp),
  gPath('GRID.text'), grep = TRUE, global = FALSE,
  x = unit(0.25, 'npc')
)
grid.newpage()
grid.draw(g1)

但是,您可能需要一个非常具体的路径,因此请按照strip-t-1 向下到您的GRID.text(注意global = TRUE,它只影响一个条带)

g2 <- editGrob(
  grid.force(gp),
  gPath('strip-t-1', 'strip', 'strip', 'GRID.text'), grep = TRUE, global = TRUE,
  x = unit(0.75, 'npc')
)
grid.newpage()
grid.draw(g2)

【讨论】:

  • 一个小建议:x = unit(0, 'npc'), hjust = 0 在左对齐方面可能比 x = unit(0.25, 'npc') 本身更安全,因为绘图的大小/构面标题的长度在其他用例中可能会有所不同。跨度>
  • @Z.Lin just = 'left'just = 'right' 也可以吗?我总是必须在基本图中同时尝试adj = 0adj = 1 来记住哪个是左哪个是右。这个问题让我想起了为什么我像瘟疫一样避免 ggplot
  • just = 'left' (或正确的)如果你也输入hjust = NULL 应该可以工作,因为如果指定,后者会覆盖前者。这是我对?grid::grid.text的理解。
【解决方案2】:

这是最终 ggtext 包应该能够以一般方式完成的事情,但到目前为止,它的 HTML 呈现代码太有限了。一个新的渲染引擎正在开发中,它支持更多的 CSS,包括 CSS 选择器,这使得以通用方式将格式设置为特定数据值成为可能。它还支持左对齐文本所需的text-align 属性。

下面是两个例子,说明它是如何工作的。一旦新的渲染引擎集成到 ggtext 中,您将不再需要帮助代码。

# packages needed
library(ggplot2)
library(dplyr)
library(glue)
library(rlang)
library(sinab)  # remotes::install_github("clauswilke/sinab")

# helper code that will eventually live in the ggtext package
element_html <- function(css = NULL, family = NULL, face = NULL, size = NULL, colour = NULL, fill = NULL,
                         linetype = NULL, linewidth = NULL, hjust = NULL, vjust = NULL, lineheight = NULL,
                         margin = NULL, width = NULL, height = NULL, color = NULL, 
                         debug = FALSE, inherit.blank = FALSE) {
  if (!is.null(color))
    colour <- color
  
  # doesn't work with other values at this time
  hjust <- 0
  vjust <- 1
  
  structure(
    list(
      css = css,
      family = family, face = face, size = size, colour = colour, fill = fill,
      linetype = linetype, linewidth = linewidth, hjust = hjust, vjust = vjust,
      lineheight = lineheight, margin = margin, width = width, height = height,
      debug = debug, inherit.blank = inherit.blank),
    class = c("element_html", "element_text", "element")
  )
}

element_grob.element_html <- function(element, label = "", x = NULL, y = NULL,
                                      family = NULL, face = NULL, colour = NULL, size = NULL,
                                      hjust = NULL, vjust = NULL, lineheight = NULL,
                                      margin = NULL, ...) {
  if (is.null(label))
    return(ggplot2::zeroGrob())
  
  # for now we ignore hjust and vjust, it doesn't work yet
  hj <- 0
  vj <- 1
  
  css <- element$css %||% ""
  
  html_grob(
    label, x = x, y = y, hjust = hj, vjust = vj,
    width = element$width, height = element$height,
    css = css
  )
}


# CSS styling
css <- '
p { text-align: center; padding-top: 2px; }
.setosa { text-align: left; }
'

# plotting code
iris %>%
  mutate(
    # set class attribute to species name
    facet_label = glue('<p class = "{Species}">{Species}</p>')
  ) %>%
  ggplot(aes(x = Petal.Width, y = Sepal.Length)) +
  facet_grid(. ~ facet_label) +
  geom_point() +
  theme(strip.text = element_html(css = css))

# another example with different styling
css <- '
p { text-align: center; padding-top: 2px; font-style: italic; }
.setosa { background-color: #0072B2; color: white; }
.versicolor { background-color: #E69F00; }
.virginica { background-color: #009E73;  color: white; }
'

# plotting code
iris %>%
  mutate(
    # set class attribute to species name
    facet_label = glue('<p class = "{Species}">I. {Species}</p>')
  ) %>%
  ggplot(aes(x = Petal.Width, y = Sepal.Length, color = Species)) +
  facet_grid(. ~ facet_label) +
  geom_point() +
  scale_color_manual(
    values = c(
      setosa = "#0072B2", versicolor = "#E69F00", virginica = "#009E73"
    ),
    guide = "none"
  ) +
  theme_bw() +
  theme(
    strip.background = element_blank(),
    strip.text = element_html(css = css)
  )

reprex package (v0.3.0) 于 2020 年 9 月 16 日创建

【讨论】:

    猜你喜欢
    • 2012-07-08
    • 2017-03-19
    • 2011-06-25
    • 2018-06-04
    • 1970-01-01
    • 1970-01-01
    • 2017-07-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多