I have created a dygraph and want change the y-axis from scientific notation to decimal form.
This is what the code looks like:
df_xts <- xts(df$Var1,order.by=df$Date)
dygraph(A_xts,
main="DF - Var1",group="group1") %>%
dySeries("V1",label="Var1") %>%
dyOptions(stackedGraph = FALSE,colors=c("blue")) %>%
dyRangeSelector()
I'm guessing it would be placed under dyOptions but I'm not sure.
Thanks!
With my sample data it looks like this:
df_xts <- xts(runif(10) * 1e10, order.by = as.POSIXct(x = 1:10, origin = "2015-01-01") )
dygraph(df_xts, main="DF - Var1") %>%
dySeries("V1",label="Var1") %>%
dyOptions(maxNumberWidth = 20, stackedGraph = FALSE,colors=c("blue")) %>%
dyRangeSelector
Related
I need to highlight some dates ranges in my time series chart, but I can´t go ahead.
The dataset used is following:
library(dplyr)
library(xts)
library(zoo)
df <- read.csv("https://github.com/rhozon/datasets/raw/master/dataset_1a.csv", header = TRUE, sep =",") %>%
mutate(
dates = as.Date(dates)
) %>%
filter(
dates >= "2019-01-01"
) %>%
glimpse()
df_xts <- xts(df[,-1, drop = FALSE], order.by = df[,1]) %>% as.xts()
class(df_xts)
head(df_xts)
Then I tryed the following PerfomanceAnalytics commands:
library(PerformanceAnalytics)
# Create period to hold the 3 months of 2020
period <- c("2020-01/2020-03")
# Highlight the first three months of 2020
chart.TimeSeries(df$prices_usa, period.areas = period, period.color = "lightgrey")
with no success...
Error in try.xts(x, error = "'x' needs to be timeBased or xtsible") :
'x' needs to be timeBased or xtsible
By using the dygraphs package...
library(dygraphs)
dygraph( df$prices_usa ) %>%
dyShading(from = "2020-06-30", to = "2020-09-01") %>%
dyAnnotation("2020-08-01", text = "X", tooltip = "date range") %>%
dyAxis("x", drawGrid = TRUE) %>%
dyEvent("2020-06-30", "Jul 2020", labelLoc = "bottom") %>%
dyEvent("2020-09-01", "Sep 2020", labelLoc = "bottom") %>%
dyOptions(drawPoints = FALSE, pointSize = 2) #%>%
And again I found another issue:
Error in dygraph(df$prices_usa) : Unsupported type passed to argument 'data'.
I didn´t tryed with the ggplot2 package because I need to use it with interaticvity.
Could someone recommend me a solution to these issues or something that is simpler to do (even with ggplot2+plotly) that can be useful for me to demarcate or highlight some ranges of dates/periods in my time series graphs?
Using the reproducible xts object in the Note at the end use plot and xblocks. To specify a different color use something like adjustcolor("blue", 0.2) in place of grey(...). For many other approaches google R shading recessions
library(xts)
plot(as.zoo(aapl))
xblocks(aapl, ifelse(time(aapl) %in% time(aapl[period]), grey(.2, .2), NA))
Note
library(quantmod)
getSymbols("AAPL")
period <- "2020-01/2020-03"
aapl <- Cl(AAPL)
I am having a problem with skinny bars in a stacked column chart in highcharter in R. I have created a repo of the code below and am wondering if someone could help me avoid the issue of having the bars get super skinny when I add more than 49 series to the graph.
Any ideas or work arounds would be greatly appreciated.
As always, thank you in advance.
Best,
Nate
library(highcharter)
library(magrittr)
library(viridisLite)
dfmtx<- as.data.frame.matrix(matrix(data = abs(rnorm(n=20*50, mean = 0, sd=1)), ncol = 50))
dfmtx<- dfmtx/rowSums(dfmtx)
df<- data.frame(date=seq.Date(from = as.Date("2001-01-01"), to = Sys.Date(), by="years")[1:20],
dfmtx, stringsAsFactors = F)
hc<- highcharter::highchart() %>%
highcharter::hc_chart(type = "column") %>%
#highcharter::hc_plotOptions(column=list(pointWidth=45, pointPadding=0, groupPadding=0.1, padding=0)) %>%
highcharter::hc_plotOptions(column = list(stacking = "normal"), series=list(cropThreshold=200)) %>%
highcharter::hc_xAxis(categories = df$date, title=list(text="Fake Date")) %>%
highcharter::hc_title(text=paste0("Bars Get Skinny When You Add 50"))
for(i in 2:50){ # Smiles...This Works!
#for(i in 2:51){ # Tears..skinny bars :(
the_name<- colnames(df)[i]
hc<- hc %>%
highcharter::hc_add_series(name=the_name,
data = df[,i],
stack = "SameStack")
}
# Pretty colors...why not?
cols<- viridisLite::viridis(n=length(hc$x$hc_opts$series))
cols<- base::substr(cols, 0,7)
hc<- hc %>%
highcharter::hc_yAxis(title=list(text="Proportion"), max=1) %>%
highcharter::hc_colors(cols) %>%
highcharter::hc_legend(align="center")
hc
You can set the width and height of the chart using hc_size().
for(i in 2:51){ # Tears..skinny bars :(
the_name<- colnames(df)[i]
hc<- hc %>%
highcharter::hc_add_series(name=the_name,
data = df[,i],
stack = "SameStack")
}
# Pretty colors...why not?
cols<- viridisLite::viridis(n=length(hc$x$hc_opts$series))
cols<- base::substr(cols, 0,7)
hc<- hc %>%
highcharter::hc_yAxis(title=list(text="Proportion"), max=1) %>%
highcharter::hc_colors(cols) %>%
highcharter::hc_legend(align="center") %>%
highcharter::hc_size(height = 800) #Setting chart height to 800.
hc
TLDR: I want to label the frame slider with the three letter abbreviation instead of the number for each month.
I created a bar chart showing average snow depth each month over a 40 year period. I'm pulling my data from NOAA and then grouping by year and month using lubridate. Here is the code:
snow_depth <- govy_data$snwd %>%
replace_na(list(snwd = 0)) %>%
mutate(month_char = month(date, label = TRUE, abbr = TRUE)) %>%
group_by(year = year(date), month = month(date), month_char) %>%
summarise(avg_depth = mean(snwd))
The mutate function creates a column (month_char) in the data frame holding the three letter abbreviation for each month. The class for this column is an ordered factor.
The code below shows how I'm creating the chart/animation:
snow_plot <- snow_depth %>% plot_ly(
x = ~year,
y = ~avg_depth,
color = ~avg_temp,
frame = ~month,
text = ~paste('<i>Month</i>: ', month_char,
'<br><b>Avg. Depth</b>: ', avg_depth,
'<br><b>Avg. Temp</b>: ', avg_temp),
hoverinfo = 'text',
type = 'bar'
)
snow_plot
This code generates a plot that animates well and looks like this:
What I'd like to do is change the labels on the slider so instead of numbers, it shows the three letter month abbreviation. I've tried switching the frame to ~month_char which is the ordered factor of three letter month abbreviations. What I end up with, isn't right at all:
The data frame looks like:
I fear, with the current implementation of animation sliders in R's plotly API the desired behaviour can't be realized. This is due to the fact, that no custom animation steps are allowed (this includes the labels). Please see (and support) my GitHub FR for further information.
This is the best I was currently able to come up with:
library(plotly)
DF <- data.frame(
year = rep(seq(1980L, 2020L), each = 12),
month = rep(1:12, 41),
month_char = rep(factor(month.abb), 41),
avg_depth = runif(492)
)
fig <- DF %>%
plot_ly(
x = ~year,
y = ~avg_depth,
frame = ~paste0(sprintf("%02d", month), " - ", month_char),
type = 'bar'
) %>%
animation_slider(
currentvalue = list(prefix = "Month: ")
)
fig
(Edit from OP) Here's the resulting graph using the above code:
I am trying to produce a ribbon on my highcharter chart (roughly following is there an equivalent to geom_ribbon in highcharter?).
However, the following example to produce a highcharter graph in R produces an error:
library(quantmod)
library(dplyr)
library(highcharter)
getSymbols("VOD")
bb_data = BBands(Cl(VOD), n=20)
highchart(type = "stock") %>%
hc_add_series(bb_data, type = "arearange", hcaes(low = dn, high=up))
The error is:
Error: 'hcaes(low = dn, high = up)' argument is not named in hc_add_series
I have think this is because it is a time series object (xts).
It works if I cast it to a data.frame, but then I lose the date.
highchart(type = "stock") %>%
hc_add_series(as.data.frame(bb_data), type = "arearange", hcaes(low = dn, high=up))
I cannot combine it to with the moving average or price data as I would wish, as the ribbon is then missing from the subsequent plot:
highchart(type = "stock") %>%
hc_add_series(Cl(VOD), name = "VOD") %>%
hc_add_series(bb_data$mavg, name = "20d MA") %>%
hc_add_series(as.data.frame(bb_data), type = "arearange", hcaes(low = dn, high=up))
ok, so I had to first extract the date from the time series object and bind it with the time series object to form a data frame or data table and then plot using that.
bb_data2 = cbind(date = as.Date(index(bb_data)), data.table(bb_data))
highchart(type = "stock") %>%
hc_add_series(bb_data2, type = "arearange", hcaes(x=date, low = dn, high=up)) %>%
hc_add_series(Cl(VOD), name = "VOD") %>%
hc_add_series(bb_data$mavg, name = "20d MA")
I am trying to make an interactive stock performance plot from R. It is to compare the relative performance of several stocks. Each stock's performance line should start at 0%.
For static plots I would use dplyr group_by and mutate to calculate performance (see my code).
With ggplot2 and plotly/ggplotly, rangeslider() allows to interactively select the x-axis range. Now I'd like performance to be starting at 0 from any start range selected.
How can I either move the dplyr calculation into the plotting or have a feedback loop to recalculate as the range is changed?
Ideally it should be usable in static RMarkdown HTML. Alternatively I'd also switch to Shiny.
I tried several options for rangeslider. Also I tried with ggplot stat_function but could not achieve the desired result. Also I found dygraphs which has dyRangeSelector. But also here I face the same problem.
This is my code:
library(plotly)
library(tidyquant)
stocks <- tq_get(c("AAPL", "MSFT"), from = "2019-01-01")
range_from <- as.Date("2019-02-01")
stocks_range <- stocks %>%
filter(date >= range_from) %>%
group_by(symbol) %>%
mutate(performance = adjusted/first(adjusted)-1)
p <- stocks_range %>%
ggplot(aes(x = date, y = performance, color = symbol)) +
geom_line()
ggplotly(p, dynamicTicks = T) %>%
rangeslider(borderwidth = 1) %>%
layout(hovermode = "x", yaxis = list(tickformat = "%"))
If you do not want to use shiny, you can either use the dyRebase option in dygraphs, or you have to insert custom javascript code in plotly. In both examples, I rebase to one, not zero.
Option 1: with 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()
Note that `dyRebase(value = 0) does not work.
Option 2: with plotly using event handlers. I try to avoid ggplotly, hence my plot_ly solution. Here the time selection is just by zooming, but I think it can be done by a range selector as well. The javascript code in onRenderRebaseTxt rebases every trace to the first visible data point (taking care of possible missing values). It is only called with the relayout event, hence the first rebasing must be done before the plot.
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)
I found a solution with plotly_relayout which reads out the visible x-axis range. This is used to recompute the performance. It works as a Shiny app. Here's my code:
library(shiny)
library(plotly)
library(tidyquant)
library(lubridate)
stocks <- tq_get(c("AAPL", "MSFT"), from = "2019-01-01")
ui <- fluidPage(
titlePanel("Rangesliding performance"),
mainPanel(
plotlyOutput("plot")
)
)
server <- function(input, output) {
d <- reactive({ e <- event_data("plotly_relayout")
if (is.null(e)) {
e$xaxis.range <- c(min(stocks$date), max(stocks$date))
}
e })
stocks_range_dyn <- reactive({
s <- stocks %>%
group_by(symbol) %>%
mutate(performance = adjusted/first(adjusted)-1)
if (!is.null(d())) {
s <- s %>%
mutate(performance = adjusted/nth(adjusted, which.min(abs(date - date(d()$xaxis.range[[1]]))))-1)
}
s
})
output$plot <- renderPlotly({
plot_ly(stocks_range_dyn(), x = ~date, y = ~performance, color = ~symbol) %>%
add_lines() %>%
rangeslider(start = d()$xaxis.range[[1]], end = d()$xaxis.range[[2]], borderwidth = 1)
})
}
shinyApp(ui = ui, server = server)
Definign the start/end of the rangeslider only works with plot_ly, not with a ggplot object converted by ggplotly. I am unsure if this is a bug, therefore opened an issue on Github.