Update: Changing percentual change for 'PL Acumulada' series This is the new tooltip formatter:
hc_tooltip(split = T, crosshairs = T,
formatter = htmlwidgets::JS(
"function(tooltip) {
function pref(pts) { /* create y-axis tooltips with this function */
col = pts.color; y = pts.y; nm = pts.series.name; /* collect color, y, name */
compVal = pts.series.linkedSeries[0].dataModify.compareValue; /* 1st val in view */
compVal2 = compVal
delta = (y - compVal)/compVal * 100; /* compute the comparison value as HC does */
adder = `(${delta.toFixed(2)}%)</span>`; /* create remaining string for tooltip (percentagem)*/
y = Highcharts.numberFormat(y, 0, '.', ' '); /* format y after calc */
return `<b><span style='color:${col};'>● ${nm}:</span></b> ${y} ` + adder;
}
function pref2(pts) {
col = pts.color; y = pts.y; nm = pts.series.name; /* collect color, y, name */
compVal = compVal2
delta = y/compVal * 100; /* compute the comparison value as HC does */
adder = `(${delta.toFixed(2)}%)</span>`; /* create remaining string for tooltip (percentagem)*/
y = Highcharts.numberFormat(y, 0, '.', ' '); /* format y after calc */
return `<b><span style='color:${col};'>● ${nm}:</span></b> ${y} ` + adder;
}
xform = Highcharts.dateFormat('%B %e, %Y', this.x); /* x-axis tooltip formatted */
ttd1 = pref(this.points[0]); /* call function to create y-axis tooltips (AUM)*/
ttd2 = pref2(this.points[1]); /* call function to create y-axis tooltips (CUM NP)*/
return [xform, ttd1, ttd2]; /* send tooltip formatting (DATE, AUM, CUM NP*/
}")
) %>%
As you can see, 24 657 / 49 036 799 (first value in view of 'AUM' line) *100% = 0.05%
################################ Original question #############
I have two datasets: data and data2. Both of these have two columns (one has dates and the other has values).
Datasets:
data <- structure(list(DATA = structure(c(19327, 19328, 19331, 19332,
19333, 19334, 19335, 19338, 19339, 19340, 19341, 19342, 19345,
19346, 19347, 19348, 19349), class = "Date"), AUM = c(32962594L,
33213220L, 33278745L, 33482196L, 33591402L, 33591402L, 33660796L,
33810382L, 34172853L, 34264748L, 34032274L, 34216610L, 34416588L,
34462226L, 35308681L, 35429483L, 35456650L)), row.names = c(NA,
-17L), class = "data.frame")
data2 <- structure(list(DATA = structure(c(19327, 19328, 19331, 19332,
19333, 19334, 19335, 19338, 19339, 19340, 19341, 19342, 19345,
19346, 19347, 19348, 19349), class = "Date"), CUM_SUM = c(0L,
173080L, 318158L, 504538L, 607304L, 607304L, 771404L, 916984L,
1153354L, 1292314L, 1381434L, 1708534L, 1937284L, 2035272L, 2817863L,
3046949L, 3046949L)), row.names = c(NA, -17L), class = "data.frame")
I want to present a graph that not only shows the values progression, but also, for every point, indicates the % change to the first value. I also want the y_axis to be the points values and not the % change. My present graph shows for one series (data) the % change, but the y_axis is not in the desired format. Instead of the % changes, I want to see the values.
This is my graph code:
highchart() %>%
hc_yAxis_multiples(list(title = list(text = "data"), opposite = FALSE),
list(showLastLabel = FALSE, opposite = TRUE, title = list(text = "data2"))) %>%
hc_add_series(name = "data", yAxis = 0, id = "data_line", data = data, hcaes(x = DATA, y = AUM), type = 'line', compare = 'percent') %>%
hc_add_series(name = 'data2', yAxis = 1, id = 'data2_line', data = data2, hcaes(x = DATA, y = CUM_SUM), type = 'line') %>%
hc_xAxis(type = "datetime") %>%
hc_plotOptions(column = list(dataLabels = list(enabled = F),enableMouseTracking = T)) %>%
hc_chart(zoomType = 'xy') %>%
hc_colors(c("#336600","#990000")) %>%
hc_tooltip(pointFormat = '<span style="color:{series.color}">{series.name}</span>: <b>{point.y}</b> ({point.change} %)<br/>',
split = TRUE, crosshairs = TRUE) %>%
hc_exporting(enabled = TRUE)
And this is the graph that results from the code:
As you can see, the left y_axis is not in the desired format.
One option is removing the legend click event, which seems counterintuitive. Control is one of the many things that make these charts useful. Instead, I've modified the click event for the trace that is linked to the hidden trace. Check it out.
Now when you click the Data Values ($)
item in the legend, it essentially ignores the legendItemClick
event and updates the visibility independently.
#----------------- with modified number formatting &&& SPLIT tooltips ------------------
# added an event to ensure visibility doesn't change on invisible series
highchart() %>% # three y-axes with min/max scaling
hc_add_series(data, type = "line", name = "Data Values ($)",
compare = F, id = 'dv',
hcaes(x = DATA, y = AUM),
events = list(
legendItemClick = htmlwidgets::JS(
"function(e) {
var shown = this.visible ? false : true;
this.update({visible: shown});
return false;
}"
))) %>%
hc_add_series(data, type = "line", name = "Data Values ($)",
compare = 'percent', linkedTo = 'dv', visible = F, # <-- linked & invisible!
hcaes(x = DATA, y = AUM)) %>%
hc_add_series(data2, type = "line", name = "Data2", compare = F,
hcaes(x = DATA, y = CUM_SUM), yAxis = 1) %>%
hc_yAxis_multiples(list(title = list(text = "Data Values ($)"), opposite = F),
list(title = list(text = "Data2"), opposite = T)) %>%
hc_chart(zoomType = 'xy') %>%
hc_colors(c("#336600","#336600","#990000")) %>% # added first color 2x for invisible axis
hc_tooltip(split = T,
formatter = htmlwidgets::JS(
"function(tooltip) {
function pref(pts) { /* create y-axis tooltips with this function */
col = pts.color; y = pts.y; nm = pts.series.name; /* collect color, y, name */
if(nm != 'Data2'){
compVal = pts.series.linkedSeries[0].dataModify.compareValue; /* 1st val in view */
delta = (y - compVal)/compVal * 100; /* compute the comparison value as HC does */
adder = `(${delta.toFixed(2)}%)</span>`; /* create remaining string for tooltip */
} else {
adder = ''; /* if data2, there are no calculations to add */
}
y = Highcharts.numberFormat(y, 0, '.', ' '); /* format y after calc */
return `<b><span style='color:${col};'>● ${nm}:</span></b> ${y} ` + adder;
}
xform = Highcharts.dateFormat('%B %e, %Y', this.x); /* x-axis tooltip formatted */
ttd1 = pref(this.points[0]); /* call function to create y-axis tooltips */
ttd2 = pref(this.points[1]);
return [xform, ttd1, ttd2]; /* send tooltip formatting */
}")) %>%
hc_exporting(enabled = TRUE) %>%
hc_xAxis(type = "datetime")
In comments, I wrote that you could replace the y
declaration in the JavaScript with y = Highcharts.numberFormat
ter
(this.y, 0, '.', ' ');
There are a few things wrong here. First, it's Highcharts.numberFormat
<- (no ter
at the end). Sorry about that. If that's all it was, I would have added another comment. However, that leads to a few other issues that I didn't account for with that not-great bit of information. So to rectify that and to address your other comment about splitting the tooltips, I've added the following information.
Here's the plot I provided originally, without split tooltips but with formatted values. I've changed 3: things. y
, delta
, and how y
is called in the string tooltip
.
In delta
, I've changed y
to this.y
. (The line immediately following y = Highcharts...
is the line that creates delta
.)
In tooltip
, I've removed toFixed()
from ${y}
.
#----------------- with modified number formatting ------------------
highchart() %>% # three y-axes with min/max scaling
hc_add_series(data, type = "line", name = "Data Values ($)",
compare = F, id = 'dv',
hcaes(x = DATA, y = AUM)) %>%
hc_add_series(data, type = "line", name = "Data Values ($)",
compare = 'percent', linkedTo = 'dv', visible = F, # <-- linked & invisible!
hcaes(x = DATA, y = AUM)) %>%
hc_add_series(data2, type = "line", name = "Data2", compare = F,
hcaes(x = DATA, y = CUM_SUM), yAxis = 1) %>%
hc_yAxis_multiples(list(title = list(text = "Data Values ($)"), opposite = F),
list(title = list(text = "Data2"), opposite = T)) %>%
hc_chart(zoomType = 'xy') %>%
hc_colors(c("#336600","#336600","#990000")) %>% # added first color 2 times to account for invisible axes
hc_tooltip(
formatter = htmlwidgets::JS(
"function(tooltip) {
/* collect name, x (and format it), y, color, compare value, and % difference */
nm = this.series.name;
if(nm == 'Data2') { /* use standard tooltip for data2 */
return tooltip.defaultFormatter.call(this, tooltip);
}
xform = Highcharts.dateFormat('%B %e, %Y', this.x); /* collect/format date */
compVal = this.series.linkedSeries[0].dataModify.compareValue; /* 1st val in view */
col = this.color; /* set color and y to vars */
y = Highcharts.numberFormat(this.y, 0, '.', ' '); /* <<---- I'm new!! */
delta = (this.y - compVal)/compVal * 100; /* compute the comparison value as HC does */
tooltip = `<span>${xform}<br><hr><b><span style='color:${col};'>`; /* create tooltip */
tooltip += `● ${nm}:</span></b> ${y} (${delta.toFixed(2)}%)</span>`;
return tooltip; /* send back new tooltip */
}")) %>%
hc_exporting(enabled = TRUE) %>%
hc_xAxis(type = "datetime")
If you follow the JavaScript, when the tooltips are not split, you see that one string was returned. This string was created using multiple variables preceded by this
.
When you split the tooltips, each plotted trace has an index in this.points
. Additionally, you need to return a string for each item in the split. In your graph, you have 1 x-axis item and 2 y-axis items, so you need to return 3 strings.
#----------------- with modified number formatting &&& SPLIT tooltips ------------------
highchart() %>% # three y-axes with min/max scaling
hc_add_series(data, type = "line", name = "Data Values ($)",
compare = F, id = 'dv',
hcaes(x = DATA, y = AUM)) %>%
hc_add_series(data, type = "line", name = "Data Values ($)",
compare = 'percent', linkedTo = 'dv', visible = F, # <-- linked & invisible!
hcaes(x = DATA, y = AUM)) %>%
hc_add_series(data2, type = "line", name = "Data2", compare = F,
hcaes(x = DATA, y = CUM_SUM), yAxis = 1) %>%
hc_yAxis_multiples(list(title = list(text = "Data Values ($)"), opposite = F),
list(title = list(text = "Data2"), opposite = T)) %>%
hc_chart(zoomType = 'xy') %>%
hc_colors(c("#336600","#336600","#990000")) %>% # added first color 2 times to account for invisible axes
hc_tooltip(split = T,
formatter = htmlwidgets::JS(
"function(tooltip) {
function pref(pts) { /* create y-axis tooltips with this function */
col = pts.color; y = pts.y; nm = pts.series.name; /* collect color, y, name */
if(nm != 'Data2'){
compVal = pts.series.linkedSeries[0].dataModify.compareValue; /* 1st val in view */
delta = (y - compVal)/compVal * 100; /* compute the comparison value as HC does */
adder = `(${delta.toFixed(2)}%)</span>`; /* create remaining string for tooltip */
} else {
adder = ''; /* if data2, there are no calculations to add */
}
y = Highcharts.numberFormat(y, 0, '.', ' '); /* format y after calc */
return `<b><span style='color:${col};'>● ${nm}:</span></b> ${y} ` + adder;
}
xform = Highcharts.dateFormat('%B %e, %Y', this.x); /* x-axis tooltip formatted */
ttd1 = pref(this.points[0]); /* call function to create y-axis tooltips */
ttd2 = pref(this.points[1]);
return [xform, ttd1, ttd2]; /* send tooltip formatting */
}")) %>%
hc_exporting(enabled = TRUE) %>%
hc_xAxis(type = "datetime")
In case your number formatting choices are not as I specified, here are the arguments:
Highcharts.numberFormat(value, decimalPlaces, decimalPoint, thousandsSeparator);
When you set the series named data
to the left, you told Highcharts to make the y-axis percentages. However, even if you manipulate the axes to present the actual stock values, Highcharts will still graph the dates on the x-axis and the % on the y-axis.
Your % comp value plotted line will not match that $ y-axis.
I tried to think of a way to articulate better what I mean and why you won't be able to do what you're trying to do... I took stock values and created mock comparison values based on a few ranges (to simulate various zoom settings and how compare
changes).
You'll see that the stock value might go up, but that doesn't mean that the compare
value goes up. You'll also see that the values change depending on where you zoom. You would have to have infinite rescaling of the $ axis to align with the % axis.
Here's the code to make the plot and the plot I've mentioned that outlines the issue.
library(highcharter)
library(quantmod)
# get stock info
goo <- getSymbols("GOOG", auto.assign = F)
# frame data for building comparison values
df1 <- data.frame(dt = seq.Date(from = as.Date("2020-01-01"),
length.out = 300, by = "day"),
goo$GOOG.Open[1001:1300]) %>%
setNames(c("dt", "val"))
# four sets of comparison values
df1$fromO <- c(NA, ((df1$val - df1[1, ]$val)/df1[1, ]$val)[-1])
df1$from100 <- c(rep(NA, 100), ((df1$val - df1[100, ]$val)/df1[100, ]$val)[101:300])
df1$from200 <- c(rep(NA, 200), ((df1$val - df1[200, ]$val)/df1[200, ]$val)[201:300])
df1$btw150250 <- c(rep(NA, 150), ((df1$val - df1[150, ]$val)/df1[150, ]$val)[151:250], rep(NA, 50))
df1[, 3:6] <- df1[,3:6] * 100 # get % value
# visualize the issue with plotting comp value but labeling it with the $
highchart() %>%
hc_add_series(df1, type = "line", name = "Original Data",
hcaes(x = dt, y = val)) %>%
hc_add_series(df1, type = "line", name = "100-300 Days",
hcaes(x = dt, y = from100), yAxis = 1) %>%
hc_add_series(df1, type = "line", name = "200-300 Days",
hcaes(x = dt, y = from200), yAxis = 1) %>%
hc_add_series(df1, type = "line", name = "Between 150-250 Days",
hcaes(x = dt, y = btw150250), yAxis = 1) %>%
hc_xAxis(type = "datetime") %>%
hc_yAxis_multiples(list(opposite = F, title = list(text = "Stock Value ($)")),
list(opposite = T, title = list(text = "Comparative (%)")))
Instead of what you proposed, you could plot the dates and values and have something like a tooltip or label that presents the comparison value. Alternatively, you could plot the data and the comparison value using opposing y-axes. However, if you do that, it won't work with your data2
.
Why won't that work with data2
?
A picture answers this a lot faster:
If you have 2 axes, one of the three will essentially be a flat line.
If you have 3 axes, you may be able to align them initially.... check it out:
# new range for values axes (align to compare and data2)
low <- min(data$AUM)
high <- max(data$AUM)
# determine 'equivalent to 10' to match scale, using 0-7.57 as old scale
newH <- round(10 * (high - low)/7.57 + low, 0)
newI <- round((newH - low)/5, 0) # new interval of axes
highchart() %>% # three y-axes with min/max scaling
hc_add_series(data, type = "line", name = "Data Values ($)",
compare = F,
hcaes(x = DATA, y = AUM)) %>%
hc_add_series(data, type = "line", name = "Date Compare (%)",
compare = "percent", yAxis = 1,
hcaes(x = DATA, y = AUM)) %>%
hc_add_series(data2, type = "line", name = "Data2", compare = F,
hcaes(x = DATA, y = CUM_SUM), yAxis = 2) %>%
hc_yAxis_multiples(list(opposite = F, #min = low, max = newH, tickInterval = newI,
tickInterval = newI, min = low,
breaks = list(breakSize = 1,
from = 0, to = low),
title = list(text = "Value ($)")),
list(opposite = T, min = 0, max = 10, # used previous plot scale
title = list(text = "Compare (%)")),
list(opposite = F, min = 0, max = 4000000, # used prev plot scale
title = list(text = "Data2"))) %>%
hc_xAxis(type = "datetime")
Here's ONE random zoom... see that the values no longer align.
You can see here that the plotting of the
compare
series does not align with the values on the values axes.
Like a previous Q&A, I suggest you use tooltips to garnish and present the comp values and plot the actual values.
This uses your data and the features you specifically identified in your chart. However, it plots the values, hides the compare
line, and adds the comp line data to the tooltips for the values.
For data2
, I used the default tooltip.
Here's the code to make that plot.
highchart() %>% # three y-axes with min/max scaling
hc_add_series(data, type = "line", name = "Data Values ($)",
compare = F, id = 'dv',
hcaes(x = DATA, y = AUM)) %>%
hc_add_series(data, type = "line", name = "Data Values ($)",
compare = 'percent', linkedTo = 'dv', visible = F, # <-- linked & invisible!
hcaes(x = DATA, y = AUM)) %>%
hc_add_series(data2, type = "line", name = "Data2", compare = F,
hcaes(x = DATA, y = CUM_SUM), yAxis = 1) %>%
hc_yAxis_multiples(list(title = list(text = "Data Values ($)"), opposite = F),
list(title = list(text = "Data2"), opposite = T)) %>%
hc_chart(zoomType = 'xy') %>%
hc_colors(c("#336600","#336600","#990000")) %>% # added first color 2 times to account for invisible axes
hc_tooltip(
formatter = htmlwidgets::JS(
"function(tooltip) {
/* collect name, x (and format it), y, color, compare value, and % difference */
nm = this.series.name;
if(nm == 'Data2') { /* use standard tooltip for data2 */
return tooltip.defaultFormatter.call(this, tooltip);
}
xform = Highcharts.dateFormat('%B %e, %Y', this.x); /* collect/format date */
compVal = this.series.linkedSeries[0].dataModify.compareValue; /* 1st val in view */
col = this.color; y = this.y; /* set color and y to vars */
delta = (y - compVal)/compVal * 100; /* compute the comparison value as HC does */
tooltip = `<span>${xform}<br><hr><b><span style='color:${col};'>`; /* create tooltip */
tooltip += `● ${nm}:</span></b> ${y.toFixed(0)} (${delta.toFixed(2)}%)</span>`;
return tooltip; /* send back new tooltip */
}")) %>%
hc_exporting(enabled = TRUE)