使用 highcharter 自定义箱线图的颜色

Customize colors for boxplot with highcharter

我在 highcharter 上有箱线图,我想自定义

这是我的代码

df = data.frame(cbind(categ = rep(c('a','b','c','d')),value = rnorm(1000)))

hcboxplot(var = df$categ, x = as.numeric(df$value)) %>% 
  hc_chart(type = "column")  %>% 
  hc_colors(c("#203d7d","#a0a0ed","#203d7e","#a0a0ad")) 

hc_colors 仅当我将 var2 而不是 var 时才有效,但随后箱线图缩小了...

由于还没有highcharter答案,我至少给你一个基本的解决方案。

首先,您对数据框的定义有些缺陷,宁可:

dat <- data.frame(categ=c('a','b','c','d'), value=rnorm(1000))

现在,使用 boxplot 非常简单。 border 选项为您的边框着色。使用选项 col,您还可以为填充着色。

boxplot(value ~ categ, dat, border=c("#203d7d","#a0a0ed","#203d7e","#a0a0ad"), pars=list(outpch=16))

给予

注意:请参阅 了解更多自定义设置。

API 样式 fillColor: https://api.highcharts.com/highcharts/series.boxplot.fillColor

对于"Border color"https://api.highcharts.com/highcharts/series.boxplot.color

如何设置样式和定义点的纯 JavaScript 示例:https://jsfiddle.net/BlackLabel/6tud3fgx

和R代码:

library(highcharter)
df = data.frame(cbind(categ = rep(c('a','b','c','d', 'e')),value = rnorm(1000)))
hcboxplot(var = df$categ, x = as.numeric(df$value)) %>% 
  hc_chart(type = "column", events = list(
    load = JS("function() {
        var chart = this;
        chart.series[0].points[2].update({
          color: 'red'
        })
        chart.series[0].points[4].update({
          x: 4,
          low: 600,
          q1: 700,
          median: 800,
          q3: 900,
          high: 1000,
          color: 'orange'
        })
      }")
  ))  %>% 
  hc_plotOptions(boxplot = list(
    fillColor = '#F0F0E0',
    lineWidth = 2,
    medianColor = '#0C5DA5',
    medianWidth = 3,
    stemColor = '#A63400',
    stemDashStyle = 'dot',
    stemWidth = 1,
    whiskerColor = '#3D9200',
    whiskerLength = '20%',
    whiskerWidth = 3,
    color = 'black'
  ))  %>% 
  hc_colors(c("#203d7d","#a0a0ed","#203d7e","#a0a0ad"))

我做了几个函数来用高图和箱线图做一些事情。它会让您为每个箱线图着色并相应地填充它,然后根据 Highcharts API 注入新的图形参数,如果您愿意的话。

查看:

## Boxplots Data and names, note the data index (0,1,2) is the first number in the datum
series<- list(
  list(
    name="a",
    data=list(c(0,1,2,3,4,5))
  ),
  list(
    name="b",
    data=list(c(1,2,3,4,5,6))

  ),
  list(
    name="c",
    data=list(c(2,3,4,5,6,7))

  )
)

# Graphical attribute to be set: fillColor.
# Make the colors for the box fill and then also the box lines (make them match so it looks pretty)
cols<- viridisLite::viridis(n= length(series2), alpha = 0.5) # Keeping alpha in here! (for box fill)
cols2<- substr(cols, 0,7) # no alpha, pure hex truth, for box lines 

gen_key_vector<-function(variable, num_times){
  return(rep(variable, num_times))
} 

kv<- gen_key_vector(variable = "fillColor", length(series)) 

# Make a function to put stuff in the 'series' list, requires seq_along to be used since x is the list/vector index tracker

add_variable_to_series_list<- function(x, series_list, key_vector, value_vector){
  base::stopifnot(length(key_vector) == length(value_vector))
  base::stopifnot(length(series_list) == length(key_vector))
  series_list[[x]][length(series_list[[x]])+1]<- value_vector[x]
  names(series_list[[x]])[length(series_list[[x]])]<- key_vector[x]
  return(series_list[[x]])
}
## Put the extra stuff in the 'series' list
series2<- lapply(seq_along(series), function(x){ add_variable_to_series_list(x = x, series_list = series, key_vector = kv, value_vector = cols) })


hc<- highcharter::highchart() %>%
  highcharter::hc_chart(type="boxplot", inverted=FALSE) %>%
  highcharter::hc_title(text="This is a title") %>%
  highcharter::hc_legend(enabled=FALSE) %>%
  highcharter::hc_xAxis(type="category", categories=c("a", "b", "c"), title=list(text="Some x-axis title")) %>%
  highcharter::hc_add_series_list(series2) %>%
  hc_plotOptions(series = list(
    marker = list(
      symbol = "circle"
    ),
    grouping=FALSE
  )) %>%
  highcharter::hc_colors(cols2) %>%
  highcharter::hc_exporting(enabled=TRUE)
hc

这可能可以调整为使用简单的数据框,但我认为它会立即为您提供您想要的东西,而无需做太多额外的工作。此外,也许可以查看 list_parselist_parse2' fromhighcharter...it could probably help with building out theseries` 对象。我仍然需要查看它。

编辑:

我扩展了该示例,使其适用于常规 DF。根据一些后续问题,颜色是使用 make_highchart_boxplot_with_colored_factors 函数内的 viridis 调色板设置的。如果你想允许你自己的调色板和颜色,你可以公开这些参数并将它们作为参数包含在函数调用中。扩展示例借鉴了如何从 highcharter 库中添加离群值(尽管是以一种 hacky 的方式),然后从头开始构建其他所有内容。希望这有助于澄清我之前的回答。请注意,我可能还可以清理 if 条件以使其更简短一些,但出于说明目的,我将其保持冗长。

双重编辑:您现在可以为因子变量的每个水平指定一个颜色向量

library(highcharter)
library(magrittr)
library(viridisLite)

df = data.frame(cbind(categ = rep(c('a','b','c','d')),value = rnorm(1000)))
df$value<- base::as.numeric(df$value)


add_variable_to_series_list<- function(x, series_list, key_vector, value_vector){
  base::stopifnot(length(key_vector) == length(value_vector))
  base::stopifnot(length(series_list) == length(key_vector))
  series_list[[x]][length(series_list[[x]])+1]<- value_vector[x]
  names(series_list[[x]])[length(series_list[[x]])]<- key_vector[x]
  return(series_list[[x]])
}


# From highcharter github pages:
hc_add_series_bwpout = function(hc, value, by, ...) {
  z = lapply(levels(by), function(x) {
    bpstats = boxplot.stats(value[by == x])$stats
    outliers = c()
    for (y in na.exclude(value[by == x])) {
      if ((y < bpstats[1]) | (y > bpstats[5]))
        outliers = c(outliers, list(which(levels(by)==x)-1, y))
    }
    outliers
  })
  hc %>%
    hc_add_series(data = z, type="scatter", ...)
}


gen_key_vector<-function(variable, num_times){
  return(rep(variable, num_times))
} 
gen_boxplot_series_from_df<- function(value, by,...){
  value<- base::as.numeric(value)
  by<- base::as.factor(by)
  box_names<- levels(by)
  z=lapply(box_names, function(x) {
    boxplot.stats(value[by==x])$stats
  })
  tmp<- lapply(seq_along(z), function(x){
    var_name_list<- list(box_names[x])
    #tmp0<- list(names(df)[x])
    names(var_name_list)<- "name"
    index<- x-1
    tmp<- list(c(index,  z[[x]]))
    tmp<- list(tmp)
    names(tmp)<- "data"
    tmp_out<- c(var_name_list, tmp)
    #tmp<- list(tmp)
    return(tmp_out)

  })
  return(tmp)
}
# Usage: 
#series<- gen_boxplot_series_from_df(value = df$total_value, by=df$asset_class)


## Boxplot function:
make_highchart_boxplot_with_colored_factors<- function(value, by, chart_title="Boxplots",
                                                       chart_x_axis_label="Values", show_outliers=FALSE,
                                                       boxcolors=NULL, box_line_colors=NULL){
  by<- as.factor(by)
  box_names_to_use<- levels(by)
  series<- gen_boxplot_series_from_df(value = value, by=by)
  if(is.null(boxcolors)){
    cols<- viridisLite::viridis(n= length(series), alpha = 0.5) # Keeping alpha in here! (COLORS FOR BOXES ARE SET HERE)
  } else {
    cols<- boxcolors
  }
  if(is.null(box_line_colors)){
    if(base::nchar(cols[[1]])==9){
      cols2<- substr(cols, 0,7) # no alpha, pure hex truth, for box lines 
    } else {
      cols2<- cols
    }

  } else {
    cols2<- box_line_colors
  }

  # Injecting value 'fillColor' into series list
  kv<- gen_key_vector(variable = "fillColor", length(series)) 
  series2<- lapply(seq_along(series), function(x){ add_variable_to_series_list(x = x, series_list = series, key_vector = kv, value_vector = cols) })

  if(show_outliers == TRUE){
    hc<- highcharter::highchart() %>%
      highcharter::hc_chart(type="boxplot", inverted=FALSE) %>%
      highcharter::hc_title(text=chart_title) %>%
      highcharter::hc_legend(enabled=FALSE) %>%
      highcharter::hc_xAxis(type="category", categories=box_names_to_use, title=list(text=chart_x_axis_label)) %>%
      highcharter::hc_add_series_list(series2) %>%
      hc_add_series_bwpout(value = value, by=by, name="Outliers") %>%
      hc_plotOptions(series = list(
        marker = list(
          symbol = "circle"
        ),
        grouping=FALSE
      )) %>%
      highcharter::hc_colors(cols2) %>%
      highcharter::hc_exporting(enabled=TRUE)

  } else{
    hc<- highcharter::highchart() %>%
      highcharter::hc_chart(type="boxplot", inverted=FALSE) %>%
      highcharter::hc_title(text=chart_title) %>%
      highcharter::hc_legend(enabled=FALSE) %>%
      highcharter::hc_xAxis(type="category", categories=box_names_to_use, title=list(text=chart_x_axis_label)) %>%
      highcharter::hc_add_series_list(series2) %>%
      hc_plotOptions(series = list(
        marker = list(
          symbol = "circle"
        ),
        grouping=FALSE
      )) %>%
      highcharter::hc_colors(cols2) %>%
      highcharter::hc_exporting(enabled=TRUE)
  }
  hc
}
# Usage:
tst_box<- make_highchart_boxplot_with_colored_factors(value = df$value, by=df$categ, chart_title = "Some Title", chart_x_axis_label = "Some X Axis", show_outliers = TRUE)
tst_box

# Custom Colors:
custom_colors_with_alpha_in_hex<- paste0(gplots::col2hex(sample(x=colors(), size = length(unique(df$categ)), replace = FALSE)), "80")
tst_box2<- make_highchart_boxplot_with_colored_factors(value = df$value, by=df$categ, chart_title = "Some Title",
                                                      chart_x_axis_label = "Some X Axis",
                                                      show_outliers = TRUE, boxcolors = custom_colors_with_alpha_in_hex)
tst_box2

tst_box3<- make_highchart_boxplot_with_colored_factors(value = df$value, by=df$categ, chart_title = "Some Title",
                                                                 chart_x_axis_label = "Some X Axis",
                                                                 show_outliers = TRUE, boxcolors = custom_colors_with_alpha_in_hex, box_line_colors = "black")
tst_box3

希望对您有所帮助,如果您还有其他问题,请告诉我。我很乐意尽我所能提供帮助。 -nate