2017-06-16 46 views
2

我想创建一个使用dygraphs的条形图和折线图,基于dygraphs软件包中提供的“Bar &折线图”dygraph示例heredyBarChart()custom plotter,似乎应该可以。如何用R dygraphs创建条形图和线图?

使用定制的包装,我可以创造一个barplot,所以我觉得代码工作:

library(dygraphs) 

dyBarChart <- function(dygraph) { 
    dyPlotter(
    dygraph = dygraph, 
    name = "BarChart", 
    path = system.file("examples/plotters/barchart.js",package = "dygraphs") 
) 
} 

lungDeaths <- cbind(ldeaths, mdeaths) 
dygraph(lungDeaths) %>% 
    dyBarChart() 

enter image description here

我认为我可以再使用dySeries()定制我想系列以线条/栏显示,但以下任何一项都不行。他们不会错误,但没有创建。我也不确定"linePlotter"是否是正确的绘图仪名称,但无论如何,我需要一点帮助。

# doesn't work 
dygraph(lungDeaths) %>% 
    dyBarChart() %>% 
    dySeries("ldeaths", plotter = "linePlotter") 

# also doesn't work: 
dygraph(lungDeaths) %>% 
    dySeries("ldeaths", plotter = "dyBarChart") %>% 
    dySeries("mdeaths", color = "blue") 

谢谢。

回答

2

有时你会很幸运......几周前我曾经做过同样的事情,并且我发现文档不太清楚如何去做。但你很亲密。

  1. 必须设置绘图仪为每个dyseries
  2. plotter参数在dyseries命令不带函数的名称:一步一步 -

    怎么做。但它必须是纯文本的JavaScript函数

  3. 堆叠条更容易。 Multibars需要一种方法将参数传递给javascript函数,而不能直接在包中进行。所以我必须做一个解决方法(至少我发现在R中没有更好的方法)。

顺便说一句,设置dyPlotter命令不起作用,因为它为绘图中的所有dySeries全局设置绘图仪。至少这就是我所认为的。

所以不用再说了,这是我的代码。为了显示所有功能,我添加了更多的测试数据。

测试数据:

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

功能:

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

一些解释:

dy_position做所有的绘图。它使用每个系列轴的单独绘图仪。

reorder_xts是需要确保所有线图都位于xts的右端。这是多条线图所需要的。因为java脚本循环遍历所有系列(集合)以确定条的宽度,所以我们需要确保我们没有循环遍历线图的系列。否则,我们有更多的酒吧。

multibar_combi_plotter确实如此。它接受一个数字参数lines_names并修改javascript字符串,以便它遍历除line_names之外的所有图(即xts右侧的最后一个系列)。在sprintf命令的字符串中注意几个小号%s!之后它返回绘图仪作为dySeries参数的character

所有的javascript代码直接来自dygraphs文件夹中的例子。

下面是一些例子...

例子:

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

谢谢!这回答了我的问题。我要修改你的代码,使得y轴的尺寸相同,但这非常有帮助。 –

0

我不确定这正是你想要的。我的建议是接近条形图和线条图的组合,而不需要创建单独的功能。

您可以设置每个系列的图的类型,其中dySeries。您可以选择lineplot(默认),stepPlotstemPlot。此外,您可能会设置查看drawPointspointSize的积分,您也可以选择填写图表或不填写fillGraph。对于其他选项类型?dySeries

的代码如下:

library(dygraphs) 

lungDeaths <- cbind(ldeaths, mdeaths) 

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

屈服这个阴谋:

enter image description here

请让我知道这是否是你想要的。

+0

感谢回应,我担心我可能不得不走这条路,但@ user3293236提供了一个很好的答案,使用实际的酒吧。 –

0

了一些研究,我认为,这将是最简单的了。至少这就是我看起来的样子。

您需要下载提供的 “barseries.js” 文件在http://dygraphs.com/tests/plotters.html

然后代码看起来像这样

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

屈服这一结果

enter image description here