Как точно наложить два графика

В качестве отправной точки я использую очень полезный код из ответа Кэт на этот вопрос (Как добавить меньше шероховатостей к границам карты, чем к заливке карты), чтобы создать два графика с намерением чтобы один из графиков был наложен поверх другого.

library(magrittr)
library(ggplot2)
#devtools::install_github("xvrdm/ggrough")
library(ggrough)
library(sf)
library(htmltools)    
library(ggiraph)      

trace(ggrough:::parse_rough, edit=TRUE)
#In the popup window, paste this so that parse_rough will use parse_sf for GeomSf.
function (svg, geom) 
{
  rough_els <- list()
  if (geom %in% c("GeomCol", "GeomBar", "GeomTile", 
                  "Background")) {
    rough_els <- append(rough_els, parse_rects(svg))
  }
  if (geom %in% c("GeomArea", "GeomViolin", "GeomSmooth", 
                  "Background")) {
    rough_els <- append(rough_els, parse_areas(svg))
  }
  if (geom %in% c("GeomPoint", "GeomJitter", "GeomDotPlot", 
                  "Background")) {
    rough_els <- append(rough_els, parse_circles(svg))
  }
  if (geom %in% c("GeomLine", "GeomSmooth", "Background")) {
    rough_els <- append(rough_els, parse_lines(svg))
  }
  if (geom %in% c("Background")) {
    rough_els <- append(rough_els, parse_texts(svg))
  }
  if (geom %in% c("GeomSf")) {
    rough_els <- append(rough_els, parse_sf(svg))
  }
  purrr::map(rough_els, ~purrr::list_modify(.x, geom = geom))
}

# Create the function parse_sf.
parse_sf <- function (svg) {
  shape <- "path"
  keys <- NULL
  ggrough:::parse_shape(svg, shape, keys) %>% {
    purrr::map(., 
               ~purrr::list_modify(.x, 
                                   points = .x$d, 
                                   shape = "path"
               ))
  }
}
nc <- sf::st_read(system.file("shape/nc.shp", package = "sf"), quiet = TRUE)

b <- ggplot(nc) + geom_sf(color = "black") + theme_minimal() +
  theme(panel.grid = element_line(color = NA),  # not resized or removed! (keep spacing)
        axis.text = element_text(color = NA))

options <- list(GeomSf = list(fill_style = "hachure", angle = 60, angle_noise = 1,
                              gap_noise = 0, gap = 6, fill_weight = 2, bowing = 5,
                              roughness = 30))

(xx <- get_rough_chart(b, options))  # from your question
fixer <- function(ggr) {          # where ggr is the ggrough graph
  nd <- lapply(1:length(ggr$x$data), function(j) {
    if (!is.null(ggr$x$data[[j]]$lengthAdjust)) { # if a text element (axis label)
      ggr$x$data[[j]]$content <- ""              # remove text, but keep spacing
      ggr$x$data[[j]]                            # return modified data element
    } else {
      ggr$x$data[[j]]                            # not text, return orig data
    }
  })
  ggr$x$data <- nd                               # add mod data to graph
  ggr                                            # return mod graph
}
xx2 <- xx %>% fixer()  # modify the plot, to hide text

(g2 <- ggplot(nc) +
    geom_sf(fill = "transparent", color = "black", linewidth = 2) +
    theme_minimal() +
    theme(plot.background = element_rect(fill = NA, color = "transparent"), # no white background
          panel.background = element_rect(fill = NA, color = "transparent"),
          text = element_text(size = 9)))      # text size to match defaults in ggrough

gg <- girafe(ggobj = g2, width_svg = 7, height_svg = 5)  # h/w default w/ ggrough

browsable(div( # parent div, size matches ggrough's default
  style = css(width = "960px", height = "500px", position = "relative"),
  div(xx2, style = css(display = "block")),                           # ggrough graph
  div(gg, style = css(position = "absolute", top = 0, padding.top = "54.2px", # layer behind
                      width = "610px", height = "500px", z.index = -2))
              )) # size and padding found by trial and error with defaults for graph sizes

График в ответе, похоже, наложен правильно. Однако, когда я запускаю тот же код (в RStudio), я получаю неправильное наложение:

Я также попробовал это в RStudio на другом компьютере, где у меня тоже получилось несовершенное наложение, но в другой степени.

У меня есть два вопроса:

  1. Как правильно наложить графики, не прибегая к методу проб и ошибок?
  2. Как я могу настроить код, чтобы текущий фон переключался на передний план? Другими словами, как я могу сделать так, чтобы черные рамки располагались поверх серых каракулей, а не наоборот? Ближе к концу я попробовал поменять порядок двух div, но это не сработало.
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
56
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Мне не удалось найти четкой информации о том, как ggrough переводится в буквальные размеры.

В этом ответе я использовал соотношение сторон ширина х высота 7 х 5 (дюймов), что является довольно стандартным (browser, knitr и тому подобное). Я не проверял, будут ли эти формулы работать при разных соотношениях сторон.

Поскольку я не мог сформулировать то, что выглядит как обливание грязью потолочного вентилятора для ggrough, я построил сотни графиков, выровнял их, а затем определил, есть ли форум, который я мог бы создать, чтобы точно определить правильные размеры для объекта ggplot.

Когда я говорю о ggplot, я имею в виду пограничный слой, который находится сверху. Когда я говорю о ggrough, я имею в виду слой заливки внизу.

Следующие метрики изменяются в зависимости от высоты и ширины, назначенных ggrough.

  • ширина ggplot
  • верхнее дополнение ggplot
  • размер шрифта ggplot
  • левое дополнение ггро

Поскольку эти элементы разбросаны по разным функциям, я создал пользовательскую функцию, которая опирается на три входных параметра: ширину и высоту ggrough и данные для построения графика.

Значение, которое вы назначаете для ширины и высоты... Я считаю, что они представляют собой дюймы, но я бы не стал предполагать, что 1 = 1 дюйм. В их документации нет ничего, что бы определяло, что представляют собой эти значения, но 1 соответствует примерно 72 пикселям, что является точным, если 1 представляет дюйм.

В функцию записано 2 вызова ошибок. 1) Если высота превышает ширину: это только создает больше бесполезного белого пространства над выступом. 2) Если значения высоты/ширины превышают размер окна браузера. (Если это произойдет, график ggrough потеряет свое соотношение сторон и скроет часть графика - ничего хорошего в этом нет!) Если вы активируете любой из них, вы увидите сообщение в консоли, сообщающее, что произошло.

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

aligner <- function(grw, grh, nc) {   # set rough chart width/height (8, 5, for example), data used in plot
  if (isTRUE(grh > grw)) {
    return(cat("\033[0;37;101mThe height should not exceed the width for this plot.\033[0m\n"))
  }
         # hide the text in the ggrough object 
  fixer <- function(ggr) {                         # where ggr is the ggrough graph
    nd <- lapply(1:length(ggr$x$data), function(j) {
      if (!is.null(ggr$x$data[[j]]$lengthAdjust)) { # if a text element (axis label)
        ggr$x$data[[j]]$content <- ""              # remove text, but keep spacing
        ggr$x$data[[j]]                            # return modified data element
      } else {
        ggr$x$data[[j]]                            # not text, return orig data
      }
    })
    ggr$x$data <- nd                               # add mod data to graph
    ggr                                            # return mod graph
  }
  tpad <- function(grw, grh) {   # calculate the top padding, given ggrough width, height
    delta <- grh - grw + 1
    widD <<- 8 - grw
    widH <- 7 - grh
    45.5 - widD * 10.0 + delta * 35.5 + .5
  }
  #---------- set the variables -----------
  pltW = 7; pltH = 5            # setting aspect ratio; if this changes nothing else may work correctly!
  browsW = 960                  # browser width (default is 960) for htmlwidgets/ used for error checking
  browsH = 500                  # browser height (default is 500) for htmlwidgets/ used for error checking
  
  sfs <- list(-0.325, 6.1)      # slope formula metrics for calculating font size of ggplot object
  sdw <- list(72.5, -3)         # slope formula metrics for calculating width of div
  
  #---------- calculate metrics -----------
  fs <- sfs[[1]] * grw + sfs[[2]]        # calculate the approriate font size for ggplot object
  dw <- sdw[[1]] * grw + sdw[[2]]        # calculate the approriate div width for ggplot object
  
  if (any(pltH/pltW * dw > browsH)) {     # validate aspect ratio by width fits in browser window
    return(cat("\033[0;37;101mWidth of", grw, "is too high to fit. Reduce width & try again.\033[0m\n"))
  } 
  
  tp <- tpad(grw, grh)                   # calculate top padding 
  if (isTRUE(tp < 0)) {                   # validate aspect ratio fits in browser window
    return(cat("\033[0;37;101mWith the given height and width, the plot doesn't fit. Try increasing the height.\033[0m\n"))
  } 
  
  lp <- ifelse(isTRUE(widD > 0), 1 - .5 * widD, 1)  # calculate the left padding
  
  #------------ create graphs ------------
  b <- ggplot(nc) + geom_sf(color = "black") + theme_minimal() +
    theme(panel.grid = element_line(color = NA),  # not resized or removed! (keep spacing)
          axis.text = element_text(color = NA))
  
  options <- list(GeomSf = list(fill_style = "hachure", angle = 60, angle_noise = 1,
                                gap_noise = 0, gap = 6, fill_weight = 2, bowing = 5,
                                roughness = 30))
  xx <- get_rough_chart(b, options, width = grw, height = grh) %>% fixer() # create gg rough graph
  
  g2 <- ggplot(nc) +
    geom_sf(fill = "transparent", color = "black", linewidth = 2) +
    theme_minimal() +
    theme(plot.background = element_rect(fill = NA, color = "transparent"), # no white background
          panel.background = element_rect(fill = NA, color = "transparent"),
          text = element_text(size = rel(fs)))      # text size to match defaults in ggrough
  
  gg <- girafe(ggobj = g2, width_svg = pltW, height_svg = pltH)  # great ggplot graph HTML
  
  #-------- notify user of calcs ---------
  message(paste0("Entered size: ", grw, ", ", grh, "; calculated dims are: ", 
                 "div width ", dw, "; font size ", fs, "; top padding ", tp, 
                 " and left padding ", lp))
  
  #-------- create graph overlay ---------
  browsable(div(                                # parent div, size matches ggrough's default
    style = css(width = "960px", height = paste0(browsH, "pt"), position = "relative"),
    div(xx, style = css(display = "block", padding.left = paste0(lp, "px"))), # ggrough graph
    div(gg, style = css(position = "absolute", top = 0,                       # ggplot graph
                        padding.top = paste0(tp, "px"), 
                        width = paste0(dw, "px"), z.index = -2))
  ))
}

aligner(7, 7, nc)

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

Или в 5, 5:

Или в 9, 7:

Это пример затемнения выходных данных и сообщения об ошибке, которое вы можете увидеть.

Ух ты, огромное спасибо! Это снова было превосходно!

bill999 28.08.2024 00:09

Другие вопросы по теме