Chart.js: stack the bars to the left - javascript

I need to stack the bars in the bar chart to the left as per the image attached
is there a way to do that in chart.js?
EDIT:
Just to clarify what I am looking for.
The number of the bars in my chart is dynamic, if there are 10 of them then chart looks fine but if there are only 2 they each take 50% of the width of the chart (see picture #2)
I want both of those bars to be exactly the same width as if there were 10 of them and be stacked to the left.
One option that I'm currently considering is just to add (10 - no of bars) bars with 0 value so that they won't be visible. But I'm hoping that there is a better solution.
Thanks.

Instead of creating a graph with 10 empty bar charts, then populate it with your values, I think it would be better to add empty values to reach the number of 10 (same idea though).
If you take a look in the Chart.js documentation, you can see that you can create plugins for your charts and graphs. Plugins are extremely useful when editing your chart (instead of just hardcoding what you want) since they allow you to handle what is happening while creating your charts.
For instance : beforeUpdate, afterDraw are some of the events you can handle with plugins.
Now, you must know that the chart object contains a lot of information :
If you want to edit a global option, you'd check chart.config.options
If you want to edit a specific chart, you'd check chart.config.data
In our case, we'd need the data attribute.
If you take a deep look in it, you'd see that the number of values come from the lengh of both data.labels and data.datasets[n].data (n being the nth dataset).
Now that you know what to do, and how to do it, you can do it.
I still made a quick example of what you are looking for :
var ctx = document.getElementById("myChart").getContext("2d");
// stores the number of bars you have at the beginning.
var length = -1;
// creates a new plugin
Chart.pluginService.register({
// before the update ..
beforeUpdate: function(chart) {
var data = chart.config.data;
for (var i = data.labels.length; i < data.maxBarNumber; i++) {
length = (length == -1) ? i : length;
// populates both arrays with default values, you can put anything though
data.labels[i] = i;
data.datasets[0].data[i] = 0;
}
},
// after the update ..
afterUpdate: function(chart) {
console.log(chart);
var data = chart.config.data;
if (length == -1) return;
// prevents new charts to be drawn
for (var i = length; i < data.maxBarNumber; i++) {
data.datasets[0]._meta[0].data[i].draw = function() {
return
};
}
}
});
var data = {
// change here depending on how many bar charts you can have
maxBarNumber: 10,
labels: [1, 2, 3, 4, 5, 6, 7],
datasets: [{
label: "dataset",
backgroundColor: 'rgba(255, 99, 132, 0.2)',
borderColor: 'rgba(255,99,132,1)',
borderWidth: 1,
data: [65, 59, 80, 81, 56, 55, 40],
}]
};
var myBarChart = new Chart(ctx, {
type: 'bar',
data: data,
options: {
scales: {
xAxes: [{
display: false
}],
yAxes: [{
stacked: true
}]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.2.1/Chart.min.js"></script>
<canvas id="myChart" width="400" height="400"></canvas>

You can use Array.prototype.reverse() to reverse the data if it is currently stacked to the right. Otherwise you will need to use some type of sorting to go from largest data to smallest data.

Related

apexcharts different options for axis range

Let's take a look at the simple chart data:
it has (x,y) pairs:
x
y
0
-3
1
2
2
7
3
8
4
15
5
0
The idea is to create a basic line chart, using VueJS in my case, but the idea can be generalized to JavaScript.
I have a series array of objects, where each object has x and y coordinates:
series = [
{
x: 0,
y: -3
},
{
x: 1,
y: 2
},
...
]
This series is part of options object:
const options = {
chart: {
type: 'line'
},
series: series
}
const chart = new ApexCharts(document.querySelector("#chart"), options);
chart.render();
And the chart is rendered.
Now, let's say I want to append the data to that chart - add 2 new (x,y) pairs
const newData = [
{
x: 6,
y: 20
},
{
x: 7,
y: -10
}
]
chart.appendData([{ data: chartData }])
I would also like that newly appendedData has, for example, different color, fill, or something else - so newly added data displays differently than old data.
Feel free to point me to documentation if I missed anything, but I searched through apex chart methods, and the only thing that looks remotely close to this would be inside
updateOptions() method, the redrawPath flag (updateOptions docs:
When the chart is re-rendered, should it draw from the existing paths
or completely redraw the chart paths from the beginning. By default,
the chart is re-rendered from the existing paths
In order to style the new data differently, you'll want to put these data points into a different series using the appendSeries method:
const newData = [
{
x: 6,
y: 20
},
{
x: 7,
y: -10
}
]
chart.appendSeries({
name: "series-2", // optional
data: newData
})
Most of the styling in ApexCharts is done based on series (more specifically seriesIndex). So by placing the new data in a separate series you'll be able to style this second series using an array of, for example, colors.
You could either specify the color you would like to use as you append the new series of data using the updateOptions method you mention, or you can specify it in advance.
chartOptions: {
colors: ["#546E7A", "#E91E63"],
}
When working with "Numeric paired values in XY properties", the xaxis type also has to be explicitly set to numeric:
chartOptions: {
xaxis: {
type: 'numeric',
},
}
The tricky bit comes when you want to add more data a second time (or third, more time). There are two approaches I can think of here:
Shuffle the existing data across to the original series (append series-2 to series-1) - and overwrite series-2 with your new data. You don't need to edit the colors in chartOptions.
You could shuffle the colors along. If you want all "old" data to have the same color, simply prepend the colors array with your base color every time you add a new series. Or if you want each series to have a different color, just append a color every time you add a new series.

How to change color text in graph when use chart js [duplicate]

Is there a way to set a different color to a datapoint in a Line Chart if its above a certain value?
I found this example for dxChart - https://stackoverflow.com/a/24928967/949195 - and now looking for something similar for ChartJS
In updating to version 2.2.2 of ChartJS, I found that the accepted answer no longer works. The datasets will take an array holding styling information for the properties.
In this case:
var pointBackgroundColors = [];
var myChart = new Chart($('#myChart').get(0).getContext('2d'), {
type: 'line',
data: {
datasets: [
{
data: dataPoints,
pointBackgroundColor: pointBackgroundColors
}
]
}
});
for (i = 0; i < myChart.data.datasets[0].data.length; i++) {
if (myChart.data.datasets[0].data[i] > 100) {
pointBackgroundColors.push("#90cd8a");
} else {
pointBackgroundColors.push("#f58368");
}
}
myChart.update();
I found this looking through the samples for ChartJS, specifically this one: "Different Point Sizes Example"
With recent versions of chart.js I would recommend doing this with scriptable options.
Scriptable options give you an easy way to vary the style of a dataset property (e.g. line point colour) dynamically according to some function you provide. Your function is passed a 'context' object that tells it the index and value of the point etc. (see below).
Most chart properties can be scripted; the dataset properties for each chart type tell you the exact list (e.g. see here for line chart).
Here is how you might use scriptable options on a line chart (based on the example in the docs). On this chart negative data points are shown in red, and positive ones in alternating blue/green:
window.myChart = Chart.Line(ctx, {
data: {
labels: x_data,
datasets: [
{
data: y_data,
label: "Test Data",
borderColor: "#3e95cd",
fill: false,
pointBackgroundColor: function(context) {
var index = context.dataIndex;
var value = context.dataset.data[index];
return value < 0 ? 'red' : // draw negative values in red
index % 2 ? 'blue' : // else, alternate values in blue and green
'green';
}
}
],
}
});
The context object passed to your function can have the following properties. Some of these won't be present for certain types of entity, so test before use.
chart: the associated chart
dataIndex: index of the current data
dataset: dataset at index datasetIndex
datasetIndex: index of the
current dataset
hover: true if hovered
Here's what worked for me (v 2.7.0), first I had to set pointBackgroundColor and pointBorderColor in the dataset to an array (you can fill this array with colours in the first place if you want):
var myChart = new Chart(ctx, {
type: 'line',
data: {
datasets: [
{
data: dataPoints,
pointBackgroundColor: [],
pointBorderColor: [],
}
]
}
});
Then you can monkey with the colours of the points directly:
myChart.data.datasets[0].pointBackgroundColor[4] = "#cc00cc";
myChart.data.datasets[0].pointBorderColor[4] = "#cc0000";
myChart.update();
Some other properties to play with to distinguish a point: pointStrokeColor (it apparently exists but I can't seem to get it to work), pointRadius & pointHoverRadius (integers), pointStyle ('triangle', 'rect', 'rectRot', 'cross', 'crossRot', 'star', 'line', and 'dash'), though I can't seem to figure out the defaults for pointRadius and pointStyle.
For chartjs 2.0 see this following answer.
Original answer below.
Good question regarding ChartJS. I've been wanting to do a similar thing. i.e dynamically change the point colour to a different colour. Have you tried this below. I just tried it and it worked for me.
Try this:
myLineChart.datasets[0].points[4].fillColor = "rgba(000,111,111,55)" ;
Or Try this:
myLineChart.datasets[0].points[4].fillColor = "#FF0000";
Or even this:
myLineChart.datasets[0].points[4].fillColor = "lightgreen";
Then do this:
myLineChart.update();
I guess you could have something like;
if (myLineChart.datasets[0].points[4].value > 100) {
myLineChart.datasets[0].points[4].fillColor = "lightgreen";
myLineChart.update();
}
Give it a try anyway.
Just adding what worked for me in the new 2.0 version.
Instead of:
myLineChart.datasets[0].points[4].fillColor = "lightgreen";
I had to use:
myChart.config.data.datasets[0].backgroundColor[4] = "lightgreen";
Not sure if that's because of a change in 2.0 or because I'm using a bar chart and not a line chart.
If you initialize the myChart in this manner,
var myChart = new Chart(ctx, {
type: 'line',
data: {
you have to change line color by this code
myChart.data.datasets[0].backgroundColor[0] ="#87CEFA";
If you initialize the myChart in this manner,
myBar = new Chart(ctx).Line(barChartData, {
you have to change line color by this code
myLineChart.datasets[0].points[4].fillColor = "#FF0000";

How to skip x Axes labels in ChartJS

The only thing I found for this topic is this
, but it does not really help solve the problem.
So I have a chart which is filled with some data like this:
As you can see the values which are not set in the dataSet, are cut off. This is because of this code which fills everything with undefined:
let dataSet: any = {
label: user.userName,
backgroundColor: 'rgba(0, 0, 0, 0)',
borderColor: this.getRandomColor(),
data: new Array(this.chart.data.labels.length).fill(undefined)
}
After that I fill the data in with this code:
data.forEach((d)=>{
let tmpDate: Date = new Date(d.date * 1000)
let insertIndex: number = this.chart.data.labels.indexOf(this.getDateString(tmpDate))
dataSet.data.splice(insertIndex, 1, d.data) // d.data is a number
})
this.chart.data.datasets.push(dataSet)
this.chart.update()
I would like it to skip the undefined values and create a smooth line across the chart.
spanGaps option in the docs should be what you're looking for.

How to duplicate Y Axis on JQuery Flot

I'm being able to use JQuery Flot, and it's a very nice tool. However, I could not find a GOOD solution for my problem.
I want to duplicate Y axis, so I can display 1 on the left and 1 on the right, so the users, when comparing data from the rightmost side of the chart, won't have to scroll through the leftmost side of the chart. I'm assuming they will be accessing it through a smartphone.
JQuery Flot allows multiple axis, but for each axis, I would need a different set of data, as in this example:
http://people.iola.dk/olau/flot/examples/multiple-axes.html
But I don't want to duplicate the data. Can't I just 'tell' Flot to duplicate the yaxis using the same set of data?
You can use the hooks functionality to force flot to show the second yaxis even though it has no data series assigned to it:
// hook function to mark axis as "used"
// and assign min/max from left axis
pOff = function(plot, offset){
plot.getYAxes()[1].used = true;
plot.getYAxes()[1].datamin = plot.getYAxes()[0].datamin;
plot.getYAxes()[1].datamax = plot.getYAxes()[0].datamax;
}
$.plot("#placeholder2", [ { data: d2 } ], {
hooks: { processOffset: [pOff] },
yaxes: [ {},
{position: 'right'} // add second axis
]
});
Depending on how your axis is configured though, this might be messy. You'll have to steal parameters from the left axis to get it to work (as I've done above with datamin/datamax).
If it was my code, I'd go with your duplicate data approach. You aren't really duplicating anything, just assigned the same array to two series. I'd then configure the 2nd series to simply not draw.
var d2 = [[0, 3], [4, 8], [8, 5], [9, 13]];
// use the same data but toggle off the lines...
$.plot("#placeholder", [ { data: d2 }, {data: d2, yaxis: 2, lines: {show: false}} ], {
yaxes: [ {},
{position: 'right'} ]
});
Here's a fiddle demonstrating the two approaches.

Limit labels number on Chart.js line chart

I want to display all of the points on my chart from the data I get, but I don't want to display all the labels for them, because then the chart is not very readable. I was looking for it in the docs, but couldn't find any parameter that would limit this.
I don't want to take only three labels for example, because then the chart is also limited to three points. Is it possible?
I have something like that right now:
If I could just leave every third-fourth label, it would be great. But I found absolutely nothing about labels options.
Try adding the options.scales.xAxes.ticks.maxTicksLimit option:
xAxes: [{
type: 'time',
ticks: {
autoSkip: true,
maxTicksLimit: 20
}
}]
For concreteness, let's say your original list of labels looks like:
["0", "1", "2", "3", "4", "5", "6", "7", "8"]
If you only want to display every 4th label, filter your list of labels so that every 4th label is filled in, and all others are the empty string (e.g. ["0", "", "", "", "4", "", "", "", "8"]).
For anyone looking to achieve this on Chart JS V2 the following will work:
var options = {
scales: {
xAxes: [{
afterTickToLabelConversion: function(data){
var xLabels = data.ticks;
xLabels.forEach(function (labels, i) {
if (i % 2 == 1){
xLabels[i] = '';
}
});
}
}]
}
}
Then pass the options variable as usual into a:
myLineChart = new Chart(ctx, {
type: 'line',
data: data,
options: options
});`
UPDATE:
I'v updated my fork with the latest pull (as of Jan 27, 2014) from NNick's Chart.js master branch.
https://github.com/hay-wire/Chart.js/tree/showXLabels
ORIGINAL ANSWER:
For those still facing this issue, I forked Chart.js a while back to solve the same problem. You can check it out on:
https://github.com/hay-wire/Chart.js/tree/skip-xlabels => Older branch! Check showXLabels branch for latest pull.
How to use:
Applicable to bar chart and line chart.
User can now pass a { showXLabels: 10 } to display only 10 labels (actual displayed labels count might be a bit different depending on the number of total labels present on x axis, but it will still remain close to 10 however)
Helps a lot when there is a very large amount of data. Earlier, the graph used to look devastated due to x axis labels drawn over each other in the cramped space. With showXLabels, user now has the control to reduce the number of labels to whatever number of labels fit good into the space available to him.
See the attached images for a comparison.
Without showXLabels option:
With { showXLabels: 10 } passed into option:
Here's some discussion on it:
https://github.com/nnnick/Chart.js/pull/521#issuecomment-60469304
For Chart.js 3.3.2, you can use #Nikita Ag's approach with a few changes. You can check the documentation. Put ticks in xAxis in scales. Example:
...
options: {
scales: {
xAxis: {
ticks: {
maxTicksLimit: 10
}
}
}
}
...
for axis rotation
use this:
scales: {
xAxes: [
{
// aqui controlas la cantidad de elementos en el eje horizontal con autoSkip
ticks: {
autoSkip: true,
maxRotation: 0,
minRotation: 0
}
}
]
}
In Chart.js 3.2.0:
options: {
scales: {
x: {
ticks: {
maxTicksLimit: 10
}
}
}
}
According to the chart.js github issue #12. Current solutions include:
Use 2.0 alpha (not production)
Hide x-axis at all when it becames too crowd (cannot accept at all)
manually control label skip of x-axis (not in responsive page)
However, after a few minutes, I thinks there's a better solution.
The following snippet will hide labels automatically. By modify xLabels with empty string before invoke draw() and restore them after then. Even more, re-rotating x labels can be applied as there's more space after hiding.
var axisFixedDrawFn = function() {
var self = this
var widthPerXLabel = (self.width - self.xScalePaddingLeft - self.xScalePaddingRight) / self.xLabels.length
var xLabelPerFontSize = self.fontSize / widthPerXLabel
var xLabelStep = Math.ceil(xLabelPerFontSize)
var xLabelRotationOld = null
var xLabelsOld = null
if (xLabelStep > 1) {
var widthPerSkipedXLabel = (self.width - self.xScalePaddingLeft - self.xScalePaddingRight) / (self.xLabels.length / xLabelStep)
xLabelRotationOld = self.xLabelRotation
xLabelsOld = clone(self.xLabels)
self.xLabelRotation = Math.asin(self.fontSize / widthPerSkipedXLabel) / Math.PI * 180
for (var i = 0; i < self.xLabels.length; ++i) {
if (i % xLabelStep != 0) {
self.xLabels[i] = ''
}
}
}
Chart.Scale.prototype.draw.apply(self, arguments);
if (xLabelRotationOld != null) {
self.xLabelRotation = xLabelRotationOld
}
if (xLabelsOld != null) {
self.xLabels = xLabelsOld
}
};
Chart.types.Bar.extend({
name : "AxisFixedBar",
initialize : function(data) {
Chart.types.Bar.prototype.initialize.apply(this, arguments);
this.scale.draw = axisFixedDrawFn;
}
});
Chart.types.Line.extend({
name : "AxisFixedLine",
initialize : function(data) {
Chart.types.Line.prototype.initialize.apply(this, arguments);
this.scale.draw = axisFixedDrawFn;
}
});
Please notice that clone is an external dependency.
i had a similar type of issue, and was given a nice solution to my specific issue show label in tooltip but not in x axis for chartjs line chart. See if this helps you
you can limit at as
scales: {
x: {
ticks: {
// For a category axis, the val is the index so the lookup via getLabelForValue is needed
callback: function(val, index) {
// Hide the label of every 2nd dataset
return index % 5 === 0 ? this.getLabelForValue(val) : '';
},
}
}
}
this will skip 4 labels and set the 5th one only.
you can use the following code:
xAxes: [{
ticks: {
autoSkip: true,
maxRotation: 90
}
}]
You may well not need anything with this new built-in feature.
A built-in label auto-skip feature detects would-be overlapping ticks and labels and removes every nth label to keep things displaying normally. https://www.chartjs.org/docs/latest/axes/
To set a custom number of ticks regardless of your chartsjs version:
yAxes: [{
ticks: {
stepSize: Math.round((Math.max.apply(Math, myListOfyValues) / 10)/5)*5,
beginAtZero: true,
precision: 0
}
}]
10 = the number of ticks
5 = rounds tick values to the nearest 5. All your y values will have the same step size.
Similar will work for xAxes too.
This answer works like a charm.
If you are wondering about the clone function, try this one:
var clone = function(el){ return el.slice(0); }
In the Chart.js file, you should find (on line 884 for me)
var Line = function(...
...
function drawScale(){
...
ctx.fillText(data.labels[i], 0,0);
...
If you just wrap that one line call to fillText with if ( i % config.xFreq === 0){ ... }
and then in chart.Line.defaults add something line xFreq : 1 you should be able to start using xFreq in your options when you call new Chart(ctx).Line(data, options).
Mind you this is pretty hacky.

Categories

Resources