Как создать линейку и линейный график с помощью R-графиков?

Я хотел бы создать гистограмму и линейную диаграмму с использованием графиков, что, по-видимому, должно быть возможно на основе приведенного здесь примера графиков "Линейчатая диаграмма и график", а также dyBarChart() пользовательский плоттер в пакете dygraphs.

Используя пользовательскую оболочку, я могу создать барплот, поэтому я думаю, что код работает:

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() чтобы настроить серию я хотел показать с линией / бар, но ни одна из следующих работ. Они не ошибаются, но ничего не создается. Я также не уверен, если "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")

Благодарю.

3 ответа

Решение

Иногда вам везет... Я работал над тем же самым пару недель назад и обнаружил, что в документации не совсем ясно, как это сделать. Но вы были довольно близки к себе.

Как это сделать - пошагово:

  1. Вы должны установить плоттер для каждой дизерии
  2. plotter Аргумент в команде dyseries не принимает имена функций. Но это должна быть функция JavaScript как обычный текст
  3. Укладывать бары проще. Мультибарам нужен способ передать аргумент функции 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 таким образом, чтобы она зацикливалась на всех графиках, кроме названий строк (то есть последней серии в правой части xts). Обратите внимание на несколько маленьких %s в строке для sprintfкоманда! После этого он возвращает плоттер как character для аргумента dySeries.

Весь код 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)

После небольшого исследования я думаю, что это будет проще всего. По крайней мере, так мне кажется.

Вам необходимо загрузить файл "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")

Дать этот результат

введите описание изображения здесь

Я не уверен, что это именно то, что вы хотите. То, что я предлагаю, приближается к комбинации гистограммы и линейного графика, без необходимости создавать отдельную функцию.

Вы можете установить тип сюжета для серии, с 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)

Получив этот участок:

введите описание изображения здесь

Пожалуйста, дайте мне знать, хотите ли вы этого.

Другие вопросы по тегам