I have a grid with 4 doughtnut charts on each column for different periods of time: last 90 days, last 60 days, last 7 days and today.
The problem with today is that it doesn't always show data, especially in the morning. Is there a way to force ChartJS to show the chart even if it doesn't have any data?
Here's an example: http://jsfiddle.net/6xV78/219/
var pieData = [
{
value: 0,
color:"#3F9F3F"
},
{
value : 0,
color : "#222"
}
];
I found a quick work-around, not sure how "good" or "valid" way it is but it's working for me. If the values are null/zero I replaced them with -1 to retain the looks of the chart and then use the custom tooltip function to override the output.
{
...
data: [earned == 0 ? -1 : earned, pending == 0 ? -1 : pending]
...
},
options: {
tooltip: {
callbacks: {
label: function (tooltipItem, data) {
const value = data['datasets'][0]['data'][tooltipItem['index']];
return '$' + (value == -1 ? 0 : value);
}
}
}
}
Obviously I have 2 slices and when both are 0 the chart is displayed with 2 equal halves both showing $0 income (both earned and pending).
*Do note that this will still take 1 into account when others aren't null so you need to take care of that on your end. I added a method to verify if ALL values are null and that's the only case I display it like this.
A pie chart with all values equal to zero is ill-defined. Because the angle (and the area) of each slice is proportionate to the ratio of the slice's respective value over the sum of all values. If all values are equal to zero, then their sum is zero. Division by zero should be rightfully avoided by the library (hopefully by design), resulting in the no-pie-chart case you encounter. It should be the programmer's responsibility to detect the all-zeros case before populating the chart, if such a case has a possibility of occurring. Then the programmer could either display a "No data yet. What are you doing up so early? Go to sleep." message, if all values are zero. Or, maybe, if they terribly need to keep the looks consistent (having a chart there all the time), they could show a special all-black no-data pie chart with the following dummy data:
var pieNoData = [
{
value: 1,
color: "#000000"
}
];
There is no shame in disclosing that no data exists yet, though.
Related
Full code example here: https://jsfiddle.net/_dario/o6nugkrw/24/
I have a data series structured like this (from an API call):
{
"mango": 12736,
"orange": 8906,
"banana": 8404,
"2020": 8239,
"blackberry": 7703,
"pear": 7297,
"raspberry": 6895,
"apple": 6432,
"kiwi": 6202,
"tomato": 6189,
"1995": 6123,
"kumquat": 6038,
"melon": 5982,
"strawberry": 5973,
"pineapple": 5441
}
The sorting order is value high to low, regardless of the label. These are to be plotted in an Highcharts horizontal bar chart.
Notice there are two numeric (string, though) labels: "1995" and "2020".
This specific data format is then parsed for Highcharts:
//--previous highcharts options
series: Object.keys(data).map((s, index) => {
let arr = new Array(length).fill(null, 0, length);
arr[index] = data[s];
return {
name: s,
data: arr,
tooltip: {
headerFormat: ''
},
}
}),
//--subsequent highcharts options
as per the jsfiddle example (https://jsfiddle.net/_dario/o6nugkrw/24/), the sorting order along the Y axis in the chart is different, and no matter what the order the data is presented in, the two "numeric" labels always stay on top and are sorted differently (by numeric value).
I found no reference in the Highcharts docs about this and would like to have them treated as "words" like the others and sorted accordingly. I believe the error might be in the parsing above, but cannot find it.
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;
};
I am working with the Highstock compare demo:
http://www.highcharts.com/stock/demo/compare
jsFiddle:
http://jsfiddle.net/gh/get/jquery/1.9.1/highslide-software/highcharts.com/tree/master/samples/stock/demo/compare/
The associated code of the percent compare is as follows:
plotOptions: {
series: {
compare: 'percent'
}
},
If we set the rangeSelector to 1m (one month), and assuming today is August 15, 2016, then the first entry displayed is Tuesday, July 12. The values are MSFT: 53.21, AAPL: 97.42, and GOOG: 720.64. The Tooltip shows percentage changes of +1.18%, +0.45%, and +0.78%, respectively, over the previous day. But the problem is that the values for the previous day (7/11/2016) are not shown. This is confusing to the user, in my opinion. What I want to do instead is give each of these starting values a percentage change of 0%, so the left-side of the graph always starts at the origin. How do I do this?
UPDATE: I was thinking along the lines of something like this:
events: {
load: function(e) {
set_new_min_y_data_points(e);
}
}
// ...
function set_new_min_y_data_points(e) {
for (var i = 0; i < e.target.series.length; ++i) {
// By setting the first data point to the same
// value as the second data point, we ensure
// that the series starts at the origin.
e.target.series[i].processedYData[0] = e.target.series[i].processedYData[1];
}
}
...but this doesn't work. Even though the values of e.target.series[i].processedYData[0] are changed, the graph looks the same.
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]
]
I have a kendo column chart, the datasource gets refreshed when different criterias are set via date pickers.
I want to stop the chart from displaying the value axis as a decimal and the only way I have found so far is to either set the format, which results in duplicating numbers, or the major unit, which if my data changes, then this results in overlapping value axis labels. Neither are suitable.
The only way I can now think to do it is to dynamically set the major unit based on whether my maximum value is less than 10, if it is then the major unit is set to 1, if not no major unit isn't set.
This should work fine but, if the major unit gets set to 1, and the data changes I now need to find a way to clear the major unit if my new maximum value is greater than 10.
In javascript I have:
if (highest <= 10) {
chart.data("kendoChart").options.valueAxis.majorUnit = 1;
} else {
chart.data("kendoChart").options.valueAxis.majorUnit.remove(); // This does not work
}
I can't just set majorUnit to null or 0, it doesn't like that and there is no documentation on the correct syntax for removing this kind of attribute.
This is what worked for me:
chart.data("kendoChart").options.valueAxis.majorUnit = undefined;
Don't forget to call
chart.data("kendoChart").refresh();
Do you have an example to show?
Does it help you if you just hide the value axis lines?
http://docs.kendoui.com/api/dataviz/chart#configuration-categoryAxis.line.visible
chart.data('kendoChart').options.valueAxis.line.visible = false;
If you are using datasource, you can put this code into requestEnd function, so no chart refresh is required:
$("#chart").kendoChart({
dataSource: {
transport: {
read: {
url: url,
dataType: "json",
type: 'POST'
}
},
// This is to set a step that looks appropriate for the size of the graph
requestEnd: function(e){
var max = 1;
// Iterate over your own data as you need, here my data returns "Category" and "Count" in each row.
e.response.forEach(function(row){
if(row.Count > max)
max = row.Count;
});
if(max <= 10)
$("#chart").data('kendoChart').options.valueAxis.majorUnit = 2;
else
$("#chart").data('kendoChart').options.valueAxis.majorUnit = undefined;
},
},