簡體   English   中英

如何使用 geom_contour_filled 制作離散漸變色條?

[英]How to make discrete gradient color bar with geom_contour_filled?

我根據這樣的一段代碼繪制了一張地圖:

ggplot(faithfuld, aes(y=eruptions, x=waiting, z=100*density)) +
geom_contour_filled(breaks = c(-Inf,-2., -1.5, -1., -0.5, 0, 0.5, 1, 1.5, 2, 3, 4, 5, 7, 9, 11,Inf))+
theme(plot.title = element_text(size = 10,hjust = 0.5))

這是我的情節目前看起來像: 在此處輸入圖像描述 但是我的老板讓我把這個傳說變成這樣: 在此處輸入圖像描述 或像這樣: 在此處輸入圖像描述 此鏈接 ( https://ggplot2.tidyverse.org/reference/theme.html ) 中的參數只是為圖例提供了微小的更改。 而且我找不到任何可以實現這一目標的論點,ggplot 是否可行? 還是我必須使用其他繪圖包?

創建具有不同間隔寬度且圖例級別之間沒有間距的離散顏色條此問題(答案 4)提供了一種可以像我的老板所需的那樣創建顏色條的方法,但是,我正在使用geom_contour_filled(breaks = c(-Inf,-2., -1.5, -1., -0.5, 0, 0.5, 1, 1.5, 2, 3, 4, 5, 7, 9, 11,Inf))這個論點所以傳說總是出現很多文字: 在此處輸入圖像描述 有什么解決辦法嗎?

編輯

我建議不要使用這個答案——我在這個線程中的第二個答案更合適,但我在這里回答了這個問題,不知道新功能。 我仍然認為它在非常特定的情況下可能很有用,所以我把它留給未來的讀者。 這些函數取自Claus Wilke 在此 github 問題中的評論並對其進行了修改。

我還想再次建議考慮使用 AF7 用戶創建假圖例的功能,因為您可以更自由地設置圖例的樣式。

geom_contour_filled離散化您感興趣的維度,然后固有的連續scale_fill_discrete_gradient失敗。 似乎metR::geom_contour_fill不會產生離散數據,而是保持連續......

為了使該解決方案發揮作用,您需要將變量切割成箱,然后使用因子水平來設置中斷和限制。 這有點hacky...

library(RColorBrewer)
library(metR)
library(ggplot2)

mybreaks <- c(seq(-2,2,0.5), 3:5, seq(7,11,2))
mycols <- rev(colorRampPalette(brewer.pal(11, "Spectral"))(length(mybreaks)-1))
faithfuld$cut_dens <- cut(100*faithfuld$density, mybreaks)

ggplot(faithfuld, aes(eruptions, waiting)) +
  geom_contour_fill(aes(z = as.integer(cut_dens))) +
  scale_fill_discrete_gradient(
    colours = mycols,
    breaks = seq(1, 15, 1), # breaks and limits based on factor levels! 
    limits = c(1,15),
    bins = length(mybreaks)-1,
    labels = mybreaks,
    guide = guide_colourbar(frame.colour = "black", 
                            ticks.colour = "black", # you can also remove the ticks with NA
                            barwidth=20)
  ) +
  theme(legend.position = "bottom")

功能

## very mildly modified from Claus Wilke
discrete_gradient_pal <- function(colours, bins = 5) {
  ramp <- scales::colour_ramp(colours)
  
  function(x) {
    if (length(x) == 0) return(character())
    
    i <- floor(x * bins)
    i <- ifelse(i > bins-1, bins-1, i)
    ramp(i/(bins-1))
  }
}

scale_fill_discrete_gradient <- 
  function(..., colours, bins = 5, 
           na.value = "grey50", 
           guide = "colourbar", 
           aesthetics = "fill", colors)  {
    colours <- if (missing(colours)) 
      colors
    else colours
    continuous_scale(
      aesthetics,
      "discrete_gradient",
      discrete_gradient_pal(colours, bins),
      na.value = na.value,
      guide = guide,
      ...
    )
  } 

我相信這與我之前的答案足以證明第二個答案是正確的。 我回答后者完全否認了 ggplot2 3.3.0 附帶的新比例函數,現在我們開始了,它們讓它變得更容易。 我仍然會保留其他解決方案,因為它可能有助於......非常具體的要求。

我們仍然需要使用metR,因為連續/離散輪廓的問題仍然存在,而metR::geom_contour_fill 可以很好地處理這個問題。

我正在修改scale_fill_fermenter函數,這是在這里使用的好函數,因為它適用於分箱比例。 如果n > max(palette_colors) ,我稍微增強了底層的brewer_pal函數,以便它提供比原始 brewer 顏色更多的功能。

更新您應該使用guide_colorsteps來更改顏色條。 查看有關在小節開始和結束時更長的休息時間的相關討論

library(ggplot2)
library(metR)

mybreaks <- c(seq(-2,2,0.5), 3:5, seq(7,11,2))

ggplot(faithfuld, aes(eruptions, waiting)) +
  metR::geom_contour_fill(aes(z = 100*density)) +
  scale_fill_craftfermenter(
    breaks = mybreaks, 
    palette = "Spectral", 
    limits = c(-2,11),
    guide = guide_colorsteps(
      frame.colour = "black", 
      ticks.colour = "black", # you can also remove the ticks with NA
      barwidth=20)
  ) +
  theme(legend.position = "bottom")
#> Warning: 14 colours used, but Spectral has only 11 - New palette created based
#> on all colors of Spectral

## with uneven steps, better representing the scale 
ggplot(faithfuld, aes(eruptions, waiting)) +
  metR::geom_contour_fill(aes(z = 100*density)) +
  scale_fill_craftfermenter(
    breaks = mybreaks, 
    palette = "Spectral", 
    limits = c(-2,11),
    guide = guide_colorsteps(
      even.steps = FALSE,
      frame.colour = "black", 
      ticks.colour = "black", # you can also remove the ticks with NA
      barwidth=20, )
  ) +
  theme(legend.position = "bottom")
#> Warning: 14 colours used, but Spectral has only 11 - New palette created based
#> on all colors of Spectral

功能修改

craftbrewer_pal <- function (type = "seq", palette = 1, direction = 1) 
{
  pal <- scales:::pal_name(palette, type)
  force(direction)
  function(n) {
    n_max_palette <- RColorBrewer:::maxcolors[names(RColorBrewer:::maxcolors) == palette]
    
    if (n < 3) {
      pal <- suppressWarnings(RColorBrewer::brewer.pal(n, pal))
    } else if (n > n_max_palette){
      rlang::warn(paste(n, "colours used, but", palette, "has only",
                    n_max_palette, "- New palette created based on all colors of", 
                    palette))
      n_palette <- RColorBrewer::brewer.pal(n_max_palette, palette)
      colfunc <- grDevices::colorRampPalette(n_palette)
      pal <- colfunc(n)
    }
    else {
      pal <- RColorBrewer::brewer.pal(n, pal)
    }
    pal <- pal[seq_len(n)]
    if (direction == -1) {
      pal <- rev(pal)
    }
    pal
  }
}

scale_fill_craftfermenter <- function(..., type = "seq", palette = 1, direction = -1, na.value = "grey50", guide = "coloursteps", aesthetics = "fill") {
  type <- match.arg(type, c("seq", "div", "qual"))
  if (type == "qual") {
    warn("Using a discrete colour palette in a binned scale.\n  Consider using type = \"seq\" or type = \"div\" instead")
  }
  binned_scale(aesthetics, "fermenter", ggplot2:::binned_pal(craftbrewer_pal(type, palette, direction)), na.value = na.value, guide = guide, ...)
}
["

set.seed(42)

d <- data.frame(
  x = runif(1000, -20, 20)
)

d$y <- cut(d$x, breaks = c(-Inf, seq(-2, 11, 1), Inf), labels = c(seq(-2, 11, 1), ""))

library(ggplot2)

ggplot(d, aes(y, fill = as.numeric(y))) +
  geom_bar() +
  scale_fill_viridis_b(name = "\u00B0C", limits = c(-2, 11), breaks = seq(-2, 11, 1),
                       guide = guide_bins(axis = FALSE, title.position = "right",
                                          axis.colour = "black",
                                          keywidth = unit(1, "cm"), 
                                          keyheight = unit(1, "cm"))) + 
  theme(legend.position = "bottom")

這是一個舊答案,但metR包可能會用新的離散量表解決這個問題(免責聲明,我是作者 :))。 使用ggplot2::geom_contour_filled() (或metR::geom_contour_fill(aes(fill = stat(level))) )然后使用metR::scale_fill_discretised()

library(ggplot2)

breaks <-  c(-Inf,-2., -1.5, -1., -0.5, 0, 0.5, 1, 1.5, 2, 3, 4, 5, 7, 9, 11,Inf)
ggplot(faithfuld, aes(y=eruptions, x=waiting, z=100*density)) +
  geom_contour_filled(breaks = breaks) +
  metR::scale_fill_discretised()

這會將離散值(例如來自geom_contour_filled()的計算level變量)視為連續值。 請注意,現在色標正確地反映了中斷的不等間距。 也就是說,不僅中斷在指南中的間距不均勻,而且顏色在色標中的間距也不均勻。

如果您想使用類似於屏幕截圖中的調色板,您可以使用ggplot2::scale_fill_gradientn()但使用super參數將其轉換為離散比例。

ggplot(faithfuld, aes(y=eruptions, x=waiting, z=100*density)) +
  geom_contour_filled(breaks = breaks) +
  scale_fill_gradientn(colours = c("#0A2864", "#CCD9FF", "#FFF9CF", "#FEBF00", "#E6281E", "#6C0000"),
    super = metR::ScaleDiscretised)

或任何其他連續規模。

ggplot(faithfuld, aes(y=eruptions, x=waiting, z=100*density)) +
  geom_contour_filled(breaks = breaks) +
  scale_fill_distiller(super = metR::ScaleDiscretised, palette = "Spectral")

然后,繼續進行您認為合適的任何調整。

(這個功能有點新,在我沒有考慮過的情況下可能會出現錯誤。如果您使用它並發現任何問題,請在 github 存儲庫中打開一個問題。我很樂意解決它。)

reprex 包於 2020-11-26 創建 (v0.3.0)

如果我沒記錯的話,ggplot 3.3.0 版可能會解決您的所有問題(如這里所示)。 似乎不再需要metR 包。 雖然這個問題很老,但這可能會對未來的讀者有所幫助。 您可以使用guide_colorsteps函數將“間隔”標簽更改為我們熟悉的標簽。 我使用了 RColorBrewer 包,因為我認為如果您想使用“光譜”調色板(因為它沒有包含足夠的示例顏色),它是最好的選擇,但根據您的調色板需求,它不是必需的(如下所述) .

Spectral.colors <- colorRampPalette(RColorBrewer::brewer.pal(11, "Spectral"))
ggplot(faithfuld, aes(y=eruptions, x=waiting, z=100*density)) +
  geom_contour_filled(breaks = c(-Inf,-2., -1.5, -1., -0.5, 0, 0.5, 1, 1.5, 2, 3, 4, 5, 7, 9, 11,Inf)) + 
  theme(plot.title = element_text(size = 10,hjust = 0.5)) +
  scale_fill_manual(values = rev(Spectral.colors(16)),drop=FALSE) +
  guides(fill = guide_colorsteps(direction = "horizontal",
                                 barwidth = unit(par("pin")[1], "in"))) +
  theme(legend.position = "bottom")

詢問情節

在上面的例子中, scale_fill_manual有兩個輸入, valuesdrop values是一個包含所有已使用顏色的向量(長度為 16,因為中斷的長度為 17),並且drop=FALSE確保將顯示所有中斷(如此所述)。 然后調整guidestheme以制作漂亮的底部水平圖例。 特別是, barwidth是圖例的寬度。 如果沒有給出,它的寬度可能太小了。 par("pin")[1]將以英寸為單位采用當前繪圖寬度,但您可以根據需要指定特定值。

如果您的休息時間足夠小,您可以將scale_fill_manual(values = rev(Spectral.colors(16)),drop=FALSE)替換為scale_fill_brewer(palette = "Spectral",drop=FALSE) 如果您不需要使用“Spectral”並想使用原始的geom_contour_filled調色板(“viridis”),可以用scale_fill_viridis_d(drop = FALSE)替換相同的塊。 最后,如果您想將調色板更改為“viridis”和“Spectral”以外的任何其他調色板,您可以嘗試 R 內置調色板創建功能(例如heat.colors )。 相同的塊可以替換為scale_fill_manual(values = heat.colors(16),drop=FALSE)

如果您需要圖例位於其原始位置(垂直),您的代碼應該是(這里我使用heat.colors只是為了說明):

ggplot(faithfuld, aes(y=eruptions, x=waiting, z=100*density)) +
  geom_contour_filled(breaks = c(-Inf,-2., -1.5, -1., -0.5, 0, 0.5, 1, 1.5, 2, 3, 4, 5, 7, 9, 11,Inf)) + 
  theme(plot.title = element_text(size = 10,hjust = 0.5)) +
  scale_fill_manual(values = heat.colors(16),drop=FALSE) +
  guides(fill = guide_colorsteps(barheight = unit(par("pin")[2], "in")))

vertical_legend_alternative

barwidthbarheight取代, par("pin")[1]par("pin")[2]取代。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM