2
votes

Personnalisez les couleurs du boxplot avec Highcharter

J'ai des boîtes à moustaches sur highcharter et je voudrais personnaliser à la fois le

  • Couleur de remplissage
  • Couleur de la bordure

Voici mon code

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")) 

Les hc_colors ne fonctionnent que si je mets var2 au lieu de var code > mais alors les boîtes à moustaches sont rétrécies ...


2 commentaires

Seriez-vous également ouvert à d'autres solutions que highcharter?


Dépend de la solution, je voudrais un tracé qui se dessine quand vous l'ouvrez comme dans highcharter. Je sais déjà comment le faire dans ggplot ou complotly.


3 Réponses :


0
votes

Puisqu'il n'y a pas encore de réponse highcharter , je vous donne au moins une solution de base.

Premièrement, votre définition du bloc de données est quelque peu imparfaite, faites plutôt:

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

À présent, utiliser boxplot est assez simple. L'option border colore vos bordures. Avec l'option col , vous pouvez également colorer les remplissages.

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

Donne p >

 entrez la description de l'image ici

Remarque : Voir cette belle solution pour d'autres personnalisations.


0 commentaires

1
votes

API pour styliser fillColor : https: // api .highcharts.com / highcharts / series.boxplot.fillColor

Et pour "Couleur de la bordure" : https://api.highcharts.com/highcharts/series.boxplot.color

Exemple purement en JavaScript de style et de définition points: https://jsfiddle.net/BlackLabel/6tud3fgx

Et R code:

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"))


2 commentaires

De mon côté j'ai en effet les couleurs personnalisées mais les mêmes pour chaque box.


Ma réponse n'est qu'un exemple. J'ai changé les couleurs pour des points spécifiques (points [2] et points [4]). Rien ne vous empêche de changer les couleurs de la série entière (chaque boîte) en utilisant chart.series [0] .update ({...})



0
votes

J'ai créé quelques fonctions pour faire des trucs avec des highcharts et des boxplots. Il vous permettra de colorier chaque boîte à moustaches et de le remplir en conséquence, puis d'injecter de nouveaux paramètres graphiques selon l'API Highcharts, si vous le souhaitez.

Vérifiez-le:

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

Cela pourrait probablement être ajusté pour fonctionner avec un simple dataframe, mais je pense que cela vous donnera ce que vous voulez pour le moment sans avoir à le faire faire trop de travail supplémentaire. Aussi, peut-être regarder dans list_parse ou list_parse2 'de highcharter ... cela pourrait probablement aider à construire l'objet series`..Je toujours besoin d'examiner cela. p> p> e> Modifier: em> p> p>

J'ai développé l'exemple pour qu'il fonctionne avec un DF standard. Selon certaines questions de suivi, les couleurs sont définies à l'aide de la palette viridis à l'intérieur de la fonction make_highchart_boxplot_with_colored_factors . Si vous souhaitez autoriser votre propre palette et couleurs, vous pouvez exposer ces arguments et simplement les inclure en tant que paramètres dans l'appel de fonction. L'exemple développé emprunte comment ajouter des valeurs aberrantes à partir de la bibliothèque highcharter (bien que de manière hacky), puis construit tout le reste à partir de zéro. J'espère que cela aidera à clarifier ma réponse précédente. Veuillez noter que je pourrais probablement aussi nettoyer la condition if pour la rendre un peu plus brève, mais je l'ai gardée verbeuse à des fins d'illustration.

Double Edit: Vous pouvez désormais spécifier un vecteur de couleurs pour chaque niveau de la variable factor

## 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


7 commentaires

J'ai ce que vous avez fait pour les couleurs de la bordure, mais je ne comprends pas vraiment comment changer la couleur de remplissage, j'ai tout rempli en noir lorsque je teste votre code


Avez-vous installé viridis?


Oui j'ai vérifié, il est installé, toujours rempli en noir :(


Même avec le code édité ? De plus, j'ai mal parlé quand j'ai dit d'installer virids . J'aurais dû dire viridisLite


Semble fonctionner parfaitement maintenant, merci beaucoup!


Une seule chose ne fonctionne pas: la couleur des points aberrants


Ouais, c'est encore quelque chose sur lequel j'essaye de travailler. J'ai passé quelques heures à comprendre / expérimenter la manière de construire les données. Je suis devenu très proche, mais mes données finissent par être citées comme des caractères lorsque j'essaye d'ajouter différents ensembles de valeurs aberrantes. Je pense que c'est un problème avec la méthode toJSON Je pense qu'elle est utilisée dans le package htmlwidgets ... toJSON générera des éléments cités à partir d'une liste à moins qu'ils ne proviennent d'un dataframe ... Pour cette raison, j'obtiens quelque chose comme {data: [["2,10"], ["3,5"]]} lorsque j'essaie de convertir en JSON approprié. Voir ce JSFiddle: jsfiddle.net/BlackLabel/f2z9tLrs