Если вы не хотите использовать shiny
, вы можете либо использовать опцию dyRebase
в dygraphs
, либо вам нужно вставить собственный код javascript
в plotly
. В обоих примерах я делаю ребаз, а не ноль.
Вариант 1: с dygraphs
library(dygraphs)
library(tidyquant)
library(timetk)
library(tidyr)
stocks <- tq_get(c("AAPL", "MSFT"), from = "2019-01-01")
stocks %>%
dplyr::select(symbol, date, adjusted) %>%
tidyr::spread(key = symbol, value = adjusted) %>%
timetk::tk_xts() %>%
dygraph() %>%
dyRebase(value = 1) %>%
dyRangeSelector()
Обратите внимание, что `dyRebase (значение = 0) не работает.
Вариант 2: с plotly
с использованием обработчиков событий . Я стараюсь избегать ggplotly
, поэтому мое решение plot_ly
. Здесь выбор времени осуществляется только с помощью увеличения, но я думаю, что это может быть сделано и с помощью селектора диапазона. Код javascript
в onRenderRebaseTxt
перебрасывает каждую трассу к первой видимой точке данных (с учетом возможных пропущенных значений). Он вызывается только с событием relayout
, следовательно, первый ребазинг должен быть выполнен перед сюжетом.
library(tidyquant)
library(plotly)
library(htmlwidgets)
library(dplyr)
stocks <- tq_get(c("AAPL", "MSFT"), from = "2019-01-01")
pltly <-
stocks %>%
dplyr::group_by(symbol) %>%
dplyr::mutate(adjusted = adjusted / adjusted[1L]) %>%
plotly::plot_ly(x = ~date, y = ~adjusted, color = ~symbol,
type = "scatter", mode = "lines") %>%
plotly::layout(dragmode = "zoom",
datarevision = 0)
onRenderRebaseTxt <- "
function(el, x) {
el.on('plotly_relayout', function(rlyt) {
var nrTrcs = el.data.length;
// array of x index to rebase to; defaults to zero when all x are shown, needs to be one per trace
baseX = Array.from({length: nrTrcs}, (v, i) => 0);
// if x zoomed, increase baseX until first x point larger than x-range start
if (el.layout.xaxis.autorange == false) {
for (var trc = 0; trc < nrTrcs; trc++) {
while (el.data[[trc]].x[baseX[trc]] < el.layout.xaxis.range[0]) {baseX[trc]++;}
}
}
// rebase each trace
for (var trc = 0; trc < nrTrcs; trc++) {
el.data[trc].y = el.data[[trc]].y.map(x => x / el.data[[trc]].y[baseX[trc]]);
}
el.layout.yaxis.autorange = true; // to show all traces if y was zoomed as well
el.layout.datarevision++; // needs to change for react method to show data changes
Plotly.react(el, el.data, el.layout);
});
}
"
htmlwidgets::onRender(pltly, onRenderRebaseTxt)