I am using chart.js library and I am having a issue. I want the years axis to start from 0. Right now its starting from the negative value(-50 in my case).
Currently its coming like this-
What I want-
What I am trying-
var config = {
type: 'bar',
data: {
labels: ["Year 0", "Year 1", "Year 2", "Year 3", "Year 4", "Year 5", "Year 6"],
datasets: [{
type: 'line',
label: 'Accumulative Flow',
data: [0, -50, 20, 30, 40, 50],
borderColor: 'red',
fill: false,
lineTension: 0,
borderJoinStyle: 'miter',
xAxes: [{
barPercentage: 0.4
}]
}, {
type: 'bar',
label: 'Benifit(One time)',
backgroundColor: "#005998",
data: [40, 50, 60, 80, 50, 60],
}, ]
},
options: {
title: {
display: true,
text: 'Custom Chart Title'
},
scales: {
xAxes: [{
time: {
displayFormats: {
quarter: ' YYYY'
}
},
beginAtZero: true,
barPercentage: 0.3,
id: 'x-axis-label',
position: 'bottom',
scaleStartValue: 20,
gridLines: {
display: false
},
}],
yAxes: [{
id: 'y-axis-label',
ticks: {
max: 300,
min: -50,
stepSize: 50,
},
position: 'left',
gridLines: {
display: false
},
}]
},
legend: {
position: 'right'
},
maintainAspectRatio: false,
scaleBeginAtZero: true
}
};
var ctx = document.getElementById("myChart").getContext("2d");
new Chart(ctx, config);
.GraphContain {
max-height: 500px;
position: relative;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/moment.js/2.17.0/moment.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.5.0/Chart.bundle.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.5.0/Chart.min.js"></script>
<div class="GraphContain">
<canvas id="myChart" width="400" height="400"></canvas>
</div>
Is there any parameter to do this ?
Thanks In advance!
After reading thru the core scale source, I was able to come up with a way to configure your chart to get pretty dang close to your desired behavior.
It requires that we manually set gridline colors as well as manipulate the internal scale instance ticks array (which is used by the scale draw method to paint on the canvas).
First, in order to hide some gridlines but show others, I used the gridLines.color property and passed in an array of colors where the first index color is the default gridline color and all others are white (the first index is used to color the "zero" gridline). Note, since we are later going to manipulate the internal scale ticks array, you must add an extra index to the color array with a color of white. Here is an example of what I mean.
gridLines: {
// since we only want to show the "zero line" gridline (chart.js
// uses the color of the first index to paint this line), we
// set the first index to the default color and all others to white
// note, later we add a "dummy" tick (explained later) so the length
// of this array has to be 1 greater than the number of gridlines you
// want displayed
color: [
"rgba(0, 0, 0, 0.1)", // this is for the zero line
"rgb(255, 255, 255)",
"rgb(255, 255, 255)",
"rgb(255, 255, 255)",
"rgb(255, 255, 255)",
"rgb(255, 255, 255)",
"rgb(255, 255, 255)",
"rgb(255, 255, 255)",
"rgb(255, 255, 255)",],
}
}
Next, we use the afterTickToLabelConversion scale callback configuration property to manipulate the internal scale ticks array to force the gridlines to display like you want. Here is the implementation that works for your use case.
// we will use this callback to manipulate the ticks array
// before they are drawn on the canvas
afterTickToLabelConversion: function(scaleInstance) {
// the top gridline (which is at index 0) is always shown
// so to overcome this we add a "dummy" tick at index 0
scaleInstance.ticks.unshift(null);
// we have to do the same this to this tick array as well
// because it uses the values in this array to map to the data
scaleInstance.ticksAsNumbers.unshift(null);
// since we have added an extra tick, we need to move the
// zero line index to point to the new index of 0
scaleInstance.zeroLineIndex++
}
So putting it all together you end up with a chart that looks like this.
Check out this codepen for a working example (note, I left the other attempts to solve this...so see option 3 at the bottom).
Related
I want to create a single bar using a bar chart. The setup is that the user can select different choices (representing the colors). In this example (codesandbox link below) I have a bar that has a max value of 90.000. The three chosen values are 20.000, 30.000 and 15.000, totaling 65.000.
Now, my goal is to have a border around this entire bar, not just the colors. In the image below this is represented with the red border. Currently I do this by putting a container element around my canvas element, but I would like to do this in the canvas itself, without using a container element. Someone has an idea on how to do this?
Codesandbox link
You need to define different dataset properties such as borderSkipped, borderRadius, borderWidth to achieve what you're looking for.
Don't know why but I also had to define the data of the dataset at the bottom as a floating bar in order to see the rounded border.
data: [[0, 20000]]
Please take a look at the runnable code below and see how it could work.
new Chart('chart', {
type: 'bar',
data: {
labels: [''],
datasets: [{
label: "currentAmount",
data: [[0, 20000]],
backgroundColor: "#bbb",
borderColor: "#f00",
borderWidth: 2,
borderSkipped: 'top',
borderRadius: 30,
barPercentage: 0.5
},
{
label: "amount 1",
data: [30000],
backgroundColor: "orange",
borderColor: "#f00",
borderWidth: { left: 2, right: 2 },
barPercentage: 0.5
},
{
label: "amount 2",
data: [15000],
backgroundColor: "green",
borderColor: "#f00",
borderWidth: { left: 2, right: 2 },
barPercentage: 0.5
},
{
label: "remaining",
data: [25000],
backgroundColor: "#fff",
borderColor: "#f00",
borderWidth: 2,
borderSkipped: 'bottom',
borderRadius: 30,
barPercentage: 0.5
},
]
},
options: {
plugins: {
legend: {
display: false
},
tooltip: {
displayColors: false
}
},
scales: {
y: {
display: false,
stacked: true,
beginsAtZero: true
},
x: {
display: false,
stacked: true
}
}
}
});
canvas {
max-width: 200px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.8.0/chart.min.js"></script>
<canvas id="chart"></canvas>
I'm trying to display live data given the past day, week, month, etc. Currently, the graph displays only a section of live data but I'd like for more to be shown. I'm using a barchart for now, and I'm aware of the live data having the same time logged, but I wanted to see if there is a way for more than 20 points to be shown on the chart. I added the code that I think I should edit. I've tried ticks and bounds but it's a little difficult for me to navigate exactly what I want on the chart.js site.
Edit: after some fixes to my database, I can see more data points displayed. However, when I choose "past month", I am supposed to have every recorded point from the past month. Would a scatter plot with a line through it be more reasonable to display?
Below is the application test image and code block:
Application test image
var myChart = document.getElementById("chart").getContext('2d');
gradient = myChart.createLinearGradient(0, 0, 0, 400);
gradient.addColorStop(0, 'rgba(29, 140, 248, 0.75)');
gradient.addColorStop(0.5, 'rgba(29, 140, 248, 0.5)');
gradient.addColorStop(1, 'rgba(29, 140, 248, 0)');
// Global Options
Chart.defaults.global.defaultFontFamily = 'inherit';
Chart.defaults.global.defaultFontSize = 18; //Effects x and y's number font size
Chart.defaults.global.defaultFontColor = '#777';
barchart = new Chart(myChart, {
type:'bar',
data: {
labels: {{ data.x_vals | tojson }},
datasets:[{
label:'Liquid Level',
data: { { data.y_vals } },
backgroundColor: gradient,
borderWidth:1, //Effects plotted line on chart
borderColor:'white',
hoverBorderWidth:1,
hoverBorderColor:'white',
barThickness:15
}]
},
options: {
legend: {
display:true,
position:'right',
labels: { fontColor:'#000' }
},
scales: {
yAxes: [{
display: true,
ticks: {
suggestedMin: 0,
steps: 10,
stepValue: 10,
max: 100
}
}],
xAxes: [{
display: true,
ticks: {
autoSkip: true,
padding: 4,
fontSize: 12
}
}]
},
layout:{
padding:{
left:0,
right:0,
bottom:0,
top:0
}
}
}
});
In my project I need to plot, on web page, an ECG diagram.
My scenario is the following one: I have an ECG device connected to a mobile phone via bluetooth.
By using this device and relative SDK on Android I can plot diagram on my mobile by using data sent by the device.
On mobile device the heart wave is well plotted (by using device SDK for Android)
So far so good.
Generally speaking an ECG diagram is a diagram like this one
On server side I'm able in receiving data sent by the device and I'm using chartjs (version 2.9.3) in order to plot the diagram.
My result is this one:
As you can see it's not a clear ECG diagram (let's not focus on grid, I need to change them and use an image as background because in real ECG diagram the grid has x and y axis in millimeters)
By reading this diagram a doctor will think that basically it is a fibrillation heart diagram that is not real. I can't show the PQRST waves correctly.
I made the following assumptions:
on X axis I'll put the time (but I'm not sure this is correct..)
on Y axis I'll put the heart electric voltage measured by the ECG device and these measurements are correct
This is the code I wrote:
var chartColors = {
red: 'rgb(255, 0, 0)',
orange: 'rgb(255, 159, 64)',
yellow: 'rgb(255, 205, 86)',
green: 'rgb(75, 192, 192)',
blue: 'rgb(54, 162, 235)',
purple: 'rgb(153, 102, 255)',
grey: 'rgb(201, 203, 207)',
black:'rgb(0, 0, 0)'
};
var color = Chart.helpers.color;
var config = {
type: 'line',
data: {
//labels: [],
datasets:
[{
backgroundColor: color(chartColors.red).alpha(0.5).rgbString(),
borderColor: chartColors.black,
fill: false,
cubicInterpolationMode: 'monotone',
data: []
}]
},
options: {
responsive: true,
legend: {
display: false
},
title: {
display: false,
text: ''
},
elements: {
point:{
radius: 0
}
},
scales: {
xAxes:
[{
ticks: {
display: false, //this will remove only the label
},
gridLines: {
color: "rgb(247, 174, 210)"
//color: "rgba(0, 0, 0, 0)"
},
type: 'time',
time:
{
unit: 'seconds',
unitStepSize: '1'
}
}],
yAxes: [{
gridLines: {
color: "rgb(247, 174, 210)"
//color: "rgba(0, 0, 0, 0)"
},
ticks: {
/*max: 500,
min: 0,*/
stepSize:1,
display: false //this will remove only the label
}
}]
},
tooltips: false,
hover:false
}
};
var context = $("#"+idEcg)[0].getContext('2d');
var ecgDiagram = new Chart(context, config);
var ecgDataFromServer = ..... //recover data from ecgDataFromServer.
//Note Every point has the following properties:
//tempo: it's the time when mobile device receives the measurement
//tensione: it's the heart electric voltage measured
for( var t = 0; t < ecgDataFromServer.length; t++ ){
var ecgDataPoint = ecgDataFromServer[t];
chart.config.data.datasets[0].data.push({
x: new Date(ecgDataPoint.tempo),
y: ecgDataPoint.tensione
});
}
chart.update({
preservation: true
});
I'm stucked on this diagram from several days and I can't figure how I can represent as I wish.
I can't find some formula that eventually allows to me to make a good data interpolation.
Now I'm evaluating to use d3.js as library (but I'm very new to it and I need to learn it; this is the reason I put d3.js tag as well).
I may also use some server side strategy (in java, matalab, R or any other) in order to generate a PNG o JPG image of the diagram and represents it.
Can anyone suggest to me if what I need it's feasible?
How can I plot my diagram like the ecgDiagram I showed?
Thank you
Angelo
Is there anyway to implement an animated indicator for chart.js doughnut charts? What I am looking to accomplish looks like this:
I've got the doughnut part of the chart complete, but can't seem to find a way to add the value (large text: 89% (dynamic)) or the dot for the indicator.
The code i've used is the following:
HTML
<canvas id="dashboardChart" width="400" height="400"></canvas>
JS
var ctx = document.getElementById("dashboardChart");
var dashboardChart = new Chart(ctx, {
type: 'doughnut',
data: {
labels: ["Red", "Orange", "Green"],
datasets: [{
label: '# of Votes',
data: [33, 33, 33],
backgroundColor: [
'rgba(231, 76, 60, 1)',
'rgba(255, 164, 46, 1)',
'rgba(46, 204, 113, 1)'
],
borderColor: [
'rgba(255, 255, 255 ,1)',
'rgba(255, 255, 255 ,1)',
'rgba(255, 255, 255 ,1)'
],
borderWidth: 5
}]
},
options: {
rotation: 1 * Math.PI,
circumference: 1 * Math.PI,
legend: {
display: false
},
tooltip: {
enabled: false
},
cutoutPercentage: 95
}
});
Any help is greatly appreciated!
To get you started, I was able to get a half-doughnut, or how I call it, a speedometer graph, using the following options configuration:
var chart = new Chart(canvas, {
type: 'doughnut',
data: ['400', '200'],
options: {
rotation: -90,
circumference: 180,
}
chartjs version 3.5.1
Original Answer:
I'm not sure there is a quick and simple solution to this.
Perhaps you can create a second pie chart directly on top of the existing one and have that pie chart only have circumference for a few pixels but rotated at at X percent, in this case 89%. A bit of Maths is required to work out where 89% of half a circle is. this won't give you a nice circle marker as per your image above. It will give you a small coloured segment where that circle marker ought to be and with the help of some css this second pie chart segment can be rounded off to look like what you want.
The second pie chart may look like this ...
var ctx2 = document.getElementById("dashboardChart2");
var dashboardChart2 = new Chart(ctx2, {
type: 'doughnut',
data: {
labels: ["Purple"],
datasets: [{
label: '# of Votes',
data: [5],
backgroundColor: [
'rgba(159, 90, 253, 1)'
],
borderColor: [
'rgba(255, 255, 255 ,1)',
],
borderWidth: 2
}]
},
options: {
rotation: 1 * Math.PI,/** This is where you need to work out where 89% is */
circumference: 1 * Math.PI,/** put in a much smaller amount so it does not take up an entire semi circle */
legend: {
display: false
},
tooltip: {
enabled: false
},
cutoutPercentage: 95
}
});
As for the large 89% that will probably involve css. Positioning the text directly 'infront' of the pie chart (involving things like z-index and position absolutely)
New Answer:
Perhaps you can create a doughnut chart directly on top of the existing one and have that doughnut chart have its first and third 'bars' with an opacity of 0 so they can not be seen. If the first bar has a value of 88.5 and the second bar has a value of 1 and the third bar has a value of 10.5 you will have effectively put the second bar at 89%, with a width of 1% (88.5 + 1 + 10.5 = 100).
datasets: [{
data: [88.5, 1,10.5],// how much space each bar should take
backgroundColor: [
"rgba(0,0,0,0)", // bar 1: opacity 0
"rgba(255,255,255,1)", // bar 2 is white
"rgba(0,0,0,0)", // bar 3: opacity 0
],
borderColor: [
'rgba(0, 0, 0 ,0)',// bar 1 border opacity 0
'rgba(46, 204, 113, 1)',// bar 2 border is green
'rgba(0, 0, 0 ,0)'// bar 3 border opacity 0
],
borderWidth: 3
}]
As for the large 89% that will probably involve css. Positioning the text directly 'infront' of the pie chart
.percent {
position: absolute;
left: 50%;
transform: translate(-50%, 0);
font-size: 80px;
bottom: 0;
}
After having a go in a fiddle I have this ...
Example Here:
https://jsfiddle.net/rjtsbeLc/3/
Note that with relative and absolute positioning I have placed the second doughnut chart on top of the existing one, and the percentage text on top of them at the bottom in the centre.
.outer {
position: relative;
width: 600px;
height: 400px;
}
canvas {
position: absolute;
}
It isn't quite what you are looking for as the 'circle' is rectangular but I came accross this, it might help you work out how to round off the rectangle into a circle ...
Chart.js Doughnut with rounded edges https://stackoverflow.com/a/36964890/5178301
When I use a left and right line plot in Chartjs, I sometimes get inconsistent Y Axis tick interval counts. So, I might have like 7 intervals on the left, and Chartjs automatically might put 10 on the right. An example of a hard-to-read chart would look like this:
Therefore, the question is -- how do I set the Y Axis tick interval on the right so that it is consistent with the left?
When defining the options.scales.yAxes[1] (the right Y axis), add a beforeUpdate callback so that you can tweak its stepSize, like so:
beforeUpdate: function(scale) {
// get the max data point on the right
var nMax = Math.max.apply(Math,scale.chart.config.data.datasets[1].data);
// Get the count of ticks on the left that Chartjs automatically created.
// (Change the 'Clicks' to the 'id' property of that left Y Axis.)
var nLeftTickCount = scale.chart.scales['Clicks'].ticks.length;
// Add some exception logic so that we don't go less than 7 (a failsafe).
// Also, we need the count of spaces between the ticks,
// not the count of total ticks.
nLeftTickCount = (nLeftTickCount < 7) ? 7 : nLeftTickCount - 1;
// compute our tick step size
var nStepSize = nMax / nLeftTickCount;
// Assign the right Y Axis step size.
scale.chart.options.scales.yAxes[1].ticks.stepSize = nStepSize;
return;
}
This creates a consistent chart like so:
Here is the entire example of the area chart with a left and right Y Axis:
<script src="vendor/chartjs/chart.js/dist/Chart.min.js"></script>
<div class="chart-container">
<canvas id="my-canvas" width="400" height="200" style="width:100%;"></canvas>
</div>
<script>
var tsCanvas = document.getElementById('my-canvas');
var tsChart = new Chart(tsCanvas, {
type: 'line',
data: {
labels: ["Feb 1","Feb 16","Mar 1","Mar 16","Mar 22"],
datasets: [
{
label: 'Clicks',
yAxisID: 'Clicks',
data: [10706, 12847, 11516, 10464, 1204],
backgroundColor: 'rgba(26, 187, 156, 0.2)',
borderColor: 'rgba(26, 187, 156, 1)',
pointBackgroundColor: 'rgba(26, 187, 156, 1)',
borderWidth: 0.5,
pointRadius:2,
tension:0
},
{
label: 'Revenue',
yAxisID: 'Revenue',
data: [106.66, 342.86, 313.67, 461.18, 25.84],
backgroundColor: 'rgba(90, 144, 197, 0.2)',
borderColor: 'rgba(90, 144, 197, 1)',
pointBackgroundColor: 'rgba(90, 144, 197, 1)',
borderWidth: 0.5,
pointRadius:2,
tension:0
}
]
},
options: {
maintainAspectRatio:false,
hover: {
animationDuration:0
},
tooltips: {
mode: 'index',
multiKeyBackground: 'rgba(255,255,255,0.55)'
},
scales: {
yAxes: [
{
id: 'Clicks',
type: 'linear',
position: 'left',
scaleLabel: {
display:true,
labelString: 'Clicks'
},
ticks: {
beginAtZero:true
}
},
{
beforeUpdate: function(scale) {
var nMaxRev = Math.max.apply(Math,scale.chart.config.data.datasets[1].data);
var nLeftTickCount = scale.chart.scales['Clicks'].ticks.length;
nLeftTickCount = (nLeftTickCount < 7) ? 7 : nLeftTickCount - 1;
var nTickInterval = nMaxRev / nLeftTickCount;
scale.chart.options.scales.yAxes[1].ticks.stepSize = nTickInterval;
return;
},
id: 'Revenue',
type: 'linear',
position: 'right',
scaleLabel: {
display:true,
labelString: 'Revenue'
},
ticks: {
beginAtZero:true
}
}
],
xAxes: [
{
type: 'category',
ticks: {
minRotation:50,
maxRotation:50
}
}
]
}
}
});
</script>