Chart.js 3.7.1 - How can I control the number of ticks on the y axis of a line chart? - chart.js3

The data will always be integers between -10 and 10, including 0 so there could be a maximum of 21 'intervals' on the y axis.
Regardless of the data, I need the y axis to display from -10 to 10 (including 0) in increments of 1. So I need a total of 21 (ticks?) on the y axis regardless of the data.
I tried this, per the docs:
I also tried it without the steps param:
options: {
scales: {
y: {
max: -10,
min: 10,
ticks: {
steps: 21,
stepSize: 1
}
}
}
}
This is what I got:

The missing part in your code is autoSkip: false.
y: {
max: 10,
min: -10,
ticks: {
stepSize: 1,
autoSkip: false
}
}
According to the Chart.js documentation, autoskip is true by default.
autoskip: If true, automatically calculates how many labels can be shown and hides labels accordingly. (...) Turn autoSkip off to show all labels no matter what.
Please take a look at below runnable code and see how it works.
new Chart('canvas', {
type: 'line',
data: {
labels: ['A', 'B', 'C', 'D', 'E', 'F'],
datasets: [{
label: 'Dataset 1',
data: [3, 9, 7, 5, 9, 2],
backgroundColor: 'rgba(255, 99, 132, 0.2)',
borderColor: 'rgb(255, 99, 132)',
fill: false
},
{
label: 'Dataset 2',
data: [1, 2, -3, -5, -2, 1],
backgroundColor: 'rgba(255, 159, 64, 0.2)',
borderColor: 'rgb(255, 159, 64)'
}
]
},
options: {
scales: {
y: {
max: 10,
min: -10,
ticks: {
stepSize: 1,
autoSkip: false
}
}
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.7.1/chart.min.js"></script>
<canvas id="canvas"></canvas>

Related

echarts - visualMap according to y axis

I am trying to add a visual map according to the y axis in echarts.
Taking one of their example:
https://echarts.apache.org/examples/en/editor.html?c=area-pieces
The results looks as follow:
what I'm trying to achieve is:
Obviously here, I have just rotated the picture by 90 degree.
How can this be achieve in echarts directly (so not by saving the picture first)?
The simplest solution would be inverting the axis, data index, and visual map axis. See chart options below:
option = {
backgroundColor: '#fff',
xAxis: {
type: 'value',
boundaryGap: [0, '30%'],
position: 'top'
},
yAxis: {
type: 'category',
boundaryGap: false
},
visualMap: {
type: 'piecewise',
show: false,
dimension: 1,
seriesIndex: 0,
pieces: [{
gt: 1,
lt: 3,
color: 'rgba(0, 180, 0, 0.5)'
}, {
gt: 5,
lt: 7,
color: 'rgba(0, 180, 0, 0.5)'
}]
},
series: [
{
type: 'line',
smooth: 0.6,
symbol: 'none',
lineStyle: {
color: 'green',
width: 5
},
markLine: {
symbol: ['none', 'none'],
label: {show: false},
data: [
{yAxis: 1},
{yAxis: 3},
{yAxis: 5},
{yAxis: 7}
]
},
areaStyle: {},
data: [
[200, '2019-10-10'],
[400, '2019-10-11'],
[650, '2019-10-12'],
[500, '2019-10-13'],
[250, '2019-10-14'],
[300, '2019-10-15'],
[450, '2019-10-16'],
[300, '2019-10-17'],
[100, '2019-10-18']
]
}
]
};
Result:
See on Imgur

Draw points and lines inside a bar in bar chart

Who know how to draw lines and points inside a bar something like this:
You can draw the lines as floating bars where individual bars are specified with the syntax [min, max], same as you already do for your your other bars. Given an array of number values, the "line" data can be produced with Array.map() as follows.
data: [110, 150, 140, 100, 120].map(v => [v - 1, v + 1])
Then you need to define individual stacked xAxes for the "bar" and the "line" datasets. In order to have the original "line" values displayed in the tooltips, a toolips.callback.label function is also needed.
The points can be defined in an additional dataset of type 'scatter'.
Please have a look at below runnable code snippet.
new Chart("chart", {
type: "bar",
data: {
labels: ["4", "3", "2", "1", "0"],
datasets: [{
label: "Bars",
backgroundColor: "rgba(0, 255, 0, 0.2)",
data: [[20, 100], [50, 180], [60, 120], [10, 130], [70, 140]],
xAxisID: "x-axis-actual",
order: 1
},
{
label: "Lines",
backgroundColor: "rgb(0, 0, 0)",
data: [90, 150, 110, 90, 120].map(v => [v - 1, v + 1]),
xAxisID: "x-axis-target",
order: 2
},
{
label: "Points",
backgroundColor: "rgb(255, 255, 255)",
borderColor: "rgb(0, 0, 0)",
data: [80, 110, 90, 100, 120],
type: "scatter"
}
]
},
options: {
legend: {
display: false
},
tooltips: {
callbacks: {
label: (tooltipItem, data) => {
const dataset = data.datasets[tooltipItem.datasetIndex];
const v = dataset.data[tooltipItem.index];
return dataset.label + ': ' + (tooltipItem.datasetIndex == 1 ? (v[1] + v[0]) / 2 : tooltipItem.value);
}
}
},
scales: {
xAxes: [{
id: "x-axis-target",
stacked: true
},
{
display: false,
offset: true,
stacked: true,
id: "x-axis-actual",
gridLines: {
offsetGridLines: true
}
}
],
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<canvas id="chart" height="120"></canvas>

How to show only the data points that have a change in Chartjs?

Show only the data points that have a change.
In order to reduce the clutter, I want to not show the circles when the prev value or next are the same. Still when you hover over them to show the label with information.
This is how I want it to look:
The second and third circles are the same, they must be hidden and only show on hover:
you can use the following options to style the points...
pointBackgroundColor, pointBorderColor, pointBorderWidth
but instead of providing a single value...
pointBackgroundColor: '#ffffff',
pointBorderColor: 'rgb(102, 187, 106)',
pointBorderWidth: 2,
you'll need to provide an array, with values for each point in the dataset,
then you can change the value for the points in question.
for the points you do not want to show, use color such as 'transparent'.
this will hide the point, but still show tooltip on hover.
pointBackgroundColor: ['#ffffff', '#ffffff', 'transparent', 'transparent', '#ffffff', '#ffffff'],
pointBorderColor: ['rgb(102, 187, 106)', 'rgb(102, 187, 106)', 'transparent', 'transparent', 'rgb(102, 187, 106)', 'rgb(102, 187, 106)'],
pointBorderWidth: [2, 2, 0, 0, 2, 2]
see following working snippet...
new Chart(document.getElementById('myChart').getContext('2d'), {
type: 'line',
data: {
labels: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
datasets: [{
backgroundColor: 'rgba(102, 187, 106, 0.2)',
borderColor: 'rgb(102, 187, 106)',
borderWidth: 2,
data: [5, 6, 6, 6, 6, 7, 6, 6, 5, 4],
label: 'y',
lineTension: 0,
pointBackgroundColor: ['#ffffff', '#ffffff', 'transparent', 'transparent', '#ffffff', '#ffffff', '#ffffff', '#ffffff', '#ffffff', '#ffffff'],
pointBorderColor: ['rgb(102, 187, 106)', 'rgb(102, 187, 106)', 'transparent', 'transparent', 'rgb(102, 187, 106)', 'rgb(102, 187, 106)', 'rgb(102, 187, 106)', 'rgb(102, 187, 106)', 'rgb(102, 187, 106)', 'rgb(102, 187, 106)'],
pointBorderWidth: [2, 2, 0, 0, 2, 2, 2, 2, 2, 2]
}]
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.bundle.min.js"></script>
<canvas id="myChart"></canvas>
A slightly different approach to WhiteHat's (ninja'd!) that iterates the series via .forEach to build the colour options:
Edit: Minor tweak to if to account for previous and next value in deciding point visibility and added hover colour settings to show hidden point on hover.
let labels = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'],
series = [10, 5, 5, 5, 5, 2, 3, 3, 3, 10],
pointBackgroundColor = [],
pointBorderColor = [],
pointHoverBackgroundColor = 'white',
pointHoverBorderColor = 'red';
series.forEach(
(value, index) => {
if (value == series[index - 1] && value == series[index + 1]) {
pointBackgroundColor.push('transparent');
pointBorderColor.push('transparent');
} else {
pointBackgroundColor.push('white');
pointBorderColor.push('red');
}
});
myChart = new Chart(document.getElementById('chart'), {
type: 'line',
data: {
labels: labels,
datasets: [{
label: 'series1',
data: series,
pointBackgroundColor: pointBackgroundColor,
pointBorderColor: pointBorderColor,
pointHoverBackgroundColor: pointHoverBackgroundColor,
pointHoverBorderColor: pointHoverBorderColor
}]
},
options: {
maintainAspectRatio: false,
tooltips: {
mode: 'index',
intersect: false
},
hover: {
intersect: false
}
}
});
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.min.js"></script>
<canvas id="chart"></canvas>
WhiteHat solution is good but doesn't achieve the desired effect. When you hover over a hidden data point circle it should make the circle visible.
Here is how I did it
Step 1:
In the backend using PHP, I check if the prev and next point are different, and made a point radius 0.
$countPoints = count($points);
for ($i=1; $i < $countPoints-1; $i++) {
$prevVal = $chartChange[$i-1];
$nextVal = $chartChange[$i+1];
if($chartChange[$i] == $prevVal && $chartChange[$i] == $nextVal){
$points[$i] = 0;
}
}
Step 2 :
Add and pass the imploded array to the options object. Using [3,0,3,3] format
pointRadius: [{/literal}{$points}{literal}]
Edit:
Using only js
let labels = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'],
series = [10, 5, 5, 5, 5, 2, 3, 3, 3, 10],
pointRadius = [],
pointBackgroundColor = "rgb(230, 247, 238)",
pointBorderColor = "rgb(47, 186, 117)";
series.forEach(
(value, index) => {
if (value == series[index - 1] && value == series[index + 1]) {
pointRadius.push(0);
} else {
pointRadius.push(4);
}
});
myChart = new Chart(document.getElementById('myChart'), {
type: 'line',
data: {
labels: labels,
datasets: [{
label: 'series1',
fill: 'start',
pointRadius: pointRadius,
data: series,
backgroundColor:pointBackgroundColor,
borderColor:pointBorderColor,
pointHoverRadius: 4,
pointBackgroundColor: pointBackgroundColor,
pointBorderColor: pointBorderColor,
}]
},
options: {
tooltips: {
// mode: 'index',
intersect: false
},
tooltips: {
mode: 'index',
axis: 'x',
intersect: false
},
hover: {
intersect: false
},
maintainAspectRatio: false
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.bundle.min.js"></script>
<canvas id="myChart"></canvas>

Chart.js: change title/legend positon to right

I have a bar chart with a title on top. How can I go about changing the legend’s position to right of the chart. I searched on other forums but couldn’t find anything. Here is my code:
let ctx = document.getElementById('canvas');
let chart = new Chart(ctx, {
type: 'bar',
data: {
labels: [1, 2, 3, 4, 5],
datasets: [{
label: 'Votes',
data: [1, 2, 3, 4, 5],
backgroundColor: 'rgba(255, 0, 0, 0.2)'
}, {
label: 'Score',
data: [1, 2, 3, 4, 5],
backgroundColor: 'rgba(0, 255, 0, 0.2)'
}]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
You could set legend­'s position property to right in your chart options, to place the legend at the right side of the chart ...
options: {
legend: {
position: 'right'
},
...
}
ᴅᴇᴍᴏ
let ctx = document.getElementById('canvas').getContext('2d');
let chart = new Chart(ctx, {
type: 'bar',
data: {
labels: [1, 2, 3, 4, 5],
datasets: [{
label: 'Votes',
data: [1, 2, 3, 4, 5],
backgroundColor: 'rgba(255, 0, 0, 0.2)'
}, {
label: 'Score',
data: [1, 2, 3, 4, 5],
backgroundColor: 'rgba(0, 255, 0, 0.2)'
}]
},
options: {
legend: {
position: 'right'
},
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.5.0/Chart.min.js"></script>
<canvas id="canvas"></canvas>

Highcharts, graphing precipitation types, volumes and intensity over time

I have an automatic weather station that collects four different types of data for precipitation:
On/Off for precipitation event
total volume over time period in mm
intensity mm/hour and
precipitation type
i.e.:
0 No precipitation
40 Precipitation present
51 Light drizzle
52 Moderate drizzle
53 Heavy drizzle
Stacked bars can manage volume by precipitation type over time.
I would like to graph intensity by type by time. I think changing marker colours based on type is an answer to this. Is there a better solution please?
One suggestion based on your requirements could be a combination bar and line chart, using dual axes (as Grzegorz Blachliński mentioned).
As you noted, stacked bars would be helpful for showing comparative volume of each precipitation type. You could then overlay lines to show the intensity of each type over time.
I would suggest choosing colors that the user can easily relate to each precipitation type, especially between the two chart types.
Here's a rough draft I coded based on one of the demo charts from the Highcharts website:
$(function () {
$('#container').highcharts({
chart: {
type: 'column'
},
title: {
text: 'Precipitation'
},
xAxis: {
categories: ['Apples', 'Oranges', 'Pears', 'Grapes', 'Bananas']
},
yAxis: [{
min: 0,
title: {
text: 'Preipitation volume (mm)'
},
stackLabels: {
enabled: true,
style: {
fontWeight: 'bold',
color: (Highcharts.theme && Highcharts.theme.textColor) || 'gray'
}
}
},{
min: 0,
title: {
text: 'Preipitation intensity (mm/hr)'
},
opposite: true
}],
legend: {
//align: 'bottom',
//x: -30,
//verticalAlign: 'bottom',
//y: 25,
//floating: true,
backgroundColor: (Highcharts.theme && Highcharts.theme.background2) || 'white',
borderColor: '#CCC',
borderWidth: 1,
shadow: false
},
tooltip: {
headerFormat: '<b>{point.x}</b><br/>',
pointFormat: '{series.name}: {point.y}<br/>Total: {point.stackTotal}'
},
plotOptions: {
column: {
stacking: 'normal',
dataLabels: {
enabled: true,
color: (Highcharts.theme && Highcharts.theme.dataLabelsColor) || 'white',
style: {
textShadow: '0 0 3px black'
}
}
}
},
series: [{
name: 'rain',
data: [5, 3, 4, 7, 2],
color: '#b3b3ff'
}, {
name: 'sleet',
data: [2, 2, 3, 2, 1],
color: '#d9b3ff'
}, {
name: 'snow',
data: [3, 4, 4, 2, 5],
color: '#c2c2f0'
},{
name: 'rain intensity',
data: [5, 3, 4, 7, 2],
color: 'blue',
type: 'line',
yAxis: 1
}, {
name: 'sleet intensity',
data: [2, 2, 3, 2, 1],
color: 'purple',
type: 'line',
yAxis: 1
}, {
name: 'snow intensity',
data: [3, 4, 4, 2, 5],
color: 'indigo',
type: 'line',
yAxis: 1
}]
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://code.highcharts.com/highcharts.js"></script>
<script src="https://code.highcharts.com/modules/exporting.js"></script>
<div id="container" style="min-width: 310px; height: 400px; margin: 0 auto"></div>
If you like, you're also welcome to work from this code at the fiddle I created here: http://jsfiddle.net/brightmatrix/kbk53n43/
I hope this is helpful for you.