How do you create a bar and line plot with R dygraphs?

前端 未结 3 1636
情书的邮戳
情书的邮戳 2020-12-06 13:49

I would like to create a bar and line chart using dygraphs, which seems like it should be possible based on the \"Bar & Line Chart\" dygraphs example here, and the

相关标签:
3条回答
  • 2020-12-06 14:28

    After a bit of research I think that this would be simplest. At least that's the way it seems for me.

    You would need to download the "barseries.js" file available at http://dygraphs.com/tests/plotters.html

    Then the code would look like so

    library(dygraphs)
    
    dyBarSeries <- function(dygraph, name, ...) {
      file <- "plotters/barseries.js" #you need to link to the downloaded file
      plotter_ <- paste0(readLines(file, skipNul = T), collapse = "\n")
    
      dots <- list(...)
      do.call('dySeries', c(list(dygraph = dygraph, name = name, plotter = 
    plotter_), dots))
    
    }
    
    lungDeaths <- cbind(ldeaths, mdeaths)
    
    
    
    dygraph(lungDeaths) %>% 
      dyBarSeries("ldeaths") %>%
      dySeries("mdeaths")
    

    Yielding this result

    enter image description here

    0 讨论(0)
  • 2020-12-06 14:30

    I am not sure this is exactly what you want. What I propose, comes close to the combination of a bar plot and a line plot, without the need to create a separate function.

    You can set the type of plot per series, with dySeries. You can choose between lineplot (default), stepPlot, and stemPlot. In addition you may set to see the points with drawPoints and pointSize, you may also opt to fill the graph or not with fillGraph. For other options type ?dySeries

    The code looks as follows:

    library(dygraphs)
    
    lungDeaths <- cbind(ldeaths, mdeaths)
    
    dygraph(lungDeaths, main = "Main Title") %>%
      dySeries("ldeaths", drawPoints = FALSE) %>%
      dySeries("mdeaths", stepPlot = TRUE, fillGraph = TRUE)
    

    Yielding this plot:

    Please, let me know whether this is what you want.

    0 讨论(0)
  • 2020-12-06 14:47

    Sometimes you get lucky… I‘ve worked on the same thing a couple of weeks ago and I‘ve found that the documentation is not quite clear on how to do it. But you were pretty close yourself.

    How to do it – step by step:

    1. You have to set the plotter for each dyseries
    2. The plotter argument in the dyseries command does not take functions names. But it needs to be a javascript function as plain text
    3. Stacking the bars is easier. Multibars need a way to pass an argument to the javascript function, which you cannot do directly in the package. So I had to do a workaround (At least I found no better way to do it in R).

    BTW, setting the dyPlotter command did not work because it sets the plotter globally for all dySeries in the plot. At least that‘s what I figure it does.

    So without further ado, here‘s my code. I have added some more test data just to show all the functions.

    Test data:

    library(xts)
    library(dygraphs)
    test<-xts(matrix(rnorm(100*4), ncol=4, nrow=100), order.by=seq.POSIXt(as.POSIXct("2017-01-01 00:00", tz="UTC"),by=3600, length.out = 100))
    colnames(test)<-c("Series_A","Series_B", "Series_C", "Series_D")
    

    Functions:

    dy_position<-function(data_final, plot_title, y2_names=NULL, y1_label, y2_label, y1_step=F, y2_step=F, stacked=T){
    
      data_final<-reorder_xts(data_final, y2_names) #reorder necessary so that all y2 are at the right end of the xts. Needed for the multibar plot
    
      dyg <- dygraphs::dygraph(data_final, main=plot_title)
      dyg <- dygraphs::dyAxis(dyg, "x", rangePad=20)
      dyg <- dygraphs::dyAxis(dyg, "y", label = y1_label,
                          axisLabelWidth = 90)
      y1_names<-colnames(data_final)[!(colnames(data_final) %in%y2_names)]
    
      if (length(y1_names)==1){
        stacked<-T #in this case only stacking works
      }
    
      if (stacked){
        dyg <- dygraphs::dyOptions(dyg,stepPlot=y1_step,stackedGraph = T)
        for(i in seq_along(y1_names)) {
         dyg <- dygraphs::dySeries(dyg, y1_names[i], axis = "y", strokeWidth = 1.5, stepPlot = y1_step, plotter="  function barChartPlotter(e) {
                                var ctx = e.drawingContext;
                                var points = e.points;
                                var y_bottom = e.dygraph.toDomYCoord(0);
    
                                ctx.fillStyle = e.color;
    
                                // Find the minimum separation between x-values.
                                // This determines the bar width.
                                var min_sep = Infinity;
                                for (var i = 1; i < points.length; i++) {
                                var sep = points[i].canvasx - points[i - 1].canvasx;
                                if (sep < min_sep) min_sep = sep;
                                }
                                var bar_width = Math.floor(2.0 / 3 * min_sep);
    
                                // Do the actual plotting.
                                for (var i = 0; i < points.length; i++) {
                                var p = points[i];
                                var center_x = p.canvasx;
    
                                ctx.fillRect(center_x - bar_width / 2, p.canvasy,
                                bar_width, y_bottom - p.canvasy);
    
                                ctx.strokeRect(center_x - bar_width / 2, p.canvasy,
                                bar_width, y_bottom - p.canvasy);
                                }
    }")
        }
      } else {
        dyg <- dygraphs::dyOptions(dyg,stepPlot=y1_step)
        for(i in seq_along(y1_names)) {
    
          #plotter in function
          dyg <- dygraphs::dySeries(dyg, y1_names[i], axis = "y", strokeWidth   = 1.5, stepPlot = y1_step, plotter =multibar_combi_plotter(length(y2_names)))
        }
      }
    
      # put stuff on y2 axis
      dyg <- dygraphs::dyAxis(dyg, "y2", label = y2_label, independentTicks = T)
      for(i in seq_along(y2_names)) {
        dyg <- dygraphs::dySeries(dyg, y2_names[i], axis = "y2", strokeWidth = 1.5, stepPlot = y2_step)
      }
    
      return(dyg)
    }
    
    #we need to take into account all values and then leave out the ones we do not like
    multibar_combi_plotter<-function(num_values){
      #plotter function
      plotter_text<-"function multiColumnBarPlotter(e) {
      // We need to handle all the series simultaneously.
      if (e.seriesIndex !== 0) return;
    
      var g = e.dygraph;
      var ctx = e.drawingContext;
      var sets = e.allSeriesPoints;
      var y_bottom = e.dygraph.toDomYCoord(0);
    
      // Find the minimum separation between x-values.
      // This determines the bar width.
      var min_sep = Infinity;
       for (var j = 0; j < sets.length-%s; j++) {
        var points = sets[j];
        for (var i = 1; i < points.length; i++) {
         var sep = points[i].canvasx - points[i - 1].canvasx;
         if (sep < min_sep) min_sep = sep;
      }
      }
      var bar_width = Math.floor(2.0 / 3 * min_sep);
    
      var fillColors = [];
      var strokeColors = g.getColors();
      for (var i = 0; i < strokeColors.length; i++) {
      fillColors.push(strokeColors[i]);
      }
    
      for (var j = 0; j < sets.length-%s; j++) {
      ctx.fillStyle = fillColors[j];
      ctx.strokeStyle = strokeColors[j];
      for (var i = 0; i < sets[j].length; i++) {
        var p = sets[j][i];
        var center_x = p.canvasx;
        var x_left = center_x - (bar_width / 2) * (1 - j/(sets.length-%s-1));
    
       ctx.fillRect(x_left, p.canvasy,
       bar_width/sets.length, y_bottom - p.canvasy);
    
      ctx.strokeRect(x_left, p.canvasy,
      bar_width/sets.length, y_bottom - p.canvasy);
     }
     }
       }"
    
      custom_plotter <- sprintf(plotter_text, num_values, num_values, num_values)
      return(custom_plotter)
      }
    
    
    reorder_xts<-function(xts_series,line_names){
      bar_names<-colnames(xts_series)[!(colnames(xts_series)%in%line_names)]
      xts_series<-xts_series[,c(bar_names,line_names)]
      return(xts_series)
    }
    

    Some Explanation:

    dy_position does all the plotting. It uses individual plotters per series axis.

    reorder_xts is needed to make sure that all lines plots are at the right end of the xts. This is needed for the multibar plot. Because the java script is looping over all series (sets) to determine the width of the bars and we need to make sure we are not looping over the series which are line plots. Otherwise we have additional bars.

    multibar_combi_plotter does exactly that. It takes a numeric parameter lines_names and modifies the javascript string so that it loops over all plots except for the line_names (i.e. last series in the right part of the xts). Notice several little %s in the string for the sprintfcommand! Afterwards it returns the plotter as character for the dySeries argument.

    All the javascript code is taken directly from the examples in the dygraphs folder.

    Here are some examples...

    Examples:

    dy_position(test,plot_title = "Test1", y2_names =    c("Series_C","Series_D"),y1_label = "Axis1", y2_label = "Axis2", stacked=F)
    dy_position(test,plot_title = "Test1", y2_names = c("Series_C","Series_D"),y1_label = "Axis1", y2_label = "Axis2", stacked=T)
    dy_position(test,plot_title = "Test1", y2_names = c("Series_B","Series_C","Series_D"),y1_label = "Axis1", y2_label = "Axis2", stacked=T)
    dy_position(test,plot_title = "Test1", y2_names = c("Series_D"),y1_label = "Axis1", y2_label = "Axis2", stacked=F)
    dy_position(test,plot_title = "Test1", y2_names = c("Series_D"),y1_label = "Axis1", y2_label = "Axis2", stacked=T)
    dy_position(test,plot_title = "Test1", y2_names = NULL ,y1_label = "Axis1", y2_label = "Axis2", stacked=F)
    dy_position(test,plot_title = "Test1", y2_names = NULL ,y1_label = "Axis1", y2_label = "Axis2", stacked=T)
    
    0 讨论(0)
提交回复
热议问题