I have a plotly.js graph with multiple subplots that share an x-axis as in https://plot.ly/javascript/subplots/#stacked-subplots-with-a-shared-x-axis
I'm trying to hover across all of the subplots so that the values of all of the points with the same x value are displayed at once.
I've attempted to solve this by calling Plotly.Fx.hover on each subplot, but it only seems to take effect for the last subplot on which it is called.
http://codepen.io/john-soklaski/pen/adQwBa
The code I tried is:
Plotly.Fx.hover('myDiv', {xval: 2, curveNumber: 0}, "xy")
Plotly.Fx.hover('myDiv', {xval: 2, curveNumber: 1}, "xy2")
Ideally the API would be such that I could do this in a single call:
Plotly.Fx.hover('myDiv', [{xval: 2, curveNumber: 0, subplot: "xy"}, {xval: 2, curveNumber: 1, subplot: "xy2"}])
Any thoughts on how to get this to work?
I see this question is old, but this functionality has been added: https://github.com/plotly/plotly.js/pull/301
Plotly.plot('myDiv', data, layout);
graph = document.getElementById('myDiv');
graph.on('plotly_hover', function(eventdata) {
if (eventdata.xvals) {
Plotly.Fx.hover(graph, {
xval: eventdata.xvals[0]
}, ['xy', 'x2y2', 'x3y3', 'x4y4']);
}
});
For multiple subplots add the axis labels array also.
In this case
['xy', 'x2y2', 'x3y3', 'x4y4']
In this way you can get coupled hover events for subplots in a div
You'll have to pass the visible subplots as the third arg to Plotly.Fx.hover func.
This worked for me:
chartContainer.current.on('plotly_hover', function () {
var points = eventdata.points[0]
var pointNum = points.pointNumber
Plotly.Fx.hover(
chartContainer.current,
props.data.map((_, i) => ({
curveNumber: i,
pointNumber: pointNum
})),
Object.keys((chartContainer.current)._fullLayout._plots))
})
chartContainer.current is the div here.
Object.keys((chartContainer.current)._fullLayout._plots) will return the visible plots, for example: ['xy', 'xy2'...]
Related
I've already figured out how to make a chart using highcharts where there are three variables- one on the X axis, one on the Y axis, and one on the tooltip. The way to do this is to add the following to the tooltip:
tooltip: {
formatter () {
// this.point.x is the timestamp in my original chartData array
const pointData = chartData.find(row => row.timestamp === this.point.x)
return pointData.somethingElse
}
}
See this fiddle for the full code:
https://jsfiddle.net/m9e6thwn/
I would simply like to do the same, but with two series instead of one. I can't get it to work. I tried this:
tooltip: {
formatter () {
// this.point.x is the timestamp in my original chartData array
const pointData = chartData1.find(row => row.timestamp === this.point.x)
return pointData.somethingElse
const pointData2 = chartData2.find(row => row.timestamp === this.point.x)
return pointData2.somethingElse
}
}
Here is the fiddle of the above: https://jsfiddle.net/hdeg9x02/ As you can see, the third variable only appears on one of the two series. What am I getting wrong?
There are some issues with the way you are using the formatter now. For one, you cannot have two returns in the same function without any if clauses. That will mean that only the first return will be used.
Anyway, here are some improvements I suggest you do for your code.
Add the extra information for each point to highcharts, that makes it a lot easier to access this information through highcharts. E.g. in a tooltip. You can set the data like this:
chartData1.map(function(row) {
return {
x: row.timestamp,
y: row.value,
somethingElse: row.somethingElse
}
})
If you do that, then returning the correct tooltip for each series is a simple matter of doing this:
tooltip: {
formatter () {
// this.point.x is the timestamp in my original chartData array
return this.point.somethingElse
}
}
Working JSFiddle example: https://jsfiddle.net/ewolden/dq7L64jg/6/
If you wanted more info in the tooltip you could then do:
tooltip: {
formatter () {
// this.point.x is the timestamp in my original chartData array
return this.point.somethingElse + ", time: " + str(this.x) + ", value: " + str(this.y)
}
}
Addtionally, you need to ensure that xAxis elements, i.e. your timestamps are sorted. This is a requirement for highcharts to function properly. As it is, your example is reporting
Highcharts error #15: www.highcharts.com/errors/15
in console, because chartData2 is in reverse order. It looks okay for this example, but more complicated examples can lead to the chart not looking as you expect it to.
For this example using reverse is easy enough: data: chartData2.reverse().map(function(row) {return {x: row.timestamp, y: row.value, somethingElse: row.somethingElse}})
Working JSFiddle example: https://jsfiddle.net/ewolden/dq7L64jg/7/
The issue is that the percentage area function does not seem to work when a datetime series is missing a datapoint for some t.
E.g. removing
{
x: new Date("2008-10-31T00:00:00.000Z"),
y: 0,
drilldown: 'my_drilldown'
}
from the series in http://jsfiddle.net/qtoas0jg/3/, giving http://jsfiddle.net/qtoas0jg/4/.
The expected/desired behaviour is that the area should fill for all times t. After going through the documentation I conclude that connectNulls:false, also using step:"left" I can achieve the desire behaviour for one series, the one holding values for all t, but then again not for the second series.
Any ideas?
EDIT:
I was not able to solve the issue using Highcharts functionality. Instead I (quite unrigiously) manipulated the series that I put in by adding value 0 for the missing t. If someone stumbles apon this issue, the following might be useful:
let asd = []
// Firstly finding which t:s that need to be added for respective series
let to_be_added = series.map(arg_a => {
return([arg_a.name,arg_a.data.reduce((acc_b,arg_b) => {
// Adding all available t:s
(asd.indexOf(arg_b.x.toString())>=0?0:asd.push(arg_b.x.toString()))
acc_b.push(arg_b.x.toString())
return acc_b
},[])])
}).map(arg_a => {
return [arg_a[0],asd.filter(arg_b => arg_a[1].indexOf(arg_b)<0)]
})
// Adding the new timestamps with y:0
to_be_added.map(arg_a => {
series.map((arg_b,ind) => {
if (arg_b.name == arg_a[0]) {
arg_a[1].reverse().map(arg_c => {
series[ind].data.unshift({x:new Date(arg_c),y:0})
})
}
})
})
This problem is caused by Highcharts bug: https://github.com/highcharts/highcharts/issues/5634
To workaround use timestamps instead of Date object:
data: [{
x: new Date("2008-10-31T00:00:00.000Z").getTime(),
...
}, ...]
Live demo: http://jsfiddle.net/BlackLabel/0wr3kvt1/
I created a scatter chartlike this in the JSfiddle (http://jsfiddle.net/q8h39/102/)
which is doing two dimension data analysis.
but I need to contain some extra information (e.g: custom names and a extra count value) in the chart** and give different color for each of the plots.
I tried to create an Array and use the tooltip library like this but i didn't reach the goal yet still.
var nameArr = ['anson','jason','samson','dickson']; // Names
tooltip: {
format: {
title: function (d) { return nameArr; },
}
}
Please see the JSfiddle code for further details, many thanks
The below is the current result and the exception exception after development
i have gone through the jsfiddle link and there were two issue with this:-
c3js library is old
c3js does not provide this functionality out of the box but you can achieve this using trick.
I have fixed both of above given issues and now it is working fine.
jsfiddle:-
http://jsfiddle.net/q8h39/109/
code for setting the tooltip:-
tooltip: {
format: {
title: function(x) {
var indOfVal = engagmentArr.indexOf(x);
return nameArr[indOfVal - 1]
},
name: function() {
return engagmentArr[0];
}
},
},
There does not seem to be any option or implementation on showing the tooltip for a second or two before it dissapears when going from a hovering to non-hovering state. So when you have your mouse hovering over the tooltip, great, it shows but then when you remove your mouse from the point I would like to have that showing for an extra 2 seconds instead of dissapearing instantly as it does currently.
What I've done so far
I've looked through the documentation and the available tooltip options. It has a customTooltip function available but that is for when you want to implement a completely custom tooltip.
Gone through the chart.js line chart's codebase where it attaches the events and can't seem to figure out how to add in a delay.
Seen the 'mouseout', 'mouseover' events array list of strings but can't seem to figure out how to use them.
Can someone please point me in the right direction as to what I need to do on implementing this delay/fade effect on the tooltip.
The tooltips are cleared by the showTooltip function (the redraw clears off the existing tooltips). So one naïve way would be to hook into this to introduce your delay, like so
var data = {
labels: ['A', 'B', 'C', 'D', 'E', 'F', 'G'],
datasets: [
{
data: [12, 23, 23, 43, 45, 12, 33]
}
]
};
var ctx = document.getElementById("myChart").getContext("2d");
var myLineChart = new Chart(ctx).Line(data);
var originalShowTooltip = myLineChart.showTooltip;
var timeout;
myLineChart.showTooltip = function (activeElements) {
var delay = (activeElements.length === 0) ? 2000 : 0;
clearTimeout(timeout);
timeout = setTimeout(function () {
originalShowTooltip.call(myLineChart, activeElements);
}, delay);
}
This delays the tooltips if the chart is going to clear off all tooltips.
Notice that there is no delay in removing the old tooltip if you move on to another tooltip. If you want it this to be a delayed disappearance, you'll need to maintain your own array of active points pushing in elements (instantaneously) / popping out elements (with a delay)
Fiddle - http://jsfiddle.net/zubynd0c/
I'm being able to use JQuery Flot, and it's a very nice tool. However, I could not find a GOOD solution for my problem.
I want to duplicate Y axis, so I can display 1 on the left and 1 on the right, so the users, when comparing data from the rightmost side of the chart, won't have to scroll through the leftmost side of the chart. I'm assuming they will be accessing it through a smartphone.
JQuery Flot allows multiple axis, but for each axis, I would need a different set of data, as in this example:
http://people.iola.dk/olau/flot/examples/multiple-axes.html
But I don't want to duplicate the data. Can't I just 'tell' Flot to duplicate the yaxis using the same set of data?
You can use the hooks functionality to force flot to show the second yaxis even though it has no data series assigned to it:
// hook function to mark axis as "used"
// and assign min/max from left axis
pOff = function(plot, offset){
plot.getYAxes()[1].used = true;
plot.getYAxes()[1].datamin = plot.getYAxes()[0].datamin;
plot.getYAxes()[1].datamax = plot.getYAxes()[0].datamax;
}
$.plot("#placeholder2", [ { data: d2 } ], {
hooks: { processOffset: [pOff] },
yaxes: [ {},
{position: 'right'} // add second axis
]
});
Depending on how your axis is configured though, this might be messy. You'll have to steal parameters from the left axis to get it to work (as I've done above with datamin/datamax).
If it was my code, I'd go with your duplicate data approach. You aren't really duplicating anything, just assigned the same array to two series. I'd then configure the 2nd series to simply not draw.
var d2 = [[0, 3], [4, 8], [8, 5], [9, 13]];
// use the same data but toggle off the lines...
$.plot("#placeholder", [ { data: d2 }, {data: d2, yaxis: 2, lines: {show: false}} ], {
yaxes: [ {},
{position: 'right'} ]
});
Here's a fiddle demonstrating the two approaches.