Интересно, есть ли способ спросить R, имеет ли сюжет фиксированное соотношение сторон или нет. Вот два примера графиков:

library (ggplot2)

plot_a <- ggplot(iris, aes(Sepal.Length, Sepal.Width, color = Species)) +
          geom_point()+
          theme (aspect.ratio = 1)

plot_b <- ggplot(iris, aes(Sepal.Length, Sepal.Width, color = Species)) +
          geom_point()

В то время как plot_a имеет фиксированное соотношение сторон, plot_b не имеет фиксированного соотношения сторон. Я ищу следующую воображаемую функцию:

is_fixed_ratio (plot_a) 
TRUE

is_fixed_ratio (plot_b)
FALSE

Есть ли способ добиться этого?

3
yenats 6 Ноя 2019 в 17:57

5 ответов

Предположим, у нас есть следующие графики:

library (ggplot2)

plot_a <- ggplot(iris, aes(Sepal.Length, Sepal.Width, color = Species)) +
          geom_point()+
          theme (aspect.ratio = 1)

plot_b <- ggplot(iris, aes(Sepal.Length, Sepal.Width, color = Species)) +
          geom_point()

plot_c <- ggplot(iris, aes(Sepal.Length, Sepal.Width, color = Species)) +
          geom_point() +
          coord_equal()

В текущем принятом ответе они будут рассматриваться следующим образом:

is_fixed_ratio <- function(plot){
  purrr::map(plot, "aspect.ratio") %>% 
    unlist() %>% 
    is.null() %>% 
    !.
}
> is_fixed_ratio(plot_a)
[1] TRUE
> is_fixed_ratio(plot_b)
[1] FALSE
> is_fixed_ratio(plot_c)
[1] FALSE

В то время как plot_c имеет фиксированное соотношение сторон, просто не указанное в теме.

Чтобы проверить это, вы можете просмотреть таблицу графика:

is_fixed_ratio2 <- function(plot) {
  ggplotGrob(plot)$respect
}
> is_fixed_ratio2(plot_a)
[1] TRUE
> is_fixed_ratio2(plot_b)
[1] FALSE
> is_fixed_ratio2(plot_c)
[1] TRUE
3
teunbrand 6 Ноя 2019 в 20:12
Это ИМО - гораздо лучший ответ, чем принятый, и, вероятно, менее вероятно, что он изменится в будущем.
 – 
alan ocallaghan
6 Ноя 2019 в 20:23
Только что заметил этот ответ после публикации, по сути, того же самого.
 – 
Claus Wilke
7 Ноя 2019 в 00:07
Приятно знать, что, по крайней мере, это было правильно, но я бы сказал, что ваше объяснение более актуально.
 – 
teunbrand
7 Ноя 2019 в 00:20

Действительно хороший способ справиться с такими проблемами - использовать map из пакета purrr. При этом вам не нужно искать в списке вручную:

is_fixed_ratio <- function(plot){
  purrr::map(plot, "aspect.ratio") %>% 
    unlist() %>% 
    is.null() %>% 
    !.
}
is_fixed_ratio(plot_a)
is_fixed_ratio(plot_b)
2
mnist 6 Ноя 2019 в 18:08
Это действительно очень хороший вариант. Мне нравится идея тестирования с помощью специальной функции из-за ее удобочитаемости.
 – 
yenats
6 Ноя 2019 в 20:02

Отредактировано для проверки любого соотношения сторон

> !is.null(plot_a$theme$aspect.ratio)
[1] TRUE
> !is.null(plot_b$theme$aspect.ratio)
[1] FALSE
2
Gregor Thomas 6 Ноя 2019 в 18:43
Хорошо, это отлично работает, если aspect.ratio равно 1. Однако, если есть фиксированное соотношение сторон, отклоняющееся от 1, isTRUE(the_plot$theme$aspect.ratio == 1), я полагаю, он вернет FALSE (и я просто хочу проверить если есть фиксированное соотношение сторон). Я мог бы попробовать с достаточно маленьким значением, которое, как я полагаю, в большинстве случаев будет выглядеть так: isTRUE(the_plot$theme$aspect.ratio >= .0001)
 – 
yenats
6 Ноя 2019 в 18:08
Так же просто проверить, есть ли соотношение сторон. Просто нужно проверить, существует ли этот элемент списка aspect.ratio.
 – 
Gregor Thomas
6 Ноя 2019 в 18:41
Это решение. Спасибо!
 – 
yenats
6 Ноя 2019 в 19:48

Я не уверен насчет функции, но есть "быстрый и грязный" способ проверить это. если вы развернете подокно графиков, график без фиксированного соотношения сторон будет растягиваться и расширяться, а график с фиксированным соотношением останется той же ширины.

Вы также можете указать масштаб, ширину и высоту графика непосредственно с помощью ggsave, например

ggsave("figure.png", plot = last_plot(),
   scale = 1, width = 20, height = 15, units = "cm",
   dpi = 300)

Не могли бы вы уточнить, как бы вы хотели проверять свои участки?

0
Clarius333 6 Ноя 2019 в 18:04
Я знаю :) Однако мне нужно R, чтобы "знать", имеет ли график фиксированный aspect.ratio или нет, потому что я хочу реализовать ответ (TRUE или FALSE) в более крупном функция.
 – 
yenats
6 Ноя 2019 в 18:11

Ответы на вопросы по теме не являются надежными, потому что сюжет может иметь фиксированное соотношение сторон просто потому, что это делает координата, независимо от настроек темы. Например, любые графики, основанные на geom_sf(), будут иметь фиксированное соотношение сторон. Правильный способ сделать это - запросить grob, который генерирует ggplot.

library(tidyverse)

p_var <- ggplot(iris, aes(Sepal.Length, Sepal.Width)) +
  geom_point()

p_fixed <- p_var + coord_fixed()


# correct approach: query the grob
is_fixed_ratio <- function(plot) {
  g <- ggplotGrob(plot)
  isTRUE(g$respect)
}

# should return false
is_fixed_ratio(p_var)
#> [1] FALSE

# should return true
is_fixed_ratio(p_fixed)
#> [1] TRUE

Напротив, если мы попробуем неправильный подход, все будет работать не так, как ожидалось.

# incorrect approach: rely on a theme setting
is_fixed_ratio_wrong <- function(plot) {
  purrr::map(plot, "aspect.ratio") %>% 
    unlist() %>% 
    is.null() %>% 
    !.
}

# should return false, and does so
is_fixed_ratio_wrong(p_var)
#> [1] FALSE

# should return true, but doesn't
is_fixed_ratio_wrong(p_fixed)
#> [1] FALSE

Это работает также для примера, указанного в вопросе:

plot_a <- ggplot(iris, aes(Sepal.Length, Sepal.Width, color = Species)) +
  geom_point()+
  theme(aspect.ratio = 1)

plot_b <- ggplot(iris, aes(Sepal.Length, Sepal.Width, color = Species)) +
  geom_point()

is_fixed_ratio(plot_a)
#> [1] TRUE

is_fixed_ratio(plot_b)
#> [1] FALSE

Еще один пример:

nc <- sf::st_read(system.file("shape/nc.shp", package = "sf"), quiet = TRUE)
p <- ggplot(nc) +
  geom_sf(aes(fill = AREA))

is_fixed_ratio(p)
#> [1] TRUE

is_fixed_ratio_wrong(p)
#> [1] FALSE
2
Claus Wilke 7 Ноя 2019 в 00:01