Related
I use the chart.js plugin to make JavaScript charts. The link of the plugin: https://www.chartjs.org/ I would like the zeros of the Y-axes to be aligned without the scales being the same. Put the two zeros at the same level without the curves having the same scales.
Here is a picture of the chart.
Here is the code for the graph below:
let chart = new Chart(ctx, {
type: 'bar',
data: {
labels: charts.bar.months.short,
datasets: [
{},
{},
{
label: '{{ trans._("TREASURY")|ucfirst }}',
backgroundColor: 'rgba(0,0,0,0)',
borderColor: charts.colors['secondary'],
data: treasury.n,
type: 'line',
yAxisID: 'treasury',
lineTension: 0,
pointHitRadius:10
},
]
},
options: {
tooltips: charts.bar.tooltips,
maintainAspectRatio: false,
legend: {
display:false
},
scales: {
xAxes: [{
barPercentage: 0.8,
ticks: {
fontSize:charts.fontSize
}
}],
yAxes: [{
id:"turnover",
position: 'left',
ticks: {
fontSize:charts.fontSize,
beginAtZero: true,
callback: formatAxisAmountTruncate,
fontColor: charts.colors.success,
fontStyle: 'bold',
}
}, {
id:"charges",
position: 'left',
ticks: {
fontSize:charts.fontSize,
beginAtZero: true,
callback: formatAxisAmountTruncate,
fontColor: charts.colors.warning,
fontStyle: 'bold',
}
}, {
id:"treasury",
position: 'right',
ticks: {
fontSize:charts.fontSize,
beginAtZero: true,
callback: formatAxisAmountTruncate,
fontColor: charts.colors.secondary,
fontStyle: 'bold',
},
gridLines: {
display:false
}
}]
}
}
});
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.
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>
I'm having some trouble trying to change the backgroundColor of a specific chart area between two yAxis ticks.This is what I have so far:
And this is what I wanted:
I've seen some similar posts about that and people recommend using Annotation to do this. I tried using it on my chart and it didn't work. This is my first time building a chart with chart.js so I'm still learning. Here's my code:
var profileChart = new Chart(ctx1, {
type: "line",
data: {
labels: ["", "D", "I", "S", "C", ""],
datasets:[{
data: [],
borderWidth: 1,
pointBackgroundColor: "black",
backgroundColor: "black",
borderColor: "black",
fill: false,
lineTension: 0,
yAxisID: 'first-y-axis'
},
{
yAxisID: 'third-y-axis'
}],
},
options: {
title: {
display: true,
text: 'Gráfico do Perfil DISC',
fontSize: 20,
},
scales: {
yAxes: [{
id: 'first-y-axis',
type: 'linear',
gridLines: {
drawOnChartArea: false
},
scaleLabel: {
display: true,
padding: '15px',
labelString: 'Intensity'
},
ticks: {
max: 28,
min: 1,
stepSize: 1
}
},
{
id: 'second-y-axis',
type: 'linear',
position: 'left',
gridLines: {
drawOnChartArea: true
},
ticks: {
display: false,
min: 1,
max: 8,
stepSize: 1
}
},
{
id: 'third-y-axis',
position: 'right',
type: 'linear',
gridLines: {
drawOnChartArea: false
},
scaleLabel: {
display: true,
padding: '10px',
labelString: 'Segment'
},
ticks: {
max: 7.5,
min: 0.5,
stepSize: 1
},
afterTickToLabelConversion: function(scaleInstance) {
scaleInstance.ticks[0] = null;
scaleInstance.ticks[scaleInstance.ticks.length - 1] = null;
scaleInstance.ticksAsNumbers[0] = null;
scaleInstance.ticksAsNumbers[scaleInstance.ticksAsNumbers.length - 1] = null;
},
}]
},
legend: {
display: false
},
tooltips: {
callbacks: {
label: function(tooltipItem) {
return tooltipItem.yLabel;
}
}
}
},
annotation: {
drawTime: "afterDraw",
annotations: [{
id: 'box1',
type: 'box',
yScaleID: 'second-y-axis',
yMin: 12.5,
yMax: 16.5,
backgroundColor: 'grey',
}]
}
});
You can draw the rectangle directly on the canvas using the Plugin Core API. The API offers a range of hooks that may be used for performing custom code.
In your amended code below, I use the beforeDraw hook to draw the rectangle through CanvasRenderingContext2D.fillRect().
var profileChart = new Chart('canvas', {
type: "line",
plugins: [{
beforeDraw: chart => {
var ctx = chart.chart.ctx;
var xAxis = chart.scales['x-axis-0'];
var yAxis = chart.scales['first-y-axis'];
ctx.save();
ctx.fillStyle = 'lightgray';
ctx.beginPath();
var yTop = yAxis.getPixelForValue(16.5);
var yBottom = yAxis.getPixelForValue(12.5);
ctx.fillRect(xAxis.left, yTop, xAxis.right - xAxis.left, yBottom - yTop);
ctx.stroke();
ctx.restore();
}
}],
data: {
labels: ["", "D", "I", "S", "C", ""],
datasets: [{
data: [,25.5, 8, 7.5, 11],
borderWidth: 1,
pointBackgroundColor: "black",
backgroundColor: "black",
borderColor: "black",
fill: false,
lineTension: 0,
yAxisID: 'first-y-axis'
},
{
yAxisID: 'third-y-axis'
}
],
},
options: {
title: {
display: true,
text: 'Gráfico do Perfil DISC',
fontSize: 20,
},
scales: {
yAxes: [{
id: 'first-y-axis',
type: 'linear',
gridLines: {
drawOnChartArea: false
},
scaleLabel: {
display: true,
padding: '15px',
labelString: 'Intensity'
},
ticks: {
max: 28,
min: 1,
stepSize: 1
}
},
{
id: 'second-y-axis',
type: 'linear',
position: 'left',
gridLines: {
drawOnChartArea: true
},
ticks: {
display: false,
min: 1,
max: 8,
stepSize: 1
}
},
{
id: 'third-y-axis',
position: 'right',
type: 'linear',
gridLines: {
drawOnChartArea: false
},
scaleLabel: {
display: true,
padding: '10px',
labelString: 'Segment'
},
ticks: {
max: 7.5,
min: 0.5,
stepSize: 1
},
afterTickToLabelConversion: function(scaleInstance) {
scaleInstance.ticks[0] = null;
scaleInstance.ticks[scaleInstance.ticks.length - 1] = null;
scaleInstance.ticksAsNumbers[0] = null;
scaleInstance.ticksAsNumbers[scaleInstance.ticksAsNumbers.length - 1] = null;
},
}
]
},
legend: {
display: false
},
tooltips: {
callbacks: {
label: function(tooltipItem) {
return tooltipItem.yLabel;
}
}
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.bundle.min.js"></script>
<canvas id="canvas" height="200">
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>