2017-06-16 92 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