I found this live updating time series chart and I’m trying to add a simple feature. I want to add a vertical line where the lowest point on the chart is. I found some code to add a vertical line but I’m not sure how to approach finding the lowest point and than updating the chart. look at this Fiddle, I’m feel like I'm pretty close.
Highcharts.js code to add vertical line
xAxis: {
type: 'datetime',
tickPixelInterval: 150,
plotLines: [{ // this code adds a vertical line
color: '#FF0000', // Red
width: 2,
value: (new Date).getTime() // Position, you'll have to translate this to the values on your x axis
}]
},
This was a truly worthy question that I enjoyed researching. I did some sleuthing and discovered a way to add a plotline whenever the lowest value to date in the time series is generated.
First, I set a variable called lowestValue outside of your chart options. This variable will be used and checked as new points are added to the series.
// make the initial value higher that the possible maximum y value
var lowestValue = 10;
Next, I added some code to your chart events that checks to see whether the new y value that's generated is lower than the current value of lowestValue. If it is, we'll add a new plot line affixed to that point.
I also added code to remove the last plot line that was created (if there was one) to clearly show which point has the lowest value thus far. The key to doing this is to give the plot line you're adding a consistent id. This way, the removePlotLine() function knows which one to remove.
events: {
load: function () {
// set up the updating of the chart each second
var series = this.series[0];
setInterval(function () {
var x = (new Date()).getTime(), // current time
y = Math.random();
series.addPoint([x, y], true, true);
// if the most recent point is lower than
// the last recorded lowest value, add a
// new plotline
if (y < lowestValue) {
lowestValue = y;
var plotOption = {
color: '#FF0000',
width: 2,
value: x,
zIndex: 0,
id: 'thisPlotLine'
};
// remove the previous plot line
series.xAxis.removePlotLine('thisPlotLine');
// add the new plot line
series.xAxis.addPlotLine(plotOption);
}
}, 1000);
}
}
I modified your fiddle to show these changes: http://jsfiddle.net/brightmatrix/pnL6xtLb/2/
Now, you'll notice that, over time, your plot lines may appear more infrequently as the value of lowestValue gets closer to 0. If you'd rather show the lowest value among the points visible in the chart at any given time, I'd suggest adding a counter that keeps track of the number of points that have been added since the last plot line was added. Then, if the lowest point (with its plot line) is moved off the chart, reset lowestValue back to 10 so the lowest visible point is the one that gets the plot line.
I hope this information is helpful to you!
Related
I am having problems controlling the Y-Axis range of a highcharts graph. It seems like highcharts likes nice round numbers. When my data passes or is close to certain thresholds, the Y-Axis range can expand a lot which effectively compresses all the plot points downward.
Here is a jsfiddle that illustrates the problem I am having:
https://jsfiddle.net/shannonwrege/z8h5eork
The relevant code for this post is this:
chart.yAxis[0].setExtremes(0, max, true, false);
Keep in mind that I don't know what the data will look like in advance, so I must dynamically modify the Y-Axis range. Right now I am using the setExtremes because of other suggestions I've read on stackoverflow.
The maximum y-value of the data in the first two charts is 99. You'll notice that the y-axis is set at 150 in the first chart where the range is automatically calculated and 100 in the second chart where I specifically set the extreme values. The look of the 2nd chart is what I want. So it seems like setExtremes(0,99,true,false) should do the trick, but it actually doesn't.
In the 3rd chart I changed the data so that the maximum y-value of the data is 101, and I called setExtremes(0,101,true,false). You'll note that the y-axis is now back to 150.
Ideally I want the scale of the graph to be capped on the maximum value to limit the about of extra white space. I want to see all of the data, but I don't necessarily care about the y-axis displaying a maximum band that is greater than the max data value. In this case, I would be happy with the y-axis displaying 100 on the axis and some points over but still visible.
Does anyone know how to make this work?
I ended up using the endOnTick parameter to solve this problem. Adding the following line to the yAxis configuration parameters did exactly what I wanted:
endOnTick: false,
Here's the updated Fiddle showing the results.
https://jsfiddle.net/shannonwrege/z8h5eork/3/
All of the charts look pretty good in my opinion (even the one where the yAxis range was auto calculated).
You will need to read the data and then round up to set the idealMax
var chart,
idealMax = 0; // init the max value
// Read the data to find the highest value
for (i=0;i < (options.series[0].data).length; i++ ){
if (options.series[0].data[i][1] > idealMax) {
idealMax = options.series[0].data[i][1];
}
}
// Round the max to the nearest 10
idealMax = Math.round(idealMax / 10) * 10;
options.yAxis.tickPixelInterval = idealMax/10;
Highcharts.chart('container1', options);
chart = $('#container1').highcharts();
chart.yAxis[0].setExtremes(0, idealMax, true, false);
Updated Fiddle
I have a bar chart in c3js that uses category ticks on the x-axis.
The tick values I want to display are set upon loading the chart:
axis: {
x: {
tick:{
rotate: -35,
values: getTicks(displayData), //Return the tick values
multiline:false
},
type: 'categorized'
}
}
The reason for setting the ticks manually on load, is I need to update them later.
I need to allow users to update the x axis range dynamically, without loading new data, and I want the number of ticks displayed to remain the same, but with different values obviously.
To change the x axis range, I use this function:
chart.axis.range({min: {x: minRange}, max: {x: maxRange}});
There is no function called chart.axis.values.
Any ideas on how to change tick values dynamically?
EDIT -
To be really clear, I do not wish to update the chart's values. That includes the x and y axis values. I only wish to change what ticks are displayed.
Something like this should work.
axis: {
x: {
type: 'timeseries',
tick: {
values: function(x) { return customTicks(x) },
format: function(x) { return customFormat(x); },
}
}
}
customTicks() must return an array of Dates for this to work.
function customTicks(x) {
start = x[0];
end = x[1];
result = [];
for (var i = new Date(start); i <= end; i.setDate(i.getDate() + 1)) {
result.push(new Date(i));
}
return result;
}
customFormat() takes the date and returns the string for that date. This gives you the flexibility to customize the format as needed.
function customFormat(x) {
}
It may not be particularly elegant but does the job. One benefit of this approach is that you can use the same functions on more than one chart and they will all exhibit identical behavior always.
Problem #1 with this approach is that it seems to call customTicks() for every data point just as it does for customFormat().
Problem #2 is that it generates a lot of these errors:
d3.v3.min.js:1 [Violation] Added non-passive event listener to a scroll-blocking 'touchstart' event. Consider marking event handler as 'passive' to make the page more responsive. See https://www.chromestatus.com/feature/5745543795965952
This has already been flagged on Stackoverflow at Added non-passive event listener to a scroll-blocking 'touchstart' event
I am having the same difficulty updating the Y-Axis ticks values dynamically. I searched through the c3.js documents and was expecting to get something like chart.axis.values similar to chart.axis.range or chart.axis.max / chart.axis.min.
After digging into the Chart object on the console. I somehow managed to resolve my problem, but with a bit hacky way.
Please check the fiddle, I have played with the chart.internal which contains the chart's values on which graph is plotted. I changed those values and used chart.flush() method to redraw the chart.
According to https://github.com/c3js/c3/issues/827:
chart.internal.config.axis_x_tick_values = getTicks(displayData);
This works for me.
Take this scenario from a graph I'm working on at the moment:
The problem I'm having is in the bottom left. My dataset's first coordinate is defined at approximately (60,5), yet the domain I'm looking to cover extends right down to 0. Is there any way I can get d3 to extrapolate this data to my origin? I've browsed the API but nothing clearly stands out.
I'm well aware I could just .push a new object with coordinates (0,0) onto my dataset array, but I would prefer not to as I may need to do manipulation with my data later, making this an undesirable option.
Since you have not provided a fiddle i chose to put up a small fiddle to explain this:
My Data set is like this:
data = [{
xval: 10,
yval: 100
}, {
xval: 40,
yval: 90
}, {
xval: 50,
yval: 12
}, {
xval: 90,
yval: 70
}]
You can see the values of x and y value varies from 0 to 100.
So you will define the range like:
x.domain([0, 100]);//this will show x axis start from 0
y.domain([0,100]);//this will show y axis start from 0
example here:
as per your requirement you want the y axis to start from 10 so you do
x.domain([0, 100]);//this will show x axis start from 0
y.domain([10,100]);//this will show y axis start from 10
example here
Hope this solves your problem. ..:)
You can also adjust your data domain to the maximum and the minimum using the extent function that d3 provides.
var x_domain = d3.extent(data,function(d){return d.xval});
var y_domain = d3.extent(data,function(d){return d.yval});
x.domain(x_domain);
y.domain(y_domain);
That way the graph will always be adjusted to the data domain in both coordinates whatever data comes.
Watch this working.
Well, I found an answer to my own question here.
d3 will never extend a line beyond the final data point.
The solution is the following:
If your really must have the line start and end at the very end of your range, then you have two options:
Create a custom interpolation function; or,
Add an "end-value" data point when you pass your data array to d3.svg.line.
For me, it looks like I'm going to have to include a "start value" datapoint. Disappointing.
I would like to know how to get x-axis start value in JS library Flot. I know x-axis value in the start (obviously, because I fill it with my own data), but if you set:
pan: {
interactive: true
}
Than the user is able to pan through graph (example here) and if the user pans through graph, the x-values change. I looked inside jquery.flot.js to find where this values are computed but with no luck.
I got it. The solution was in front of me the whole time (example):
var axes = plot.getAxes();
var min = axes.xaxis.min;
I've already drawn a flot graph using some data:
var plot = $.plot($("#placeholder"),
[{
data: data,
}], {
series: {
points: {
show: true
}
},
grid: {
hoverable: true,
}
});
Now I'd like to highlight a single point on the graph, when a user hovers over an item elsewhere on the page.
I found this question, which explains how to totally redraw the series from scratch, but is there a way to highlight a single point?
Or add a new point in a different colour, which would have the effect of a highlight?
NB: when the user hovers over the relevant item elsewhere on the page, I will have the x and y coordinates of the related point, but not the pixel coordinates on the graph.
The API provides the following methods:
The Plot object returned from the plot function has some methods you
can call:
highlight(series, datapoint)
Highlight a specific datapoint in the data series. You can either
specify the actual objects, e.g. if you got them from a
"plotclick" event, or you can specify the indices, e.g.
highlight(1, 3) to highlight the fourth point in the second series
(remember, zero-based indexing).
unhighlight(series, datapoint) or unhighlight()
Remove the highlighting of the point, same parameters as
highlight.
If you call unhighlight with no parameters, e.g. as
plot.unhighlight(), all current highlights are removed.