如何使用 R dygraphs 创建条形图和线图?
How do you create a bar and line plot with R dygraphs?
我想使用 dygraphs 创建一个条形图和折线图,根据 dygraphs 包中提供的 "Bar & Line Chart" dygraphs 示例 here, and the dyBarChart()
custom plotter,这似乎应该是可能的。
使用自定义包装器,我可以创建一个条形图,所以我认为该代码有效:
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()
我假设我可以使用 dySeries()
来自定义我想用 line/bar 显示的系列,但以下都不起作用。它们不会出错,但不会创建任何内容。我也不确定 "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")
谢谢。
我不确定这是否正是您想要的。我的提议接近条形图和线图的组合,无需创建单独的函数。
您可以设置每个系列的绘图类型,dySeries
。您可以在线图(默认)、stepPlot
和 stemPlot
之间进行选择。另外你可以设置用drawPoints
和pointSize
查看点,你也可以选择用fillGraph
填充或不填充图形。对于其他选项,键入 ?dySeries
代码如下所示:
library(dygraphs)
lungDeaths <- cbind(ldeaths, mdeaths)
dygraph(lungDeaths, main = "Main Title") %>%
dySeries("ldeaths", drawPoints = FALSE) %>%
dySeries("mdeaths", stepPlot = TRUE, fillGraph = TRUE)
生成此图:
请告诉我这是否是您想要的。
有时你会很幸运……几周前我做过同样的事情,我发现文档并不清楚如何做。但你自己也很接近。
如何做——一步一步:
- 您必须为每个dyseries设置绘图仪
- dyseries 命令中的
plotter
参数不采用函数名称。但它需要是一个 java 作为纯文本的脚本函数
- 堆叠钢筋更容易。 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
并修改 java 脚本字符串,以便循环遍历除 line_names 之外的所有图(即 xts 右侧的最后一个系列)。注意 sprintf
命令的字符串中的几个小 %s
!之后它 returns 绘图仪作为 dySeries 参数的 character
。
所有 java 脚本代码均直接取自 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)
经过一些研究,我认为这将是最简单的。至少在我看来是这样。
您需要在 http://dygraphs.com/tests/plotters.html
下载 "barseries.js" 文件
然后代码看起来像这样
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
我想使用 dygraphs 创建一个条形图和折线图,根据 dygraphs 包中提供的 "Bar & Line Chart" dygraphs 示例 here, and the dyBarChart()
custom plotter,这似乎应该是可能的。
使用自定义包装器,我可以创建一个条形图,所以我认为该代码有效:
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()
我假设我可以使用 dySeries()
来自定义我想用 line/bar 显示的系列,但以下都不起作用。它们不会出错,但不会创建任何内容。我也不确定 "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")
谢谢。
我不确定这是否正是您想要的。我的提议接近条形图和线图的组合,无需创建单独的函数。
您可以设置每个系列的绘图类型,dySeries
。您可以在线图(默认)、stepPlot
和 stemPlot
之间进行选择。另外你可以设置用drawPoints
和pointSize
查看点,你也可以选择用fillGraph
填充或不填充图形。对于其他选项,键入 ?dySeries
代码如下所示:
library(dygraphs)
lungDeaths <- cbind(ldeaths, mdeaths)
dygraph(lungDeaths, main = "Main Title") %>%
dySeries("ldeaths", drawPoints = FALSE) %>%
dySeries("mdeaths", stepPlot = TRUE, fillGraph = TRUE)
生成此图:
请告诉我这是否是您想要的。
有时你会很幸运……几周前我做过同样的事情,我发现文档并不清楚如何做。但你自己也很接近。
如何做——一步一步:
- 您必须为每个dyseries设置绘图仪
- dyseries 命令中的
plotter
参数不采用函数名称。但它需要是一个 java 作为纯文本的脚本函数 - 堆叠钢筋更容易。 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
并修改 java 脚本字符串,以便循环遍历除 line_names 之外的所有图(即 xts 右侧的最后一个系列)。注意 sprintf
命令的字符串中的几个小 %s
!之后它 returns 绘图仪作为 dySeries 参数的 character
。
所有 java 脚本代码均直接取自 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)
经过一些研究,我认为这将是最简单的。至少在我看来是这样。
您需要在 http://dygraphs.com/tests/plotters.html
下载 "barseries.js" 文件然后代码看起来像这样
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