I am trying to create a linechart with rbokeh where the x-axis is supposed to show a datetime variable.
Consider the following example:
data <- tibble(
time = as.POSIXct(c("2019-08-27 08:15:00",
"2019-08-27 10:30:00",
"2019-08-27 12:45:00")),
value = c(0.3, 0.6, 0.2)
)
figure(data = data) %>%
ly_lines(x = time,
y = value) %>%
ly_points(x = time,
y = value,
hover = value) %>%
x_axis(label = "Date"
# number_formatter = "numeral",
# format = list(hours = "%d %B %Y")
) %>%
y_axis(label = "Values",
number_formatter = "numeral",
format = list(percent = "0 %")) %>%
y_range(dat = c(0, 1))
This produces the following plot:
Not only does this show the wrong values on the x-axis, they are also formatted in a very inconvenient way.
I have tried changing the format to a more appropriate way by using the format argument (that has been commented out in my example), but this only causes the plot to not even be created anymore.
What is going on here?
Your code worked for me with the format argument. If you want the time included, I would use this:
figure(data = data) %>%
ly_lines(x = time,
y = value) %>%
ly_points(x = time,
y = value,
hover = value) %>%
x_axis(label = "Date",
number_formatter = "numeral",
format = list(hours = "%Y-%m-%d %H:%M:%S")
) %>%
y_axis(label = "Values",
number_formatter = "numeral",
format = list(percent = "0 %")) %>%
y_range(dat = c(0, 1)) %>%
theme_axis("x", major_label_orientation = 45)
Related
I am trying to develop a Business Cycle Clock similar to https://kosis.kr/visual/bcc/index/index.do?language=eng.
I've already achieved most of the things I wanted to replicate, but I can't figure it out how to add these traces (for example, in the link above set speed to 10 and trace length to 5 and then click on 'Apply' to understand what I mean).
Does anyone have any idea how to implement it? It would make the "clock" much easier to read. Thanks in advance.
Reprocible example:
library(plotly)
library(dplyr)
library(magrittr)
variable <- rep('A',10)
above_trend <- rnorm(10)
mom_increase <- rnorm(10)
ref_date <- seq.Date('2010-01-01' %>% as.Date,
length.out = 10,by='m')
full_clock_db <- cbind.data.frame(variable, above_trend, mom_increase, ref_date)
freq_aux = 'm'
ct = 'Brazil'
main_title = paste0('Business Cycle Clock para: ', ct)
m <- list(l=60, r=170, b=50, t=70, pad=4)
y_max_abs = 2
x_max_abs = 5
fig = plot_ly(
data = full_clock_db,
x = ~mom_increase,
y = ~above_trend,
color = ~variable,
frame = ~ref_date,
text = ~variable,
hoverinfo = "text",
type = 'scatter',
mode = 'markers'
) %>%
animation_opts( frame = 800,
transition = 500,
easing = "circle",
redraw = TRUE,
mode = "immediate") %>%
animation_slider(
currentvalue = list(prefix = "PerĂodo", font = list(color="red"))
)
fig
Another more elegant solution would be to rely on ggplot2 + gganimate:
library(ggplot2)
library(gganimate)
ggplot(full_clock_db, aes(x = mom_increase, y = above_trend)) +
geom_point(aes(group = 1L)) +
transition_time(ref_date) +
shadow_wake(wake_length = 0.1, alpha = .6)
You cna play with different shadow_* functions to find the one to your liking.
One way would be to use a line plot and repeat points as necessary. Here's an example as POC:
library(dplyr)
library(plotly)
e <- tibble(x = seq(-3, 3, 0.01)) %>%
mutate(y = dnorm(x)) %>%
mutate(iter = 1:n())
accumulate <- function(data, by, trace_length = 5L) {
data_traf <- data %>%
arrange({{ by }}) %>%
mutate(pos_end = 1:n(),
pos_start = pmax(pos_end - trace_length + 1L, 1L))
data_traf %>%
rowwise() %>%
group_map(~ data_traf %>% slice(seq(.x$pos_start, .x$pos_end, 1L)) %>%
mutate("..{{by}}.new" := .x %>% pull({{by}}))) %>%
bind_rows()
}
enew <- e %>%
accumulate(iter, 100)
plot_ly(x = ~ x, y = ~ y) %>%
add_trace(data = e, type = "scatter", mode = "lines",
line = list(color = "lightgray", width = 10)) %>%
add_trace(data = enew, frame = ~ ..iter.new,
type = "scatter", mode = "lines") %>%
animation_opts(frame = 20, 10)
The idea is that for each step, you keep the trace_length previous steps and assign them to the same frame counter (here ..iter.new). Then you plot lines instead of points and you have a sort of trace..
I would like to draw plotly graphs with rangeslider (including start/end range), yet printing quarter dates on the X-axis, instead of the usual ymd format, as shown in the example below ; i.e. printing "Q1 2019" instead of "Jan 2019" :
library(plotly)
library(zoo)
d <- tibble::tibble(
time = as.yearqtr(seq(as.Date("2016-01-01"), as.Date("2020-08-31"), by = "quarters")),
y = rnorm(seq_along(time))
)
d$time <- as.Date(d$time, format = "%Y-%m-%d")
plot_ly(d, x = ~time, y = ~y) %>%
add_lines() %>%
rangeslider(d$time[10], d$time[19])
You can do this with layout using ticktext and tickvals. This is the code that will ensure you see years and quarters on the X-axis.
plot_ly(d, x = ~time, y = ~y) %>%
add_lines() %>%
rangeslider(d$time[10], d$time[19]) %>%
layout(xaxis = list(ticktext = paste0(c(rep(2018, 3),
rep(2019, 4),
rep(2020, 2)),
" Q",
c(2:4, 1)),
tickvals = d$time[10:18]
))
Using set.seed() makes the code repeatable, (since you used rnorm). I used set.seed(3958) if you wanted to see the same output.
Another way that you can customize the text is through the zoom level. Plotly references this site for the formatting here. There are a few examples on Plotly's website, as well. Check it out.
plot_ly(d, x = ~time, y = ~y) %>%
add_lines() %>%
rangeslider(d$time[10], d$time[19]) %>%
layout(xaxis = list(
tickformatstops = list(
list(dtickrange = list(NULL, "M1"),
value = "%Y %b"),
list(dtickrange = list("M1", "M6"),
value = "%Y Q%q"),
list(dtickrange = list("M6", NULL),
value = "%Y Y")
)))
I have the following dataset:
xdata <- seq(as.Date("2020-01-01"),as.Date("2020-12-31"), "days")
ydata <- c(1:366)
datamipo <- data.frame(xdata,ydata)
And I want to plot the data by month and plot using highcharter:
datamipo %>%
mutate(month = format(xdata,"%b")) %>%
group_by(month) %>%
summarise(total = sum(ydata)) %>%
hchart(type = "line",
hcaes(x=month, y=total))
But the x axis doesn't recognize the data as dates and put them in alphabetical order. Please, do you know how can I group the date to show the totals by month? Thank you.
I would think about saving this data differently and operate on the actual values. Here you can see an example of such a setting:
df <- data_frame(
time = seq(as.Date("2020-01-01"), as.Date("2020-02-01"), by = 1),
value = sample(1000:2000, size = 32),
dt = datetime_to_timestamp(time)
)
hchart(df, "line", hcaes(dt, value)) %>%
hc_xAxis(type = "datetime", dateTimeLabelFormats = list(day = '%d dayview', week = '%d weekview'))
hchart(df, "line", hcaes(dt, value)) %>%
hc_xAxis(type = "datetime", dateTimeLabelFormats = list(day = '%d of %b', week = '%d of %b'))
I am trying to draw line chart using Highchart . I need data format in Million format . Ex for the First point in screenshot 2423175 should be shown as 2.42 Million .How do i change format = "{point.y}" to show in Millions
highchart() %>%
hc_add_series(data, hcaes(x = data$Month, y = data$Total, color = data$Total), type = "line",dataLabels = list(
enabled = TRUE,
format = "{point.y} " )
) %>%
hc_tooltip(cros[![enter image description here][1]][1]shairs = TRUE, borderWidth = 1.5,headerFormat= "",
pointFormat = paste("Year: <b>{point.x:%b-%y}</b> <br> Population: <b>{point.y}</b>")) %>%
hc_title(text = "Population by year") %>%
hc_subtitle(text = "2016-2020") %>%
hc_xAxis(type = "datetime", title = list(text = "Year")) %>%
hc_yAxis(title = list(text = "count per year")) %>%
hc_legend(enabled = FALSE) %>%
hc_add_theme(custom_theme)
Here is a 2 step way of doing it:
First, you need to format your numbers from looking like 2423175 to 2.42 before you create your plot.
data$Total <- format(round(data$Total / 1e6, 1), trim = TRUE)
Next, in order to add 'Million' after your numbers in Highcharter, change format from format = "{point.y} " to format = paste("{point.y} Million") while creating your plot. Your numbers should now be displayed in the format "X.XX Million".
You can use dataLabels.formatter: https://api.highcharts.com/highcharts/series.line.dataLabels.formatter to format your dataLabels. I know how to do it in JavaScript and inject this code inside JS() function in R:
hc_add_series(data, hcaes(x = data$Month, y = data$Total, color = data$Total), type = "line",dataLabels = list(
enabled = TRUE,
formatter = JS("function() {
return (this.y / 1000000).toFixed(2) + 'M'
}") )
) %>%
JS example: https://jsfiddle.net/BlackLabel/o49zcjLv
Let me know if it worked.
Edit: The whole working code with sample data:
library(highcharter)
data <- data.frame(
y = c(54324232,85325324,10424324,44234324,74324234, 44321413))
highchart() %>%
hc_add_series(data, type = "line", hcaes(y = y), dataLabels = list(
enabled = TRUE,
formatter = JS("function() {
return (this.y / 1000000).toFixed(2) + 'M'
}"
)))
I was using Highchart to plot some time series and wanted to add some annotation to the plot to highlight some key points. I knew putting the cursor on the graph can pop up the context, however, some automatic graph generation is needed and hence annotating is the best approach.
And I did that, with the last line in the code below. However, the effect is not what I expected. The text was located at the bottom left corner, not located at the right horizontal position yet the vertical position is right. The time series are created using xts library, which means the horizontal axis is simply the date data structure, nothing fancy. xValue is specified as the 900th element of all the time points which have a total length of 1018, so the 900th time point must be in the second half of the graph.
Anyone knows how I can put the annotation at the right location? Many thanks.
hc <- highchart(type = "stock") %>%
hc_title(text = "Some time series") %>%
hc_add_series(x, color='green', name="x", showInLegend = TRUE) %>%
hc_add_series(y, color='red', name="y", showInLegend = TRUE) %>%
hc_add_series(z, color='blue', name="z", showInLegend = TRUE) %>%
hc_navigator(enabled=FALSE) %>%
hc_scrollbar(enabled=FALSE) %>%
hc_legend(enabled=TRUE, layout="horizontal") %>%
hc_annotations(list(enabledButtons=FALSE, xValue = index(x)[900], yValue = -5, title =list(text = "Hello world! How can I make this work!")))
hc
The data can be roughly generated using the following script:
dt <- seq(as.Date("2014/1/30"), as.Date("2018/2/6"), "days")
dt <- dt[!weekdays(dt) %in% c("Saturday", "Sunday")]
n <- length(dt)
x <- xts(rnorm(n), order.by=dt)
y <- xts(rnorm(n), order.by=dt)
z <- xts(rnorm(n), order.by=dt)
Let's star with the #kamil-kulig example, this will be a little out of R world but I want to give some justification if you don't mind.
If we see annotations options is not a object but a list of object(s), so in highcharter is implemented the hc_add_annotation function.
Now, you are using a old version of highcharter. Highcharter devlopment version is using v6 of highchartsJS which made some changes: before the annotations.js was a pluging now is included as a module with some changes in the names of arguments.
Example I: Simple
The example by Kamil Kulig is replicated doing:
highchart(type = "stock") %>%
hc_add_annotation(
labelOptions = list(
backgroundColor = 'rgba(255,255,255,0.5)',
verticalAlign = 'top',
y = 15
),
labels = list(
list(
point = list(
xAxis = 0,
yAxis = 0,
x = datetime_to_timestamp(as.Date("2017/01/02")),
y = 1.5
),
text = "Some annotation"
)
)
) %>%
hc_xAxis(
minRange = 1
) %>%
hc_add_series(
pointStart = start,
pointInterval = day,
data = c(3, 4, 1)
)
Example II: With your data
Be careful in the way you add the x position. Highcharter include a datetime_to_timestamp function to convert a date into a epoch/timestap which is required for highcharts.
library(xts)
dt <- seq(as.Date("2014/1/30"), as.Date("2018/2/6"), "days")
dt <- dt[!weekdays(dt) %in% c("Saturday", "Sunday")]
n <- length(dt)
x <- xts(rnorm(n), order.by=dt)
y <- xts(rnorm(n), order.by=dt)
z <- xts(rnorm(n), order.by=dt)
highchart(type = "stock") %>%
hc_title(text = "Some time series") %>%
hc_add_series(x, color='green', name="x", showInLegend = TRUE) %>%
hc_add_series(y, color='red', name="y", showInLegend = TRUE) %>%
hc_add_series(z, color='blue', name="z", showInLegend = TRUE) %>%
hc_navigator(enabled=FALSE) %>%
hc_scrollbar(enabled=FALSE) %>%
hc_legend(enabled=TRUE, layout="horizontal") %>%
hc_add_annotation(
labels = list(
list(
point = list(
xAxis = 0,
yAxis = 0,
x = datetime_to_timestamp(as.Date(index(x)[900])),
y = 1
),
text = "Hello world! How can I make this work!"
)
)
)