How to align vertical axis area on two charts in chart.js - javascript

in chart.js I'd like to have 2 charts (one under another) with ticks syncronized. Currently it looks so
as you can see dates are not aligned. Setting equal min-max values is impossible here since values are too different.
I think the solution would be to set equal width to both y-axes. The case is complicated by the second y-axes in upper chart, but may be it's possible to place an empty right scale on the bottom chart?
My current options for the top chart are
options: {
tooltips: {
enabled: true,
trigger: 'axis',
intersect: false,
mode : 'index'
},
responsive: true,
maintainAspectRatio: false,
layout: {
padding: {
// left: 500,
right: 0,
top: 0,
bottom: 0,
},
},
scales: {
xAxes: [
{
boundaryGap : false,
gridLines: {
display: false,
},
ticks: {
// Include a dollar sign in the ticks
callback: function(value, index, values) {
return value.split('.').slice(0,2).join('.');
}
},
},
],
yAxes: [
{
id: keys[0],
position: "left",
gridLines: {
drawBorder: false,
zeroLineColor: "rgba(147, 147, 147, 0.2)",
color: "rgba(147, 147, 147, 0.2)",
},
ticks: {
padding: 20,
fontColor: "#2C71C3",
beginAtZero: false,
},
}, {
id: keys[1],
position: "right",
gridLines: {
drawBorder: false,
color: "rgba(147, 147, 147, 0)",
},
ticks: {
padding: 20,
fontColor: "#C6C6C6",
beginAtZero: false,
},
},
],
},
and for the bottom one
options: {
tooltips: {
enabled: true,
trigger: 'axis',
intersect: false,
mode : 'index'
},
responsive: true,
maintainAspectRatio: false,
layout: {
padding: {
// left: 500,
right: 0,
top: 0,
bottom: 0,
},
},
scales: {
yAxes: [
{
ticks: {
reverse: true,
},
},
],
xAxes: [
{
gridLines: {
display: false,
},
ticks: {
// Include a dollar sign in the ticks
callback: function(value, index, values) {
return value.split('.').slice(0,2).join('.');
}
},
},
],
},

I dont know how to or if it is even possible to define a width for a scale, but what you can do is add a second Y axis on the right with the grid dissabled and the callback returning a few spaces for spacing
var options = {
type: 'line',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
borderWidth: 1
},
{
label: '# of Points',
data: [7, 11, 5, 8, 3, 7],
borderWidth: 1
}
]
},
options: {
scales: {
yAxes: [{
position: 'left'
},
{
position: 'right',
gridLines: {
display: false
},
ticks: {
callback: () => (' ')
}
}
]
}
}
}
var ctx = document.getElementById('chartJSContainer').getContext('2d');
new Chart(ctx, options);
<body>
<canvas id="chartJSContainer" width="600" height="400"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.js"></script>
</body>

Little late to the party, but it is possible to set a fixed width. I updated #LeeLenalee snippet with an example (both y axis have a 100px width in this case). This way, it is possible to align both graphs without any problem. Make sure to set a width that isn't too small for the labels though!
var options = {
type: 'line',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
borderWidth: 1
},
{
label: '# of Points',
data: [7, 11, 5, 8, 3, 7],
borderWidth: 1
}
]
},
options: {
scales: {
yAxes: [{
position: 'left',
afterFit: (scaleInstance) => scaleInstance.width = 100,
},
{
position: 'right',
afterFit: (scaleInstance) => scaleInstance.width = 100,
gridLines: {
display: false
},
ticks: {
callback: () => ''
}
}
]
}
}
}
var ctx = document.getElementById('chartJSContainer').getContext('2d');
new Chart(ctx, options);
<body>
<canvas id="chartJSContainer" width="600" height="400"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.js"></script>
</body>

Related

How to increase space between label and chart area in chart.js

All my labels are on the top of the bars. I can see this
this image
but I want that would be like this
this image
padding doesn't work for xAxes, but works for yAxes
legend: {display: false},
scales: {
xAxes: [{
position: 'top',
stacked: true,
ticks: {
stepSize: 1,
min: 0,
autoSkip: false,
fontColor: '#3f7ba2',
fontStyle: 600,
fontFamily: 'Italic',
},
gridLines: {
color: '#dedfe7',
tickMarkLength: 0,
}
}],
yAxes: [{
stacked: true,
ticks: {
min: 0,
fontColor: '#62aae8',
padding: 5
},
gridLines: {
color: '#dedfe7' //b5cce2
}
}],
}
This is an issue that only persists in chart.js version 2.6.0 and lower. As you can read in the release notes under the bug fixes it says that in PR 4403 ticks.padding option now applies to vertical and horizontal scales.
So to solve your issue you will need to update to a version of chart.js higher or equal to 2.7.0
const options = {
type: 'line',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
borderWidth: 1
},
{
label: '# of Points',
data: [7, 11, 5, 8, 3, 7],
borderWidth: 1
}
]
},
options: {
scales: {
xAxes: [{
position: 'top',
ticks: {
padding: 100
}
}],
}
}
}
const ctx = document.getElementById('chartJSContainer').getContext('2d');
new Chart(ctx, options);
<body>
<canvas id="chartJSContainer" width="600" height="400"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.0/Chart.js"></script>
</body>

Smaller scale for volume dataset in Chart JS

I'm graphing some stocks data and I wanted to put the volume in a smaller gray bar dataset at the bottom, like in Yahoo Finance.
What I want:
The small grey dataset is at the bottom.
What I get:
Three different Y scales and the size of the volume dataset is the same a the other.
My code:
When I create the chart:
new Chart(context, {
type: 'line',
data: {
labels: timestamps.map(n =>
(new Date(n * 1000)).toLocaleString()
),
datasets: [
dataset,
vdataset
]
},
options: {
maintainAspectRatio: false,
scales: {
xAxis: {
// type: 'time'
ticks: {
//autoSkip: true,
maxTicksLimit: 10
}
},
yAxes: [{
id: 'volume',
display: false
}],
y: {
beginAtZero: false
},
},
animation: {
duration: 0
},
plugins: {
autocolors: false,
annotation: {
annotations
}
},
tooltips: {
mode: 'nearest'
},
hover: {
intersect: false
}
}
});
The volume dataset:
{
type: 'bar',
label: `Volume`,
data: ...,
backgroundColor: 'transparent',
borderColor: 'grey',
fill: 'origin',
pointRadius: 0,
borderWidth: 2,
yAxisID: 'volume'
}
you need to give every dataset a yAxisID and then you should name your axis with that id like this:
Data:
var data = {
labels: labels,
datasets: [{
label: 'My First Dataset',
data: generateTestSeries(),
fill: false,
borderColor: 'rgb(75, 192, 192)',
tension: 0.1,
yAxisID: "something",
},
{
label: 'My Second Dataset',
data: generateTestSeries(),
fill: false,
borderColor: 'rgb(182, 50, 192)',
tension: 0.1,
yAxisID: "volume",
},
]
};
Scales:
scales: {
volume: {
axis: "y",
min: -80,
max: 60,
position: 'right',
},
something: {
axis: "y",
min: -20,
max: 70,
position: 'left',
}
}
Also you shouldn't have the list yAxes, that was how axes were defined in chartjs 2.x
Here is a fiddle to see this in use: JSFiddle
edit: If you want an invisible axis just set display to false as seen in the now updated Fiddle.

How to set percentage value by default on each bars in horizontal bar chart js

I have used horizontal bar chart from chart.js where i need percentage values to be shown next to each bar at right side? here is the bar sample image.
click here to view sample image of bar chart
Also these are the options i have tried :
xAxes: [
{
ticks: {
min: 0,
max: 100
},
grid: {
offset: false
}
},
],
yAxes: [
{
gridLines: {
display: false,
},
display: "right",
barPercentage: 0.8,
minBarLength: 2,
},
],
Is there any option which can turn the percentage values on at he right side of the horizontal bar chart?
Please click below image to see the expected output
click image expected output
You can make use of the datalabels plugin
Example:
<script src="https://cdn.jsdelivr.net/npm/chart.js#3.3.0/dist/chart.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels#2.0.0-rc"></script>
<canvas id="myChart" width="850" height="520"></canvas>
<script>
var ctx = document.getElementById('myChart');
Chart.register(ChartDataLabels);
Chart.defaults.set('plugins.datalabels', {
color: '#FE777B'
});
var myChart = new Chart(ctx, {
type: 'bar',
plugins: [ChartDataLabels],
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
data: [12, 19, 3, 5, 2, 3],
label: 'Advisor Closed MTD',
backgroundColor: 'rgb(192,111,94)',
barThickness: 25,
datalabels: {
color: '#FFCE56'
}
}],
},
options: {
indexAxis: 'y',
responsive: false,
plugins: {
datalabels: {
formatter: (val, context) => (`${val}%`),
anchor: 'end',
align: 'end',
labels: {
value: {
color: 'blue'
}
}
}
}
}
});
</script>

How to draw a line in line chart for single value in Charts.JS

I need to plot a single value in line chart. Currently i am using charts.JS library for line graph purpose.
The data will be varied some times i'll get the single data inside the data set at that time i need to plot the single value in the line chart.
I had tried with the charts.js annotation plugin but it didn't meet my requirements. which is like it wis overlapping the plotted point in the graph area.
My code
createLineChart() {
this.lineChart = new Chart(this.lineCanvas.nativeElement, {
type: "line",
data: {
labels:[],
datasets: [
{
fill: false,
backgroundColor: "#0168FF",
borderColor: "#0168FF",
pointBackgroundColor: "white", // wite point fill
pointBorderWidth: 1, // point border width
lineTension: 0,
pointBorderColor: "blue",
pointRadius: 4,
},
],
},
options: {
scales: {
yAxes: [
{
ticks: {
padding: 20,
beginAtZero: true,
min: 0,
stepSize: 100,
},
gridLines: {
drawBorder: false,
},
},
],
xAxes: [
{
// offset: true,
ticks: {
display: false,
//beginAtZero: true,
min: 0,
},
gridLines: {
zeroLineColor: "transparent",
drawBorder: false,
display: false,
},
//offset:true,
},
],
legend: {
display: false,
},
tooltips: {
enabled: false,
},
},
drawTime: "afterDraw", // (default)
} as ChartOptions,
// plugins: [ChartAnnotation]
},
});
}
To plot the data dynamically:
generateRandomDataSet(size) {
let yaxisArr = [];
let xaxisArr = [];
let random_data:any = this.getRandomData(size)
let maxYTickVal = Math.max.apply(Math, random_data.map((val) => {return val.yaxis}));
let maxVal = Math.ceil((maxYTickVal+1) / 10) * 10
for(let data of random_data) {
yaxisArr.push(data.yaxis)
xaxisArr.push(data.xaxis)
}
this.lineChart.data.datasets[0].data = yaxisArr
this.lineChart.config.data.labels = []
this.lineChart.config.data.labels = xaxisArr
this.lineChart.config.options.scales.yAxes[0].ticks.max =maxVal
this.lineChart.config.options.scales.yAxes[0].ticks.stepSize = maxVal/2
this.lineChart.update()
}
What i required
What i am getting
Thankyou.
There exists different approaches to solve this problem.
According to the answer I gave to a similar question, you can define an animation.onComplete function to draw the line.
In a comment on before mentioned answer, Lakshmansundeep suggested an approach where he defines the same data value three times but makes sure, pointRadius for the leading and ending data point is zero.
datasets: [{
data: [120, 120, 120],
...
pointRadius: [0, 4, 0],
pointHoverRadius: [0, 4, 0],
}],
For the second approach, please have a look at the code below.
new Chart('line-chart', {
type: "line",
data: {
labels: [null, 'A', null],
datasets: [{
data: [120, 120, 120],
fill: false,
backgroundColor: "#0168FF",
borderColor: "#0168FF",
pointBackgroundColor: "white",
pointBorderWidth: 1,
lineTension: 0,
pointBorderColor: "blue",
pointRadius: [0, 4, 0],
pointHoverRadius: [0, 4, 0],
}],
},
options: {
legend: {
display: false
},
tooltips: {
enabled: false
},
scales: {
yAxes: [{
ticks: {
padding: 20,
min: 0,
stepSize: 100
},
gridLines: {
drawBorder: false
}
}],
xAxes: [{
ticks: {
display: false
},
gridLines: {
zeroLineColor: "transparent",
drawBorder: false,
display: false
}
}]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<canvas id="line-chart" height="80"></canvas>

Is it possible to show labels for all lines?

Basically I have chartJS based line chart, with two lines. X axis has dates, and Y axes has price.
There is two lines (one for average price and one for minimum price).
So I was wondering, if it is at all possible to so that lets say I hover over a point for minimum price, the average price point's label pops up as well, and vice versa.
Or if that is not possible, maybe it is possible to make it so each label contains both values (the min and average price for that particular day).
Here is the code, I have so far:
var ctx = document.getElementById('price-history').getContext('2d');
ctx.height = 150;
var chart = new Chart(ctx, {
type: 'line',
data: {
labels: <?= json_encode($priceChangeData['labels']); ?>,
datasets: [
{
label: 'Minimali kaina',
backgroundColor: 'rgb(64, 127, 178)',
borderColor: 'rgb(64, 127, 178)',
borderWidth: 1,
data: <?= json_encode($priceChangeData['line']['price_min']); ?>,
fill: false
},
{
label: 'Vidutinė kaina',
backgroundColor: '#686868',
borderColor: '#686868',
borderWidth: 1,
data: <?= json_encode($priceChangeData['line']['price_avg']); ?>,
fill: false
}
],
},
options: {
responsive: true,
layout: {
padding: {
left: 20,
right: 15
}
},
scales: {
xAxes: [{
display: true,
scaleLabel: {
display: false,
labelString: 'Data'
}
}],
yAxes: [{
display: true,
stacked: false,
scaleLabel: {
display: false,
labelString: 'Kaina'
}
}]
}
}
});
I am assuming you are talking about the tooltip­'s label. In that case, you can set tooltips mode to index in your chart­'s options config, like so :
options: {
tooltips: {
mode: 'index'
},
...
ᴡᴏʀᴋɪɴɢ ᴇxᴀᴍᴘʟᴇ ⧩
var ctx = document.getElementById('price-history').getContext('2d');
ctx.height = 150;
var chart = new Chart(ctx, {
type: 'line',
data: {
labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May'], //<?= json_encode($priceChangeData['labels']); ?>,
datasets: [{
label: 'Minimali kaina',
backgroundColor: 'rgb(64, 127, 178)',
borderColor: 'rgb(64, 127, 178)',
borderWidth: 1,
data: [3, 1, 4, 2, 5], //<?= json_encode($priceChangeData['line']['price_min']); ?>,
fill: false
}, {
label: 'Vidutinė kaina',
backgroundColor: '#686868',
borderColor: '#686868',
borderWidth: 1,
data: [2, 4, 1, 5, 3], //<?= json_encode($priceChangeData['line']['price_avg']); ?>,
fill: false
}],
},
options: {
responsive: true,
tooltips: {
mode: 'index'
},
layout: {
padding: {
left: 20,
right: 15
}
},
scales: {
xAxes: [{
display: true,
scaleLabel: {
display: false,
labelString: 'Data'
}
}],
yAxes: [{
display: true,
stacked: false,
scaleLabel: {
display: false,
labelString: 'Kaina'
}
}]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.0/Chart.min.js"></script>
<canvas id="price-history"></canvas>

Categories

Resources