[英]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
有兩個輸入, values
和drop
。 values
是一個包含所有已使用顏色的向量(長度為 16,因為中斷的長度為 17),並且drop=FALSE
確保將顯示所有中斷(如此處所述)。 然后調整guides
和theme
以制作漂亮的底部水平圖例。 特別是, 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")))
barwidth
被barheight
取代, par("pin")[1]
被par("pin")[2]
取代。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.