Çok sütunlu faset işlevi oluşturma


11

Ben bir boşluk düzeni (kullanılabilir değil ) ile bir faset düzeni sağlar - ancak birden çok sütun üzerinde işlevine facet_multi_col()benzer bir işlev oluşturmaya çalışıyorum . Aşağıdaki son çizimde olduğu gibi (ile oluşturulmuştur ) her modeldeki yüksekliklerin kullanmak istediğim kategorik bir değişkene bağlı olarak değişeceğinden, fasetlerin mutlaka sıralar arasında hizalanmasını istemiyorum.facet_col()ggforcefacet_wrap()grid.arrange()y

ggprotoUzatma kılavuzunu okuduğumda kendimi derinliğimden iyi buluyorum . En iyi yaklaşım verinin karşılık gelen alt kümeleri için sütun kırmak için bir düzen matris geçmek ve bir boşluk parametresi eklemek için facet_col ggforce içinde inşa etmek olduğunu düşünüyorum - sorunun sonuna bakın.

Tatmin edici seçeneklerimin kısa bir açıklaması

Faset yok

library(tidyverse)
library(gapminder)
global_tile <- ggplot(data = gapminder, mapping = aes(x = year, y = fct_rev(country), fill = lifeExp)) +
  geom_tile()
global_tile

resim açıklamasını buraya girin Arsaları kıtalar tarafından yıkmak istiyorum. Böyle uzun bir figür istemiyorum.

facet_wrap ()

global_tile +
  facet_wrap(facets = "continent", scales = "free")

resim açıklamasını buraya girin facet_wrap()kullanılarak, fayans, her kıtada farklı boyutlarda olduğu anlamına gelir bir boşluk bağımsız değişken olmayan coord_equal()bir hata verir

ggforce içinde facet_col ()

library(ggforce)
global_tile +
  facet_col(facets = "continent", scales = "free", space = "free", strip.position = "right") +
  theme(strip.text.y = element_text(angle = 0)) 

resim açıklamasını buraya girin Yandaki şeritler gibi. spaceargümanı tüm döşemeleri aynı boyuta ayarlar. Bir sayfaya sığmayacak kadar uzun.

gridExtra içinde grid.arrange ()

Her kıtanın nereye yerleştirileceğine ilişkin verilere sütun sütunu ekleyin

d <- gapminder %>%
  as_tibble() %>%
  mutate(col = as.numeric(continent), 
         col = ifelse(test = continent == "Europe", yes = 2, no = col),
         col = ifelse(test = continent == "Oceania", yes = 3, no = col))
head(d)
# # A tibble: 6 x 7
#   country     continent  year lifeExp      pop gdpPercap   col
#   <fct>       <fct>     <int>   <dbl>    <int>     <dbl> <dbl>
# 1 Afghanistan Asia       1952    28.8  8425333      779.     3
# 2 Afghanistan Asia       1957    30.3  9240934      821.     3
# 3 Afghanistan Asia       1962    32.0 10267083      853.     3
# 4 Afghanistan Asia       1967    34.0 11537966      836.     3
# 5 Afghanistan Asia       1972    36.1 13079460      740.     3
# 6 Afghanistan Asia       1977    38.4 14880372      786.     3
tail(d)
# # A tibble: 6 x 7
#   country  continent  year lifeExp      pop gdpPercap   col
#   <fct>    <fct>     <int>   <dbl>    <int>     <dbl> <dbl>
# 1 Zimbabwe Africa     1982    60.4  7636524      789.     1
# 2 Zimbabwe Africa     1987    62.4  9216418      706.     1
# 3 Zimbabwe Africa     1992    60.4 10704340      693.     1
# 4 Zimbabwe Africa     1997    46.8 11404948      792.     1
# 5 Zimbabwe Africa     2002    40.0 11926563      672.     1
# 6 Zimbabwe Africa     2007    43.5 12311143      470.     1

facet_col()Her sütun için çizim için kullanın

g <- list()
for(i in unique(d$col)){
  g[[i]] <- d %>%
    filter(col == i) %>%
    ggplot(mapping = aes(x = year, y = fct_rev(country), fill = lifeExp)) +
    geom_tile() +
    facet_col(facets = "continent", scales = "free_y", space = "free", strip.position = "right") +
    theme(strip.text.y = element_text(angle = 0)) +
    # aviod legends in every column
    guides(fill = FALSE) +
    labs(x = "", y = "")
}

Kullanarak bir açıklama oluşturmak get_legend()içindecowplot

library(cowplot)
gg <- ggplot(data = d, mapping = aes(x = year, y = country, fill = lifeExp)) +
  geom_tile()
leg <- get_legend(gg)

Her sütundaki ülke sayısına göre yüksekliklerle bir düzen matrisi oluşturun.

m <- 
  d %>%
  group_by(col) %>%
  summarise(row = n_distinct(country)) %>%
  rowwise() %>%
  mutate(row = paste(1:row, collapse = ",")) %>%
  separate_rows(row) %>%
  mutate(row = as.numeric(row), 
         col = col, 
         p = col) %>% 
  xtabs(formula = p ~ row + col) %>%
  cbind(max(d$col) + 1) %>%
  ifelse(. == 0, NA, .)

head(m)
#   1 2 3  
# 1 1 2 3 4
# 2 1 2 3 4
# 3 1 2 3 4
# 4 1 2 3 4
# 5 1 2 3 4
# 6 1 2 3 4

tail(m)
#     1 2  3  
# 50  1 2 NA 4
# 51  1 2 NA 4
# 52  1 2 NA 4
# 53 NA 2 NA 4
# 54 NA 2 NA 4
# 55 NA 2 NA 4

Getir gve legbirlikte kullanılarak grid.arrange()içindegridExtra

library(gridExtra)
grid.arrange(g[[1]], g[[2]], g[[3]], leg, layout_matrix = m, widths=c(0.32, 0.32, 0.32, 0.06))

resim açıklamasını buraya girin Neredeyse peşinde olduğum şey bu, ama memnun değilim a) farklı sütunlardaki fayanslar en uzun ülke uzunluğu ve kıta isimleri eşit olmadığı için farklı genişliklere sahip ve b) her birinin değiştirilmesi gereken çok fazla kod var zaman böyle bir komplo yapmak istiyorum - diğer verilerle fasetleri kıtalardan ziyade bölgelere göre düzenlemek istiyorum, örneğin "Batı Avrupa" ya da ülke sayısı değişiyor - gapminderverilerde Orta Asya ülkeleri yok .

Bir facet_multi_cols () işlevi oluşturma işleminde ilerleme

Bir düzen matrisini, matrisin her bir yüze atıfta bulunduğu bir faset fonksiyonuna geçirmek istiyorum ve fonksiyon daha sonra her paneldeki boşluk sayısına göre yükseklikleri anlayabilir. Yukarıdaki örnek için matris şöyle olacaktır:

my_layout <- matrix(c(1, NA, 2, 3, 4, 5), nrow = 2)
my_layout
#      [,1] [,2] [,3]
# [1,]    1    2    4
# [2,]   NA    3    5

Yukarıda belirtildiği gibi, ben facet_col()bir facet_multi_col()işlev denemek ve oluşturmak için kod adapte edilmiştir . Yukarıdaki layoutgibi matris sağlamak my_layoutiçin facetsargümana verilen değişkenin dördüncü ve beşinci seviyesinin üçüncü sütunda çizildiği fikrini ekledim .

facet_multi_col <- function(facets, layout, scales = "fixed", space = "fixed",
                      shrink = TRUE, labeller = "label_value",
                      drop = TRUE, strip.position = 'top') {
  # add space argument as in facet_col
  space <- match.arg(space, c('free', 'fixed'))
  facet <- facet_wrap(facets, col = col, dir = dir, scales = scales, shrink = shrink, labeller = labeller, drop = drop, strip.position = strip.position)
  params <- facet$params
  params <- facet$layout

  params$space_free <- space == 'free'
  ggproto(NULL, FacetMultiCols, shrink = shrink, params = params)
}

FacetMultiCols <- ggproto('FacetMultiCols', FacetWrap,
  # from FacetCols to allow for space argument to work
  draw_panels = function(self, panels, layout, x_scales, y_scales, ranges, coord, data, theme, params) {
    combined <- ggproto_parent(FacetWrap, self)$draw_panels(panels, layout, x_scales, y_scales, ranges, coord, data, theme, params)
    if (params$space_free) {
      widths <- vapply(layout$PANEL, function(i) diff(ranges[[i]]$x.range), numeric(1))
      panel_widths <- unit(widths, "null")
      combined$widths[panel_cols(combined)$l] <- panel_widths
    }
    combined
  }
  # adapt FacetWrap layout to set position on panels following the matrix given to layout in facet_multi_col().
  compute_layout = function(self, panels, layout, x_scales, y_scales, ranges, coord, data, theme, params) {
    layout <- ggproto_parent(FacetWrap, self)$compute_layout(panels, layout, x_scales, y_scales, ranges, coord, data, theme, params)
    # ???
)

Sanırım compute_layoutrol için bir şeyler yazmam gerekiyor, ama bunun nasıl yapılacağını anlamaya çalışıyorum.


Bunun yerine, her kıta için bir parsel listesi oluşturmayı ve bunları börülce veya patchwork gibi paketlerden biriyle hizalamayı denediniz mi? Bir ggproto oluşturmaktan daha kolay olabilir
camille

@camille grid.arrangeYukarıdaki örnekte ... farklı bir şey ifade etmedikçe yaptım ? Her sütunda farklı etiket uzunlukları ile aynı sorunları olacağını düşünüyorum?
gjabel

Buna benzer bir şey hayal ediyorum, ancak bu düzen paketleri hizalamadan daha iyi yardımcı olabilir grid.arrange. Bu gerçekten uzun bir gönderi, bu yüzden denediğiniz her şeyi takip etmek zor. Biraz hacky, ama etiketler için tek aralıklı bir yazı tipine daha yakın bir tek boşluk / yakın deneyebilirsiniz, böylece uzunlukları daha tahmin edilebilir. Daha sonra, metnin aynı uzunluğa daha yakın olduğundan emin olmak için etiketleri boş boşluklarla doldurabilirsiniz.
camille

Yanıtlar:


4

feragat

Hiç geliştirmedim facet, ama soruyu ilginç ve yeterince zor buldum, bu yüzden denedim. Henüz mükemmel değildir ve planınıza bağlı olarak ortaya çıkabilecek tüm inceliklerle test edilmemiştir, ancak üzerinde çalışabileceğiniz ilk taslaktır.

Fikir

facet_wrappanelleri bir tabloya yerleştirir ve her satır panelin tamamen kapladığı belirli bir yüksekliğe sahiptir. gtable_add_grobdiyor:

Gtable modelinde, grobs her zaman tüm tablo hücresini doldurur. Özel gerekçe istiyorsanız, grob boyutunu mutlak birimler olarak tanımlamanız veya daha sonra grob yerine gtable'a eklenebilecek başka bir gtable'a koymanız gerekebilir.

Bu olabilir ilginç bir çözüm olabilir. Ancak, bunu nasıl yapacağımdan emin değildim. Böylece farklı bir yaklaşım izledim:

  1. Geçirilen düzen parametresini temel alan özel bir düzen oluşturun
  2. Izin facet_wrapdüzene wrt tüm panelleri işlemek
  3. gtable_filterPaneli eksenleri ve şeritleri dahil tutmak için kullanın
  4. Bir düzen matrisi oluşturun. 2 yaklaşım denedim: minimum sayıda satır kullanmak ve yükseklik farklarıyla oynamak. Ve sadece y ekseninde keneler olduğu kadar yaklaşık satır eklemek. Her ikisi de benzer şekilde çalışır, ikincisi daha temiz kod üretir, bu yüzden bunu kullanırım.
  5. gridExtra::arrangeGrobPanelleri geçirilen tasarıma ve oluşturulan düzen matrisine göre düzenlemek için kullanın

Sonuçlar

Tam kod biraz uzun, ancak aşağıda bulunabilir. İşte bazı grafikler:

my_layout1 <- matrix(c(1, NA, 2, 3, 4, 5), nrow = 2)
my_layout2 <- matrix(c(1, 2, 3, 4, 5, NA), ncol = 2)

## Ex1
global_tile + facet_multi_col("continent", my_layout1, scales = "free_y", 
                              space = "free", strip.position = "top")

## Ex 2
global_tile + facet_multi_col("continent", my_layout1, scales = "free_y", 
                              space = "free", strip.position = "right")

## Ex 3 - shows that we need a minimum space for any plot 
global_tile + facet_multi_col("continent", my_layout1, scales = "free_y", 
                              space = "free", strip.position = "top", min_prop = 0)

## Ex 4
global_tile + facet_multi_col("continent", my_layout1, scales = "free_y", 
                              space = "fixed", strip.position = "right")

## Ex 5
global_tile + facet_multi_col("continent", my_layout2, scales = "free_y", 
                              space = "free")

Eski 1 Eski 2 Eski 3 Eski 4 Eski 5örnek 1 ÖRNEK 2 ÖRNEK 3 Örnek 4 Örnek 5

Kısıtlamalar

Kod kusursuz olmaktan uzaktır. Zaten gördüğüm bazı sorunlar:

  • (Sessizce) tasarımdaki her bir sütunun NA olmayan bir değerle başladığını varsayıyoruz (genel olarak üretken bir kod için, geçirilen mizanpajın dikkatlice kontrol edilmesi gerekiyor (boyutlar uygun mu? Paneller kadar giriş var mı? Vb.)
  • Çok küçük paneller iyi iş görmüyor, bu yüzden şeritlerin konumuna bağlı olarak yükseklik için minimum bir değer eklemek zorunda kaldım
  • Eksenlerin veya şeritlerin taşınmasının veya eklenmesinin etkisi henüz test edilmemiştir.

Kod: kene başına bir satır

## get strip and axis of a given panel
## Assumptions:
## - axis are adjacent to the panel, that is exactly +1/-1 positions to the t/b/l/r ...
## - ... unless there is a strip then it is +2/-2 
get_whole_panel <- function(panel_name,
                            table_layout) {
  target <- table_layout$layout %>%
    dplyr::filter(name == panel_name) %>%
    dplyr::select(row = t, col = l)
  stopifnot(NROW(target) == 1)
  pos <- unlist(target)
  dirs <- list(t = c(-1, 0),
               b = c(1, 0),
               l = c(0, -1),
               r = c(0, 1))
  filter_elems <- function(dir, 
                           type = c("axis", "strip")) {
    type <- match.arg(type)
    new_pos <- pos + dir
    res <- table_layout$layout %>%
      dplyr::filter(grepl(type, name),
                    l == new_pos["col"],
                    t == new_pos["row"]) %>%
      dplyr::pull(name)
    if (length(res)) res else NA
  }
  strip <- purrr::map_chr(dirs, filter_elems, type = "strip")
  strip <- strip[!is.na(strip)]
  dirs[[names(strip)]] <- 2 * dirs[[names(strip)]]
  axes  <- purrr::map_chr(dirs, filter_elems, type = "axis")
  gtable::gtable_filter(table_layout, paste(c(panel_name, axes, strip), collapse = "|"))
}


facet_multi_col <- function(facets, layout, scales = "fixed", space = "fixed",
                            shrink = TRUE, labeller = "label_value",
                            drop = TRUE, strip.position = "top", 
                            min_prop = ifelse(strip.position %in% c("top", "bottom"), 
                                              0.12, 0.1)) {
  space <- match.arg(space, c("free", "fixed"))
  if (space == "free") {
    ## if we ask for free space we need scales everywhere, so make sure they are included
    scales <- "free"
  }
  facet <- facet_wrap(facets, ncol = 1, scales = scales, shrink = shrink, 
                      labeller = labeller, drop = drop, strip.position = strip.position)
  params <- facet$params
  params$space_free <- space == "free"
  params$layout <- layout
  params$parent <- facet
  params$min_prop <- min_prop
  ggproto(NULL, FacetMultiCol, shrink = shrink, params = params)
}



render <- function(self, panels, layout, 
                   x_scales, y_scales, ranges, 
                   coord, data, theme, params) {
  combined <- ggproto_parent(FacetWrap, self)$draw_panels(panels, layout, 
                                                          x_scales, y_scales, ranges, 
                                                          coord, data, theme, params)
  if (params$space_free) {
    panel_names <- combined$layout$name
    panels <- lapply(panel_names[grepl("panel", panel_names)],
                     get_whole_panel,
                     table_layout = combined)

    ## remove zeroGrob panels
    zG <- sapply(panels, function(tg) all(sapply(tg$grobs, ggplot2:::is.zero)))
    panels <- panels[!zG]
    ## calculate height for each panel
    heights <- matrix(NA, NROW(params$layout), NCOL(params$layout))
    ## store the rounded range in the matrix cell corresponding to its position
    ## allow for a minimum space in dependence of the overall number of rows to
    ## render small panels well

    heights[as.matrix(layout[, c("ROW", "COL")])] <- vapply(ranges, function(r) 
      round(diff(r$y.range), 0), numeric(1))

    ## 12% should be the minimum height used by any panel if strip is on top otherwise 10%
    ## these values are empirical and can be changed
    min_height <- round(params$min_prop * max(colSums(heights, TRUE)), 0)
    heights[heights < min_height] <- min_height
    idx <- c(heights)
    idx[!is.na(idx)] <- seq_along(idx[!is.na(idx)])
    len_out <- max(colSums(heights, TRUE))
    i <- 0
    layout_matrix <- apply(heights, 2, function(col) {
      res <- unlist(lapply(col, function(n) {
        i <<- i + 1
        mark <- idx[i]
        if (is.na(n)) {
          NA
        } else {
          rep(mark, n)
        }
      }))
      len <- length(res)
      if (len < len_out) {
        res <- c(res, rep(NA, len_out - len))
      }
      res
    })

    ## set width of left axis to maximum width to align plots
    max_width <- max(do.call(grid::unit.c, lapply(panels, function(gt) gt$widths[1])))
    panels <- lapply(panels, function(p) {
      p$widths[1] <- max_width
      p
    })

    combined <- gridExtra::arrangeGrob(grobs = panels,
                            layout_matrix = layout_matrix,
                            as.table = FALSE)
    ## add name, such that find_panel can find the plotting area
    combined$layout$name <- paste("panel_", layout$LAB)
  }
  combined
}

layout <- function(data, params) {
  parent_layout <- params$parent$compute_layout(data, params)
  msg <- paste0("invalid ",
                sQuote("layout"),
                ". Falling back to ",
                sQuote("facet_wrap"),
                " layout")
  if (is.null(params$layout) ||
      !is.matrix(params$layout)) {
    warning(msg)
    parent_layout
  } else {
    ## smash layout into vector and remove NAs all done by sort
    layout <- params$layout
    panel_numbers <- sort(layout)
    if (!isTRUE(all.equal(sort(as.numeric(as.character(parent_layout$PANEL))),
                          panel_numbers))) {
      warning(msg)
      parent_layout
    } else {
      ## all good
      indices <- cbind(ROW = c(row(layout)),
                       COL = c(col(layout)),
                       PANEL = c(layout))
      indices <- indices[!is.na(indices[, "PANEL"]), ]
      ## delete row and col number from parent layout
      parent_layout$ROW <- parent_layout$COL <- NULL
      new_layout <- merge(parent_layout, 
                          indices,
                          by = "PANEL") %>%
        dplyr::arrange(PANEL)
      new_layout$PANEL <- factor(new_layout$PANEL)
      labs <- new_layout %>%
        dplyr::select(-PANEL,
                      -SCALE_X,
                      -SCALE_Y,
                      -ROW,
                      -COL) %>%
        dplyr::mutate(sep = "_") %>%
        do.call(paste, .)
      new_layout$LAB <- labs
      new_layout


    }
  }
}

FacetMultiCol <- ggproto("FacetMultiCol", FacetWrap,
                         compute_layout = layout,
                         draw_panels    = render)

Kod: farklı yükseklikte satırlar

## get strip and axis of a given panel
## Assumptions:
## - axis are adjacent to the panel, that is exactly +1/-1 positions to the t/b/l/r ...
## - ... unless there is a strip then it is +2/-2 
get_whole_panel <- function(panel_name,
                            table_layout) {
  target <- table_layout$layout %>%
    dplyr::filter(name == panel_name) %>%
    dplyr::select(row = t, col = l)
  stopifnot(NROW(target) == 1)
  pos <- unlist(target)
  dirs <- list(t = c(-1, 0),
               b = c(1, 0),
               l = c(0, -1),
               r = c(0, 1))
  filter_elems <- function(dir, 
                           type = c("axis", "strip")) {
    type <- match.arg(type)
    new_pos <- pos + dir
    res <- table_layout$layout %>%
      dplyr::filter(grepl(type, name),
                    l == new_pos["col"],
                    t == new_pos["row"]) %>%
      dplyr::pull(name)
    if (length(res)) res else NA
  }
  strip <- purrr::map_chr(dirs, filter_elems, type = "strip")
  strip <- strip[!is.na(strip)]
  dirs[[names(strip)]] <- 2 * dirs[[names(strip)]]
  axes  <- purrr::map_chr(dirs, filter_elems, type = "axis")
  gtable::gtable_filter(table_layout, paste(c(panel_name, axes, strip), collapse = "|"))
}


facet_multi_col <- function(facets, layout, scales = "fixed", space = "fixed",
                            shrink = TRUE, labeller = "label_value",
                            drop = TRUE, strip.position = "top") {
  space <- match.arg(space, c("free", "fixed"))
  if (space == "free") {
    ## if we ask for free space we need scales everywhere, so make sure they are included
    scales <- "free"
  }
  facet <- facet_wrap(facets, ncol = 1, scales = scales, shrink = shrink, 
                      labeller = labeller, drop = drop, strip.position = strip.position)
  params <- facet$params
  params$space_free <- space == "free"
  params$layout <- layout
  params$parent <- facet
  ggproto(NULL, FacetMultiCol, shrink = shrink, params = params)
}



render <- function(self, panels, layout, 
                   x_scales, y_scales, ranges, 
                   coord, data, theme, params) {
  combined <- ggproto_parent(FacetWrap, self)$draw_panels(panels, layout, 
                                                          x_scales, y_scales, ranges, 
                                                          coord, data, theme, params)
  if (params$space_free) {
    panel_names <- combined$layout$name
    panels <- lapply(panel_names[grepl("panel", panel_names)],
                     get_whole_panel,
                     table_layout = combined)

    ## remove zeroGrob panels
    zG <- sapply(panels, function(tg) all(sapply(tg$grobs, ggplot2:::is.zero)))
    panels <- panels[!zG]

    ## calculate height for each panel
    heights <- matrix(NA, NROW(params$layout), NCOL(params$layout))
    ## need to add a minimum height as otherwise the space is too narrow
    heights[as.matrix(layout[, c("ROW", "COL")])] <- vapply(layout$PANEL, function(i) 
      max(diff(ranges[[i]]$y.range), 8), numeric(1))
    heights_cum <- sort(unique(unlist(apply(heights, 2, 
                                            function(col) cumsum(col[!is.na(col)])))))
    heights_units <- unit(c(heights_cum[1], diff(heights_cum)), "null")

    ## set width of left axis to maximum width to align plots
    max_width <- max(do.call(grid::unit.c, lapply(panels, function(gt) gt$widths[1])))
    panels <- lapply(panels, function(p) {
      p$widths[1] <- max_width
      p
    })

    mark <- 0

    ## create layout matrix
    layout_matrix <- apply(heights, 2, function(h) {
      idx <- match(cumsum(h),
              cumsum(c(heights_units)))
      idx <- idx[!is.na(idx)]
      res <- unlist(purrr::imap(idx, function(len_out, pos) {
        mark <<- mark + 1
        offset <- if (pos != 1) idx[pos - 1] else 0
          rep(mark, len_out - offset)
      }))
      len_out <- length(res)
      if (len_out < length(heights_units)) {
        res <- c(res, rep(NA, length(heights_units) - len_out)) 
      }
      res
    }) 

    combined <- gridExtra::arrangeGrob(grobs = panels,
                                layout_matrix = layout_matrix,
                                heights = heights_units,
                                as.table = FALSE)
    ## add name, such that find_panel can find the plotting area
    combined$layout$name <- paste("panel_", layout$LAB)
  }
  combined
}

layout <- function(data, params) {
  parent_layout <- params$parent$compute_layout(data, params)
  msg <- paste0("invalid ",
                sQuote("layout"),
                ". Falling back to ",
                sQuote("facet_wrap"),
                " layout")
  if (is.null(params$layout) ||
      !is.matrix(params$layout)) {
    warning(msg)
    parent_layout
  } else {
    ## smash layout into vector and remove NAs all done by sort
    layout <- params$layout
    panel_numbers <- sort(layout)
    if (!isTRUE(all.equal(sort(as.numeric(as.character(parent_layout$PANEL))),
                          panel_numbers))) {
      warning(msg)
      parent_layout
    } else {
      ## all good
      indices <- cbind(ROW = c(row(layout)),
                       COL = c(col(layout)),
                       PANEL = c(layout))
      indices <- indices[!is.na(indices[, "PANEL"]), ]
      ## delete row and col number from parent layout
      parent_layout$ROW <- parent_layout$COL <- NULL
      new_layout <- merge(parent_layout, 
                          indices,
                          by = "PANEL") %>%
        dplyr::arrange(PANEL)
      new_layout$PANEL <- factor(new_layout$PANEL)
      labs <- new_layout %>%
        dplyr::select(-PANEL,
                      -SCALE_X,
                      -SCALE_Y,
                      -ROW,
                      -COL) %>%
        dplyr::mutate(sep = "_") %>%
        do.call(paste, .)
      new_layout$LAB <- labs
      new_layout


    }
  }
}

FacetMultiCol <- ggproto("FacetMultiCol", FacetWrap,
                         compute_layout = layout,
                         draw_panels    = render)

Bunun için çok teşekkürler. i diğer bazı veriler üzerinde denedim - bölgeler, kıtalar yerine (bu soruda bahsedilen) ... ben kodu buraya koymak ... gist.github.com/gjabel/3e4fb31214b5932aa0978dc6d3258dc1 ... gerçekten atar anlayamadığım garip davranış?
gjabel

Verileri paylaşabilir misiniz? Ben
özüne

veriler wpp2019 paketinde ..
CRAN'da

ah özür dilerim bir deneyin.
thothal

1
Temelde düzen hata, Bulunan gerekir , PANEL göre sıralanabilir aksi takdirde iş olmaz. senin örnek şimdi iyi render yapmak.
thothal

1

Yorumlarda önerildiği gibi, bir cowplot ve patchwork kombinasyonu sizi oldukça uzağa götürebilir. Aşağıdaki çözümüme bakın.

Temel fikir:

  • önce satır sayısına göre bir ölçeklendirme faktörü hesaplamak için,
  • sonra bir dizi tek sütun ızgara yapın, burada parsellerin yüksekliğini kalibre edilmiş ölçeklendirme faktörü ile sınırlamak için boş grafikler kullanıyorum. (ve efsaneleri kaldırın)
  • sonra bunları bir tabloya ekliyorum ve bir açıklama da ekliyorum.
  • başlangıçta, dolum ölçeği için bir maksimum hesaplıyorum.
library(tidyverse)
library(gapminder)
library(patchwork)
max_life <- max(gapminder$lifeExp)
generate_plot <- function(data, title){
  ggplot(data = data, mapping = aes(x = year, y = fct_rev(country), fill = lifeExp)) +
    geom_tile()+
    scale_fill_continuous(limits = c(0, max_life)) +
    ggtitle(title)
}
scale_plot <- function(plot, ratio){
  plot + theme(legend.position="none") + 
    plot_spacer() + 
    plot_layout(ncol = 1,
                heights = c(
                  ratio,
                  1-ratio
                )
    )
}
df <- gapminder %>% 
  group_by(continent) %>% 
  nest() %>% 
  ungroup() %>% 
  arrange(continent) %>% 
  mutate(
    rows = map_dbl(data, nrow),
    rel_height = (rows/max(rows)),
    plot = map2(
      data,
      continent,
      generate_plot
    ),
    spaced_plot = map2(
      plot,
      rel_height,
      scale_plot
        )
  )
wrap_plots(df$spaced_plot) + cowplot::get_legend(df$plot[[1]])

2019-11-06 tarihinde reprex paketi tarafından oluşturuldu (v0.3.0)

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.