I have a stacked bar chart in Chart.js 2.9.4.
On hovering, the tooltip's tip is positioned at the top-center of each bar, but the tooltip itself is rendered to the right and blocks the view of other bars.
I'd like to draw the tooltip above the bar. Is there a way to do this?
See the JSFiddle here.
(Here's the raw code as required by StackOverflow)
// Get the past 14 days for the x-axis
var allDates = [
moment('2021-04-04T00:00:00'),
moment('2021-04-05T00:00:00'),
moment('2021-04-06T00:00:00'),
moment('2021-04-07T00:00:00'),
moment('2021-04-08T00:00:00'),
moment('2021-04-09T00:00:00'),
moment('2021-04-10T00:00:00'),
moment('2021-04-11T00:00:00'),
moment('2021-04-12T00:00:00'),
moment('2021-04-13T00:00:00'),
moment('2021-04-14T00:00:00'),
moment('2021-04-15T00:00:00'),
moment('2021-04-16T00:00:00'),
moment('2021-04-17T00:00:00'),
moment('2021-04-18T00:00:00'),
];
// Simulated distribution per day
var distributionPerDay = [
[0.13, 0.05, 0.12, 0.07, 0.11, 0.14, 0.22, 0.06, 0. , 0.1 ],
[0.1 , 0.08, 0.1 , 0.09, 0.13, 0.12, 0.18, 0.11, 0.03, 0.06],
[0.08, 0.1 , 0.1 , 0.09, 0.15, 0.1 , 0.2 , 0.09, 0.03, 0.06],
[0.09, 0.09, 0.12, 0.07, 0.13, 0.12, 0.15, 0.14, 0.01, 0.08],
[0.05, 0.05, 0.16, 0.13, 0.1 , 0.1 , 0.1 , 0.1 , 0.11, 0.1 ],
[0.05, 0.05, 0.16, 0.13, 0.1 , 0.13, 0.1 , 0.12, 0.07, 0.09],
[0.08, 0.05, 0.15, 0.1 , 0.13, 0.1 , 0.12, 0.13, 0.08, 0.06],
[0.1 , 0.08, 0.13, 0.07, 0.1 , 0.13, 0.15, 0.1 , 0.05, 0.09],
[0.08, 0.1 , 0.12, 0.08, 0.13, 0.1 , 0.13, 0.07, 0.07, 0.12],
[0.12, 0.08, 0.1 , 0.04, 0.1 , 0.14, 0.11, 0.12, 0.09, 0.1 ],
[0.08, 0.06, 0.16, 0.07, 0.07, 0.19, 0.07, 0.14, 0.11, 0.05],
[0.08, 0.1 , 0.1 , 0.09, 0.1 , 0.16, 0.12, 0.12, 0.06, 0.07],
[0.12, 0.09, 0.14, 0.04, 0.16, 0.08, 0.12, 0.1 , 0.12, 0.03],
[0.09, 0.16, 0.1 , 0.07, 0.13, 0.1 , 0.1 , 0.11, 0.08, 0.06],
[0.13, 0.12, 0.13, 0.04, 0.15, 0.11, 0.06, 0.12, 0.06, 0.08]
]
// Define colors for each bar (10 bars)
var colors = ['#9e0142', '#d53e4f', '#f46d43', '#fdae61', '#fee08b', '#e6f598', '#abdda4', '#66c2a5', '#3288bd', '#5e4fa2']; // cb-Spectral
// Convert distribution into Chart.js datasets
var classNames = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
var datasets = [];
classNames.forEach(function(className, i) {
// Gather the data {x: date, y: percentage} for this class
var data = [];
distributionPerDay.forEach(function(dist, j) {
data.push({x: allDates[j], y: dist[i]});
});
// Add data and config to the datasets array
datasets.push({
label: className,
data: data,
backgroundColor: colors[i],
borderWidth: 0,
borderColor: 'black',
hoverBorderWidth: 1, // Show a 1px black border on hover
borderSkipped: false, // Draw all four borders around the bar
minBarLength: 1 // So even a bar for 0 has 1px height
});
});
var myChart = new Chart('my-chart', {
type: 'bar',
data: { datasets: datasets },
options: {
hover: {
mode: 'dataset', // Highlight an entire row on hover
animationDuration: 0 // Otherwise there is flickering when sliding over the bars quickly
},
tooltips: {
mode: 'nearest', // Only show tooltip data of one bar on hover
},
scales: {
xAxes: [{
stacked: true,
type: 'time',
time: {
unit: 'day',
},
offset: true, // Otherwise the left and right bars are cut off
ticks: { source: 'data' } // Use one tick per point in allDates
}],
yAxes: [{
stacked: true,
ticks: {
min: 0,
max: 1.0
}
}]
}
}
});
You can set yAlign: 'bottom' in tooltip options, see the JSFiddle here
Relevant part of the code:
var myChart = new Chart('my-chart', {
type: 'bar',
data: { datasets: datasets },
options: {
hover: {
mode: 'dataset',
animationDuration: 0
},
tooltips: {
mode: 'nearest',
yAlign: 'bottom' //use this to control the placement of the tooltip relative to its point
},
scales: {
xAxes: [{
stacked: true,
type: 'time',
time: {
unit: 'day',
},
offset: true,
ticks: { source: 'data' }
}],
yAxes: [{
stacked: true,
ticks: {
min: 0,
max: 1.0
}
}]
}
}
});
It isn't mentioned in the official documentation, but works for Chart.js 2.9.4
(you can have a look at the source code where that option is used to override the automatic alignment calculation based on tooltip and chart size)
Related
I'm building a Django app that is dynamically feeding data to Chart JS. because I'm trying to join two line series together (historical values and predictions), I'm trying to have Chart JS understand NaN. This is how the code is written:
<script>
new Chart(document.getElementById("chart"), {
type: 'line',
data: {
labels: {{ new_dates|safe }},
datasets: [
{
data: {{ orig_val|safe }},
label: "Historical Sales",
borderColor: "#3e95cd",
fill: false
},
{
data: {{ preds|safe }},
label: "Predictions",
borderColor: "#22DD66",
fill: false
}
]
},
options: {
title: {
display: true,
text: 'output chart'
},
maintainAspectRatio: false,
responsive: true,
scales: {
xAxes: [{
gridLines: {
display:false
}
}],
yAxes: [{
gridLines: {
display:false
}
}]
},
animation: {
duration: 2000,
},
}
});
</script>
This is what the console sees:
<script>
new Chart(document.getElementById("chart"), {
type: 'line',
data: {
labels: ['2019-01', '2019-02', '2019-03', '2019-04', '2019-05', '2019-06', '2019-07', '2019-08', '2019-09', '2019-10', '2019-11', '2019-12', '2020-01', '2020-02', '2020-03', '2020-04', '2020-05', '2020-06', '2020-07', '2020-08', '2020-09', '2020-10', '2020-11', '2020-12', '2021-01', '2021-02', '2021-03', '2021-04', '2021-05', '2021-06', '2021-07', '2021-08', '2021-09', '2021-10', '2021-11', '2021-12', '2022-01', '2022-02', '2022-03', '2022-04', '2022-05', '2022-06', '2022-07', '2022-08', '2022-09'],
datasets: [
{
data: [71.0, 67.0, 84.0, 65.0, 78.0, 74.0, 73.0, 88.0, 86.0, 77.0, 94.0, 123.0, 71.0, 77.0, 57.0, 36.0, 57.0, 78.0, 89.0, 100.0, 120.0, 98.0, 121.0, 155.0, 99.0, 86.0, 162.0, 103.0, 102.0, 117.0, 114.0, 121.0, 127.0, 128.0, 141.0, 175.0, 124.0, 121.0, 139.0, nan, nan, nan, nan, nan, nan],
label: "Historical Sales",
borderColor: "#3e95cd",
fill: false,
spanGaps: true
},
{
data: [nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, 100.2935, 154.556, 122.833, 109.4725, 160.0235, 104.568],
label: "Predictions",
borderColor: "#22DD66",
fill: false,
spanGaps: true
}
]
},
options: {
title: {
display: true,
text: 'output chart'
},
maintainAspectRatio: false,
responsive: true,
scales: {
xAxes: [{
gridLines: {
display:false
}
}],
yAxes: [{
gridLines: {
display:false
}
}]
},
animation: {
duration: 2000,
},
}
});
</script>
But, I keep getting this error:
Uncaught ReferenceError: nan is not defined
at (index):40:282
these "nan's" are generated by Python using Numpy, like this: y_hat = np.append(y, np.zeros(6) + np.nan).tolist()
it seems that Chart JS does know how to read "null" values, I just don't know how to make the conversion from Python to something that Chart JS can actually read.
Any ideas?
Thanks!
answered my own question. just needed to convert the array to strings using .astype(str). so like this: np.append(np.zeros(39) + np.nan, array_of_numbers).astype(str)
I want to create chart of type line with chatjs. The problem is, I have date formatted: { x: real number from 0 to 1, y: integers from 0 to infinite }, and I want fixed labels to the chart in x-axis, something like: [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1].
This is how I'd like to set the chart configuration:
type: 'line',
data: {
labels: ['0', '0.1', '0.2', '0.3', '0.4', '0.5', '0.6', '0.7', '0.8', '0.9', '1'],
datasets: [{
label: 'data',
data: [
{ x: 0.3, y: 446 },
{ x: 0.3331, y: 6863 },
{ x: 0.874, y: 12 },
{ x: 0.2244, y: 1565 },
{ x: 0.38899, y: 32221 },
{ x: 0.23685545, y: 3112324 },
{ x: 0.11332, y: 444423 },
{ x: 0.97694, y: 21212334 },
],
}]
},
But this is obviously not working, How can I do it?
So I found out there is another chart type of scatter. This is typically used to only points on axes chart, but it can configured to have lines between the points. Also, if marking the points on graph is unneccessary there is a configuration option to set those points' radius to 0 and this makes those hidden.
https://www.chartjs.org/docs/latest/charts/scatter.html#scatter-chart
I'm building a local html file that will generate some graphs using chartjs when offline. I'm just testing some example data I have.
See fiddle below.
http://jsfiddle.net/joshmoto/0odcemL7/
The issue is, i've set 8 points of data for each dataset, but the graph is only outputting 2 points for each dataset.
I need my x axis to display a automatic time grid distributed in seconds. My time data consists millisecond data, but my x axis grid needs to show steps in seconds. But my points must remain accurately positioned on the graph within the steps as the data is milliseconds.
.
var ctx = document.getElementById('log_chart').getContext('2d');
var myChart = new Chart(ctx, {
type: 'line',
data: {
datasets: [{
label: 'Engine Speed',
backgroundColor: '#ff0000',
borderColor: '#ff0000',
fill: false,
data: [{
t: new Date(0.37),
y: 2640
}, {
t: new Date(0.85),
y: 2560
}, {
t: new Date(1.33),
y: 2560
}, {
t: new Date(1.78),
y: 2560
}, {
t: new Date(2.23),
y: 2680
}, {
t: new Date(2.7),
y: 2920
}, {
t: new Date(3.16),
y: 3200
}, {
t: new Date(3.63),
y: 3520
}]
}, {
label: 'Mass Air Flow - Sensor',
backgroundColor: '#00FFFF',
borderColor: '#00FFFF',
fill: false,
data: [{
t: new Date(0.02),
y: 19.58
}, {
t: new Date(0.45),
y: 16.28
}, {
t: new Date(0.92),
y: 8.56
}, {
t: new Date(1.39),
y: 8.47
}, {
t: new Date(1.86),
y: 23.36
}, {
t: new Date(2.33),
y: 45.78
}, {
t: new Date(2.78),
y: 56.03
}, {
t: new Date(3.23),
y: 62.36
}]
}],
},
options: {
scales: {
// xAxes: [{
// type: 'time',
// displayFormats: {
// quarter: 'ss.SSS'
// },
// time: {
// unit: 'second'
// }
// }]
}
}
});
<script src="https://cdn.jsdelivr.net/npm/chart.js#2.8.0/dist/Chart.min.js"></script>
<div class="container">
<div class="col-12 mt-3 mb-3">
<canvas id="log_chart" width="600" height="200"></canvas>
</div>
</div>
Basically the data works like this...
t is the x axis but in time format seconds.
y is the value ranging from 0 - 5000
I'm trying my hardest to follow the docs but struggling to work this one out, I can't see anything obvious. If anyone can help out that would be awesome.
I think you need to provide more information to Chart.js so that it knows what to do with the X-Axis. On previous projects, I've given a labels property within the data.
Example -
// document ready
(function ($) {
var ctx = document.getElementById('log_chart').getContext('2d');
var myChart = new Chart(ctx, {
type: 'line',
data: {
labels: [1, 2, 3, 4, 5, 6, 7, 8],
datasets: [
{
label: 'Engine Speed',
backgroundColor: '#ff0000',
borderColor: '#ff0000',
fill: false,
data: [2640,2560,2560,2560, 2680, 2920, 3200, 3520]
},
{
label: 'Mass Air Flow - Sensor',
backgroundColor: '#00FFFF',
borderColor: '#00FFFF',
fill: false,
data: [19.58, 16.28, 8.56, 8.47, 23.36, 45.78, 56.03, 62.36]
}
],
},
options: {
scales: {
yAxes: [{
stacked: false
}],
}
}
});
})(jQuery);
So the labels property can then fill your X axis, and your data sets just plot the raw data onto the graph. The problem you'll run into with this kind of dataset is that the sensors readings are significantly lower than the engine speed, so not well represented on the chart. You'll have to work out some kind of way of normalising this data so it can be properly represented, e.g. adding a multiply to the mass airflow sensor readings.
I figured out using x axis type: linear; and removed the date functionality and just used the raw millisecond data in x rather than t.
See working example below.
var ctx = document.getElementById('log_chart').getContext('2d');
var myChart = new Chart(ctx, {
type: 'line',
data: {
datasets: [{
label: 'Engine Speed',
backgroundColor: '#ff0000',
borderColor: '#ff0000',
fill: false,
data: [{
x: 0.37,
y: 2640
}, {
x: 0.85,
y: 2560
}, {
x: 1.33,
y: 2560
}, {
x: 1.78,
y: 2560
}, {
x: 2.23,
y: 2680
}, {
x: 2.7,
y: 2920
}, {
x: 3.16,
y: 3200
}, {
x: 3.63,
y: 3520
}]
}, {
label: 'Mass Air Flow - Sensor',
backgroundColor: '#00FFFF',
borderColor: '#00FFFF',
fill: false,
data: [{
x: 0.02,
y: 19.58
}, {
x: 0.45,
y: 16.28
}, {
x: 0.92,
y: 8.56
}, {
x: 1.39,
y: 8.47
}, {
x: 1.86,
y: 23.36
}, {
x: 2.33,
y: 45.78
}, {
x: 2.78,
y: 56.03
}, {
x: 3.23,
y: 62.36
}]
}],
},
options: {
responsive: true,
title: {
display: true,
text: "Chart.js Time Scale"
},
scales: {
xAxes: [{
type: 'linear',
position: 'bottom'
}]
}
}
});
<script src="https://cdn.jsdelivr.net/npm/chart.js#2.8.0/dist/Chart.min.js"></script>
<div class="container">
<div class="col-12 mt-3 mb-3">
<canvas id="log_chart" width="600" height="200"></canvas>
</div>
</div>
Has anyone got an example of how to zoom a Y axis on a time series graph built with chartjs? Does anyone know if it's even possible?
I've been using chartjs-plugin-zoom. I've spent hours experimenting, searching for solutions and looking at the chartjs-plugin-zoom source.
Examples I've so far found show bar charts being zoomed, not a time series or X-Y charts.
I've implemented a hacky Y-axis zoom for now by setting the min and max of the Y scale. This works to a degree, but by doing this, you lose the ability to pan and see any data outside of the chart. And anyway, having to do this seems a bodge.
Grateful for an example of a working X-Y zoomable chart.
Answered my own question eventually. Basically, the example at https://codepen.io/anon/pen/PGabEK (linked from https://npmjs.com/package/chartjs-plugin-zoom) can be re-done as a time series.
Example HTML below.
var ctx = document.getElementById("myChart");
var myChart = new Chart(ctx, {
type: 'line',
data: {
datasets: [
{
data: [
{ t: '2018-03-29 08:48', y: 20.2 },
{ t: '2018-03-29 16:24', y: 23.1 },
{ t: '2018-04-09 18:24', y: 20.7 },
{ t: '2018-04-10 02:10', y: 24.2 },
{ t: '2018-04-10 09:16', y: 24.2 }
],
type: 'line',
radius: 1,
hitRadius: 3,
fill: false,
backgroundColor: 'black',
borderWidth: 2,
label: 'Some label'
},
{
data: [
{ t: '2018-03-29 08:48', y: 22.5 },
{ t: '2018-03-29 16:24', y: 22.3 },
{ t: '2018-03-30 00:00', y: 21.5 },
{ t: '2018-03-30 07:36', y: 21.5 },
{ t: '2018-03-30 15:12', y: 21.5 }
],
type: 'line',
radius: 1,
hitRadius: 3,
fill: false,
backgroundColor: 'black',
borderWidth: 2,
label: 'Another label'
}
]
},
options: {
pan: {
enabled: true,
mode: 'xy'
},
zoom: {
enabled: true,
mode: 'xy'
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.3/Chart.bundle.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/hammer.js/2.0.8/hammer.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chartjs-plugin-zoom/0.6.6/chartjs-plugin-zoom.min.js"></script>
<div id="chartDiv">
<canvas class="my-4 chartjs-render-monitor" id="myChart" style="display:block;"></canvas>
</div>
I am trying to create bell curve using django and highcharts but its not looking like i expected,
Here is the image what exactly i want
currently I'm working on this
var data = [ 2.7, 2.7, 3, 3.4, 3.1, 2.3, 3, 2.5, 2.6, 3, 2.6, 2.3,
2.7, 3, 2.9, 2.9, 2.5, 2.8, 3.3, 2.7, 3, 2.9, 3, 3, 2.5, 2.9, 2.5, 3.6,
3.2, 2.7, 3, 2.5, 2.8, 3.2, 3, 3.8];
Highcharts.chart('container', {
title: {
text: 'Bell curve'
},
xAxis: [{
title: { text: 'Data' }
}, {
title: { text: 'Bell curve' },
opposite: true
}],
yAxis: [{
title: { text: 'Data' }
}, {
title: { text: 'Bell curve' },
opposite: true
}],
series: [{
name: 'Bell curve',
type: 'bellcurve',
xAxis: 1,
yAxis: 1,
baseSeries: 1,
zIndex: -1
}, {
name: 'Data',
type: 'scatter',
data: data,
marker: {
radius: 1.5
}
}]
});
Click here to see
the problem which I'm facing are following:
1. How to remove scatter
2. How to display average point on curve.
3. How to display gradient like given in image.
To answer your questions is simple after reading the API docs for Highcharts.
1. To remove the scatter series from view you do set its visible and showInLegend properties to false:
{
name: 'Data',
type: 'scatter',
data: data,
marker: {
radius: 1.5
},
visible: false,
showInLegend: false
}
How to display average point on curve is a bit more complex. First you need to get the average. This you can do via javascript (taken from this really neat code):
var sum = data.reduce(function(a, b) { return a + b; });
var avg = sum / data.length;
Then you need to show this on the actual chart. There are many options but a scatter point or Highstock flag is probably the best option.
To display a gradient is really simple. You use the color property of the series and set the gradient options and set the colors to your liking:
{
name: 'Bell curve',
type: 'bellcurve',
xAxis: 1,
yAxis: 1,
baseSeries: 1,
zIndex: -1,
color: {
linearGradient: {
x1: 0,
y1: 0,
x2: 1,
y2: 0
},
stops: [
[0, 'rgb(255, 255, 255)'],
[1, 'rgb(200, 200, 255)']
]
}
}