Age pyramid chart using chart.js - chart.js

I'm trying to create a chart using chart.js like this one (for example):
https://thebreadoflifeblog.files.wordpress.com/2013/01/uk-age-pyramid.png
I tried multiple possibilities and so far, the best one I found is using a simple trick of merging two horizontalBar charts:
But there are actually some problems.
As I said, this is actually two different charts. I would like to have only one object.
I removed the yAxis. I could leave one to display the yAxis labels, but in that case, one of the two graphics will be smaller than the other one. I would like the labels to be displayed between both charts.
The chart on the left is using negative value to achieve the right to left bars. Is there a way to 'revert' an axis ? I saw there is a 'Scale' method, but it seems complicated for just reverting the axis...
I would like to know if there is something I can do to create such chart easier and, most important, as one unique chart.

I ran up against the same problems as you, and managed to fix it using React ChartJS' HorizontalBarChart: but only one ;-)
Try stacking the yAxis and adding two datasets, using the options property
const populationPyramidOptions = {
scales: {
yAxes: [{
stacked: true
}],
xAxes: [{
stacked: false
}]
}
<HorizontalBar data={chartData} options={populationPyramidOptions} />
You can get a pretty good result:

if you use directly chartjs check about the solution here:
https://github.com/nknganda/pyramid_chart_example
The syntax for the options is not compatible with chartjs > 3.x
Below the updated code:
options = {
plugins: {
tooltip: {
intersect: true,
callbacks: {
label: function(context) {
var label = context.dataset.label || '';
var value = context.formattedValue;
var positiveOnly = value < 0 ? -value : value;
if (label) {
label += ': ';
}
if (context.parsed.y !== null) {
label += positiveOnly
}
return label;
},
},
},
legend: {
position: "bottom",
},
},
responsive: true,
scales: {
x: {
stacked: false,
ticks: {
beginAtZero: true,
callback: (v) => {
return v < 0 ? -v : v;
},
},
},
y: {
stacked: true,
ticks: {
beginAtZero: true,
},
position: "left",
},
},
indexAxis: 'y'
}
Note that tooltips is now tooltip and inside plugins, alongside with legend.
xAxies and yAxies are x and y and no more a list.
You may find more in the official chartjs doc.
Dataset don't change as you only need to make your values negative.

Related

Can I remove the Y-axis counter on chart.js?

I have a chart.js graph that looks like this:
What I'm trying to do is remove this counter of the y-axis:
I read through the documentation and searched for it here on Stack Overflow, but I can't seem to find what I'm looking for.
Thank you in advance.
You can set the ticks display to false in the options object like this:
options: {
scales: {
yAxes: [{
ticks: {
display: false
}
}]
}
}
Will give this result:
You can also use the callback to return an ampty string as tick which as side effect also removes the horizontal grid lines like this
options: {
scales: {
yAxes: [{
ticks: {
callback: () => ('')
}
}]
}
}
result:

Multiple line types in ChartJS

I have a project to recreate a Parametric EQ and am using Angular and Chartjs (angular-chart) to do so. Most of it's working, but, I have a need for two different line types in the same graph. Most of the filter types have lines connecting the points, but one of the filter types (band stop) should show a gap at the frequency. I can plot the X/Y of the points, but how do I get the span gaps to only apply to the one data set (and not the other 9)?
Thank you for your help!
//I think the relevant data:
$scope.data = [
[{x:-100,y:-90},{x:-60,y:-10},{x:-50,y:0}],
[{x:-100,y:-80},{x:-50,y:-20},{x:0,y:0}],
[{x:-100,y:-70},{x:-40,y:-30},{x:0,y:0}],
[{x:-100,y:-60},{x:-30,y:-40},{x:0,y:0}],
[{x:-100,y:-50},{x:-20,y:-50},{x:0,y:0}],
[{x:-100,y:-40},{x:-30,y:-60},{x:0,y:0}],
[{x:-100,y:-30},{x:-40,y:-70},{x:0,y:0}],
[{x:-100,y:-20},{x:-50,y:-80},{x:0,y:0}],
[{x:-100,y:-10},{x:-60,y:-90},{x:0,y:0}],
[{x:-100,y:0},{x:-70,y:-100},{x:0,y:0}]
];
$scope.options = {
tooltips:{enabled:false},
elements:{
point:{
radius:0
},
line:{
tension:.25,
fill:false
}
},
scales: {
xAxes:[{
type:'logarithmic',
display:true,
ticks:{
min:10,
max:10000,
callback: function(...args) {
const value = Chart.Ticks.formatters.logarithmic.call(this, ...args);
if (value.length) {
return Number(value).toLocaleString()
}
return value;
}
},
}],
yAxes: [
{
id: 'y-axis-1',
ticks:{min:-20,max:20,stepSize:10},
type: 'linear',
display: true,
position: 'left'
}
]
}
};
Seems like you can add it in the specific dataset as an option in which you want it:
https://www.chartjs.org/docs/latest/charts/line.html?h=spangaps

How to adjust axis width independently of gridLines lineWidth in chart.js graphs?

For my charts, I am trying to have thin gridlines and thicker axis lines (both x and y).
I found an option to adjust zeroLineWidth but this is only applicable for 0 and my axis does not start at 0 (E.g. x-axis are years, so starting at 0 makes no sense).
I found some discussions about it but as far as I can tell this does not work yet: https://github.com/chartjs/Chart.js/pull/4117.
I also tried to supply an array for the gridLines lineWidth option. The first value changes the thickness of the axis but also of the first gridline. So this is not fully independent.
scales: {
yAxes: [{
gridLines: {
lineWidth: [5,1,1,1,1,1,1,1,1]
}
}]
}
Maybe there is no way to do this right now but if anyone has a solution that would be great. Even a hacky one would be welcome.
It looks like there's no way to do this since (as you noticed) the axis line width is directly derived from the gridline width via this line in the Chart.js source:
var axisWidth = gridLines.drawBorder ? valueAtIndexOrDefault(gridLines.lineWidth, 0, 0) : 0;
But, since you say a hacky solution is welcome...
The below snippet demonstrates combining two axes to achieve the desired affect; one for the border and one for the gridlines.
It's ugly, but functional.
let border_axis = {
gridLines: {
drawOnChartArea: false,
lineWidth: 10,
color: "rgba(255, 127, 0, 0.25)"
},
ticks: {
beginAtZero: true
}
},
gridline_axis = {
beforeBuildTicks: function(axis) {
if (axis.id == "y-axis-1") {
// this callback ensures both axes have the same min/max to keep ticks and gridlines aligned.
axis.max = axis.chart.scales["y-axis-0"].max;
axis.min = axis.chart.scales["y-axis-0"].min;
}
},
gridLines: {
drawTicks: false,
drawBorder: false
},
ticks: {
display: false
}
},
chart = new Chart(document.getElementById("chart"), {
type: "line",
data: {
labels: [2001, 2002, 2003, 2004, 2005],
datasets: [{
data: [1, 2, 3, 4, 5]
}]
},
options: {
scales: {
xAxes: [border_axis, gridline_axis],
yAxes: [border_axis, gridline_axis]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.8.0/Chart.min.js"></script>
<canvas id="chart"></canvas>

ng2-chart text label wrap and graph width

I've been having a hard time finding documentation that will show me all the possible features on how to control/customize a chart and it's properties.
I wanted to know if i am displaying data in a horizontalBar chart is there a way to get the long label text to wrap? My graph size is affected by that feature and i can't find a way that will allow me to wrap label text.
I also wanted to know is there a property so that i can control the actual width of the graph with bars and not affecting the vertical label width. So i can give more room for the vertical label text and less space for the graph part.
Here is how i am currently rendering my graph:
barChartOptions: any = {
scaleShowVerticalLines: false,
responsive: true,
scales: {
xAxes: [{
ticks: {
beginAtZero:true,
max: 100
}
}],
yAxes: [{
ticks: {
}
}]
},
tooltips:{
mode: 'point'
}
};
barChartLabels: string[] = [];
barChartType: string = 'horizontalBar';
barChartLegend: boolean = false;
barChartData: any[] = [];
data: any;
colorsOverride: Array<Color> = [{
backgroundColor: '#6aaf6a',
hoverBackgroundColor: 'purple'
}];
getChartData(link:string){
this.service.getQuery(link).subscribe(
data => {
this.data = data;
this.barChartLabels = this.data.map(x => x.display);
this.chartData = this.data.map(x => x.value);
this.barChartData = [{data: this.chartData, label:'sample' }];
}
);
}

how to update chartjs2 option (scale.tick.max)

I have a Bar Chart with this Option
scales: {
yAxes: [{
ticks: {
display:false,
beginAtZero:true,
max: 1150
}
}]
}
now i change the values of my only dataset
barChartData.datasets[0].data = newData;
and update the chart
window.myBar.update();
How can i also update the max scale of the yAxes??
I have to use a max scale so i cant use suggestedMax.
found the Solution myself.
to change any options of the chart:
myBar.config.options
in my case
myBar.config.options.scales.yAxes[0].ticks.max = newValue
after this you have to call
window.myBar.update();
This is my solution for Line Chart.
You can use 'beforeFit' callback function that you can find here in the docs http://www.chartjs.org/docs/latest/axes/
In scale.chart.config.data.datasets you have the chart dataset
You must set the scale.options.ticks.max
Example:
scales: {
yAxes: [{
beforeFit: function (scale) {
// See what you can set in scale parameter
console.log(scale)
// Find max value in your dataset
let maxValue = 0
if (scale.chart.config && scale.chart.config.data && scale.chart.config.data.datasets) {
scale.chart.config.data.datasets.forEach(dataset => {
if (dataset && dataset.data) {
dataset.data.forEach(value => {
if (value > maxValue) {
maxValue = value
}
})
}
})
}
// After, set max option !!!
scale.options.ticks.max = maxValue
}
}
I hope I've been helpful.
The link https://www.chartjs.org/docs/latest/developers/updates.html has pretty up to date information.
the keey is to recognise what the chart object is. :)
I struggled for half a day reading various pages until i found the right way
use the baseChartDirective to access the chart directly by doing this -> this.chart
To update scales do this:
var barChartOptions = {
legend: { display: true },
scales: { yAxes: [{ id: 'yaxis', type: 'linear', position: 'left', ticks: { min: 0, max: maxScale } }]} };
this.chart.chart.options = barChartOptions;
then update the chart:
this.chart.chart.update();
you can pretty much update everything. Just need to realise what the chart object means in this page: https://www.chartjs.org/docs/latest/developers/updates.html
:)