Range undefined for C3 Spline Chart - javascript

I'm trying to modify the behavior of a vertical C3.js Spine chart so that the mousewheel scrolls the range of the data instead of zooming. I created an event listener using Prototype to change the range of the chart when someone scrolls inside its parent div like so:
$("chartDiv").observe("mousewheel", function(e, charts) {
if (charts.get("splineChart") != null) {
var cht = charts.get("splineChart");
var range = cht.axis.range();
if (e.wheelDelta > 0) {
cht.axis.range({
min: {
y: range.min.y - 10
},
max: {
y: range.max.y - 10
},
});
}
else {
cht.axis.range({
min: {
y: range.min.y + 10
},
max: {
y: range.max.y + 10
},
});
}
}
}.bindAsEventListener(this, chartList));
When testing in Chrome, the event is handled corrently and I have access to the chart object that I want to work with, but the max and min objects returned by range() have undefined values for x, y, and y2.
I've read through the API listed on http://c3js.org/reference.html#api-axis-range and it says is that calling range() with no argument should return the current min and max values for each axis.
What am I doing wrong here? I need to get and update the current displayed range for data in the chart.

Related

Highstock, True way of Get count of shown points after setExtreme (Zooming) - WITHOUT counting all data with MIN and MAX

Sure there is a way to count all of points that shown after zooming or any changing view and do reaction for that.
My target is in Highchart 7.2.0 stockChart, IF "viewed points" x "radius of circles", gone more than (>) "view-port pixels", i just hide them, or doing something special with points, because some of them are Special and still should be shown.
so i need :
HOW GET : Count of points that JUST viewed now (WITHOUT PUTTING A "FOR" TO ALL OF DATA's)
(I just think if there is no true way for it, it is better to i count svg objects instead of : counting all of my data and using isInside with min and max)
The Best Events for : "afterSetExtremes" and "events:{redraw:" [Solved i think]
events: {
afterSetExtremes: function(event) {
console.log(event.min);
console.log(event.max);
}
}
How i turn them off [Solved i think]
if (chart.userOptions.plotOptions.line.marker.enabled) {
chart.userOptions.plotOptions.line.marker.enabled=false;
chart.update({
plotOptions: {
marker: {
enabled:false
}
}
});
}
If there is automatic way like "amchart" options that i just ask "marker: { enabled: true" (when no problem) and "marker: { enabled: false" when it is tight. [Solved i think]
Solved by this:
plotOptions: {
series: {
marker: {
enabled:undefined,
enabledThreshold: 4,
symbol: 'circle',
radius: 4,
},
}
}
It was like this :
marker: {enabled:true,
enabledThreshold: 0, (By Default)
Should be :
marker: {enabled:undefined,
enabledThreshold: 4, (More than Zero)
Got help from here : https://stackoverflow.com/a/54417034/7514010
The easiest way is to loop through the data and check isInside point property or point position. As an alternative you can overwrite translate method and count the number of visible points in the existing loop:
var counter;
(function(H) {
H.Series.prototype.translate = function() {
...
counter = 0;
// Translate each point
for (i = 0; i < dataLength; i++) {
...
point.isInside =
plotY !== undefined &&
plotY >= 0 &&
plotY <= yAxis.len && // #3519
plotX >= 0 &&
plotX <= xAxis.len;
// CHANGE
if (point.isInside) {
counter++;
}
// CHANGE
...
}
series.closestPointRangePx = closestPointRangePx;
H.fireEvent(this, 'afterTranslate');
}
})(Highcharts)
Live demo: http://jsfiddle.net/BlackLabel/yx1cj0at/
Docs: https://www.highcharts.com/docs/extending-highcharts
It answered by #ppotaczek here in the third comment by this link jsfiddle.net/BlackLabel/j1tLfaxu and also in GitHub issues : https://github.com/highcharts/highcharts/issues/12017
If need to get count of points that just viewed now (by using afterSetExtremes or redraw or render events) :
chart: {
events: {
render: function() {
console.log(this.series[0].points.length)
}
}
},
processedXData can be used too instead of points
points object have enough options like isInside :
this.series[0].points[0].isInsdie.
Because it is possible the first or last point be not shown and just affect the lines in line chart or in other type of chart be not shown because zooming in Y too.
and for just calculation where the extreme started you may need :
this.series[0].cropStart
and comparing that with your main data.

Chart.js - Setting max Y axis value and keeping steps correct

I'm using Chart.js 2.6. I have a chart to which I've added custom pagination to step through the dataset, as it is quite large. My pagination and everything works great, I simply grab the next chunk of data in my set and update the chart.config.data with the new data object, and then call .update() on the chart. However, in order to make the chart make sense, I needed to keep the left (Y-axis) scale the same when the user is paginating through. Normally Chart.js would rebuild it based on the data in the chart, but I want it to always reflect the same values.
I've set the max value on the yAxes object of the chart to the maximum value in my data set. I've also set the beginAtZero option to true, and the maxTicksLimit to 10. However, even though my Yaxis does stay the same, it doesn't always look that great (see below screenshot). In this example, my max is set to 21,000 in the chart. Does anyone have any suggestions as to how I can either provide a better max (rounding up to next 5,000, 500, 100, etc based on the value) or some way to get it to create the Y axis without crunching the top number the way it does now?
Here is the function I currently use to determining the max data value to set as the max value in the Yaxes object in the chart. the plugin.settings.chartData variable represents an array of the data values used in the chart. I am trying to get it to increment correctly to the next 1000, 500, etc based on what the maxValue is, but as you can see my math is not correct. In the screenshot example, the maxValue is coming back as 20,750 and my function is rounding it up to 21,000. In this example it SHOULD round it up to the next increment which would be 25,000.
var determineMaxDataValue = function() {
var maxValue = Math.max.apply(Math, plugin.settings.chartData);
var step = maxValue > 1000 ? 1000 : 500;
plugin.settings.maxDataValue = (Math.ceil(maxValue / step) * step);
};
I too had the same problem. You needn't write any special function for determining the max value in the Yaxes. Use 'suggestedMax' setting. Instead for setting 'max' as maximum value in your graph, set suggestMax as the maximum value in your graph. This never works if you have set 'stepsize'.
options: {
scales: {
yAxes: [{
ticks: {
suggestedMax: maxvalue+20
}
}]
}
}
20 is added, so that the tooltip on max value will be clearly visible.
For more info, refer http://www.chartjs.org/docs/latest/axes/cartesian/linear.html#axis-range-settings
Figured it out. Instead of supplying the max value on the Y Axis as I have been, I instead implemented the afterBuildTicks callback and updated the ticks to have the correct increments.
yAxes: [{
afterBuildTicks: function(scale) {
scale.ticks = updateChartTicks(scale);
return;
},
beforeUpdate: function(oScale) {
return;
},
ticks: {
beginAtZero:true,
// max:plugin.settings.maxDataValue,
maxTicksLimit: 10
}
}]
my updateChartTicks function loops over the existing ticks and determines the correct increment amount between the ticks. Then I use that value to add my final "tick" which will always be greater than the largest data in the dataset.
var updateChartTicks = function(scale) {
var incrementAmount = 0;
var previousAmount = 0;
var newTicks = [];
newTicks = scale.ticks;
for (x=0;x<newTicks.length;x++) {
incrementAmount = (previousAmount - newTicks[x]);
previousAmount = newTicks[x];
}
if (newTicks.length > 2) {
if (newTicks[0] - newTicks[1] != incrementAmount) {
newTicks[0] = newTicks[1] + incrementAmount;
}
}
return newTicks;
};

Hide min and max values from y Axis in Chart.js

I have assigned the min and max of Y axes with the tick configuration.But I do not want these min max values to be shown in the graph.I need to hide these values at both the ends
ticks:
{
callback: function(value){
returnparseFloat(value.toFixed(2))
},
min: y1_min,
max: y1_max,
fontColor: "#000000",
fontSize: 12
},
In order to hide specific ticks (in your case the first and last tick), you have to use the scale afterTickToLabelConversion callback property and set the value = null of the tick indexes within scaleInstance.ticks that you are wanting to hide. This will prevent them from being drawn on the canvas.
Here is an example that hides the first and last tick (by setting their values = null).
afterTickToLabelConversion: function(scaleInstance) {
// set the first and last tick to null so it does not display
// note, ticks[0] is the last tick and ticks[length - 1] is the first
scaleInstance.ticks[0] = null;
scaleInstance.ticks[scaleInstance.ticks.length - 1] = null;
// need to do the same thing for this similiar array which is used internally
scaleInstance.ticksAsNumbers[0] = null;
scaleInstance.ticksAsNumbers[scaleInstance.ticksAsNumbers.length - 1] = null;
}
You can see it in action on this codepen example
Hiding the max worked this way for me (ng2-charts):
I return undefined instead of value to hide tick's value & line
scales: {
yAxes: [{
ticks: {
callback: (value, index, values) => (index == (values.length-1)) ? undefined : value,
},
...
In version 3.5.1
afterTickToLabelConversion: function( scaleInstance ){
scaleInstance.ticks.pop();
scaleInstance.ticks.shift();
}
When using the plugin chartjs-plugin-zoom I only wanted to remove those ticks if they had decimals, as it created a flickering effect when panning.
Implementation:
afterTickToLabelConversion: (scaleInstance) => {
if (scaleInstance.ticks[0].indexOf(".") > -1) {
scaleInstance.ticks[0] = null;
scaleInstance.ticksAsNumbers[0] = null;
}
if (scaleInstance.ticks[scaleInstance.ticks.length - 1].indexOf(".") > -1) {
scaleInstance.ticks[scaleInstance.ticks.length - 1] = null;
scaleInstance.ticksAsNumbers[scaleInstance.ticksAsNumbers.length - 1] = null;
}
}

Flot Bubbles Plugin - Bubble Size

I am using the Bubbles plugin with the Flot charting library for JQuery. The data I have is dynamic and can be quite varied within the X, Y, and Z values. The main issue I am having is the size of the bubbles. If the X and Y values are somewhat close to each other but the Z value is much larger the bubble simply takes over the chart. Setting the axis min and max for the X and Y axes helps a bit but not in every case. I have tried to look for other options and settings but did not find anything useful. Is there any type of way to control the size of the bubble?
For instance Flex used to automatically create bubble sizes relative to the screen and axes where Flot seems to always set the bubble size to the same scale as the X and Y values. I have included just a sample of data. I would like to continue to use Flot as the plugin because I have many other chart types in my application and would like to use the same code base. However if there is another plugin that would be better I am open to ideas. Thanks!
https://jsfiddle.net/llamajuana/zd4hd7rb/
var d1 = [[30,339,139856], [30, 445,239823], [30,1506,127331]];
var options = {
series: {
//color: '#CCC',
color: function(x, y, value) {
var red = 55 + value * 10;
return 'rgba('+red+',50,50,1)';
},
bubbles: {
active: true,
show: true,
fill: true,
linewidth: 0,
bubblelabel: {
show: true
},
highlight: {
show: true,
opacity: 0.3
}
}
},
grid:{
hoverable: true,
clickable: true
},
tooltip: {
show: true,
content: "x: %x | y: %y | value: %ct"
}
};
var p4 = $.plot( $("#plot"), [d1], options );
You could try logarithmic scaling.
For the x- and y-axis you can do this using the transform property in the axis options or changing the data before drawing the plot.
For the bubbles you have to do this by hand, either by changing the data before drawing or by replacing the drawbubble function of the bubbles plugin (see the User draw example here).
See this fiddle for the full example. Changes from your fiddle:
1) You could change this directly in the bubbles plugin, if you wanted.
// index of bubbles plugin is dynamic, you better search for it
var defaultBubbles = $.plot.plugins[1].options.series.bubbles.drawbubble;
var logBubbles = function(ctx, serie, x, y, v, r, c, overlay){
defaultBubbles(ctx, serie, x, y, v, Math.log(r), c, overlay);
}
2) In the series options:
xaxis: {
transform: function (v) {
return Math.log(v);
},
inverseTransform: function (v) {
return Math.exp(v);
}
},
yaxis: {
transform: function (v) {
return Math.log(v);
},
inverseTransform: function (v) {
return Math.exp(v);
}
},
3) In the radiusAtPoint() function in the bubbles plugin:
// added Math.log function here too
return parseInt(series.yaxis.scale * Math.log(series.data[radius_index][2]) / 2, 0);

Show gap of missing data with Highstock

Using Highstock to chart a sorted time serie: [[timestamp, value], ...]
The datasource is sampled at irregular intervals. As result the distances between two points (in the time axis) varies.
If two adjacent points are separated for more than 5 minutes I want to show a gap in the chart.
Using the gapSize option doesn't work, because it doesn't allows to specify the 'size' of the gap as a function of time.
Showing gaps is already a part of Highstock, I just need a way to specify it as a fixed amount of time (5 minutes). Ideas?
Btw, beside that the plot works great.
Here's a slightly unclean way to "manipulate" gapSize to work so that it's value is the amount of milliseconds required to create a gap.
(function (H) {
// Wrap getSegments to change gapSize functionality to work based on time (milliseconds)
H.wrap(H.Series.prototype, 'getSegments', function (proceed) {
var cPR = this.xAxis.closestPointRange;
this.xAxis.closestPointRange = 1;
proceed.apply(this, Array.prototype.slice.call(arguments, 1));
this.xAxis.closestPointRange = cPR;
});
}(Highcharts));
This utilizes that gapSize is only used within the getSegments function (see source), and it works based on the closestPointRange of the axis. It wraps the getSegments, sets closestPointRange to 1, calls the original method and then resets closestPointRange to its original value.
With the code above you could do gaps for 5 minutes like this:
plotOptions: {
line: {
gapSize: 300000 // 5 minutes in milliseconds
}
}
See this JSFiddle demonstration of how it may work.
Halvor Strand function wrapper did not work for me as long as getSegments is not part of highstock source code anymore to calculate that gap. Anyway, you can find an approximation to solve the problem combining this other topic and the previows answer like this:
(function(H) {
H.wrap(H.Series.prototype, 'gappedPath', function(proceed) {
var gapSize = this.options.gapSize,
xAxis = this.xAxis,
points = this.points.slice(),
i = points.length - 1;
if (gapSize && i > 0) { // #5008
while (i--) {
if (points[i + 1].x - points[i].x > gapSize) { // gapSize redefinition to be the real threshold instead of using this.closestPointRange * gapSize
points.splice( // insert after this one
i + 1,
0, {
isNull: true
}
);
}
}
}
return this.getGraphPath(points);
});
}(Highcharts))
setting gapSize in plotOptions to the desired size (in ms) like Halvor said:
plotOptions: {
line: {
gapSize: 300000 // 5 minutes in milliseconds
}
}
In case anyone comes across this and is spending hours trying to figure out why gapSize is not working like me. Make sure your time series data is sorted, only then will the gaps appear in the graph.
Another issue I ran into was my data series was in this format
[
{x: 1643967900000, y: 72},
{x: 1643967600000, y: 72},
{x: 1643967300000, y: 72}
]
However this does not seem to work with gapSize and needs to be in the format below
[
[1643967900000, 72],
[1643967600000, 91],
[1643967300000, 241]
]

Categories

Resources