Wrong position of annotations in a stacked bar chart (Google Chart API) - google-visualization

I have a stacked bar chart with annotations which sums the values. The annotations are always at the end of the bar, but when there isn't a value for the last data row (I) the annotation is at the beginning and I don't know how to fix it.
var dataArray = [
["Date", "A", "B", "C", "D", "E", "F", "G", "H", "I", {role: 'annotation'}],
["7.08.2015", 0, 0, 0, 3, 6, 1, 0, 0, 0, 10],
["6.08.2015", 0, 0, 0, 0, 4, 6, 1, 0, 7, 18],
["5.08.2015", 0, 0, 0, 2, 4, 0, 0, 0, 5, 11]
];
Demo and code at JSFiddle

Found a workaround ... added a new data column, with the name Total, is has the same value as the annotation:
var dataArray = [
["Date", "A", "B", "C", "D", "E", "F", "G", "H", "I", "Total", {role: 'annotation'}],
["7.08.2015", 0, 0, 0, 3, 6, 1, 0, 0, 0, 10, 10],
["6.08.2015", 0, 0, 0, 0, 4, 6, 1, 0, 7, 18, 18],
["5.08.2015", 0, 0, 0, 2, 4, 0, 0, 0, 5, 11, 11]
];
And added this to the options:
var options = {
...
series: {
9: {
color: 'transparent',
type: "bar",
targetAxisIndex: 1,
visibleInLegend: false
}
}
};
Demo and code at JSFiddle
This makes the Total bar transparent, hide it in the legends and let it start from the zero point.
Dynamic version which takes the last data row for the annotations:
var series = {};
series[data.getNumberOfColumns() - 3] = {
color: 'transparent',
type: "bar",
targetAxisIndex: 1,
visibleInLegend: false
};
options["series"] = series;
Demo and code at JSFiddle

Related

Chartjs not displaying data from a dynamic stored variable

I am having issue in representing two datasets on my chartjs chart when both of my data is from a stored variable. When both of my data {inbound & outbound} is from a stored(and unique) variable, It shows two line graph but having similar data with the inbound data list inheriting the outbound data list. The inbound and outbound data list are two separate data and should be shown as two unique datasets on the chart.
My code is this
var inbound = InboundSmsCountList;
var outbound = OutboundSmsCountList;
var ff = MonthDaysList;
var combined_arraysx = [InboundSmsCountList,OutboundSmsCountList];
var max2 = combined_arraysx.reduce(function(final, current) {
for (var i = 0; i < final.length; ++i) {
if (current[i] > final[i]) {
final[i] = current[i];
}
}
return final;
});
var maxValue = Math.max.apply(Math, max2);
console.log(maxValue);
var ctx6 = document.getElementById('chartBar6').getContext('2d');
var gradient1x = ctx6.createLinearGradient(0, 350, 0, 0);
gradient1x.addColorStop(0, 'rgba(241, 0, 117,0)');
gradient1x.addColorStop(1, 'rgba(241, 0, 567,.5)');
var gradient2x = ctx6.createLinearGradient(0, 280, 0, 0);
gradient2x.addColorStop(0, 'rgba(86, 87, 255,0)');
gradient2x.addColorStop(1, 'rgba(34, 45, 255,.5)');
var config = {
type: 'line',
data: {
labels: ff,//['May-01', 'May-02', 'May-03', 'May-04', 'May-05', 'May-06', 'May-07', 'May-08', 'May-09', 'May-10', 'May-11', 'May-12', 'May-13', 'May-14', 'May-15', 'May-16', 'May-17', 'May-18', 'May-19', 'May-20', 'May-21', 'May-22', 'May-23', 'May-24', 'May-25', 'May-26', 'May-27', 'May-28', 'May-29', 'May-30', 'May-31'],
datasets: [{
label: 'Outbound',
data: outbound,//[1, 2, 0, 0, 84, 0, 10, 16, 8, 0, 0, 0, 4, 4, 1, 0, 0, 0, 1, 5, 0, 1, 0, 0, 0, 0, 71, 0, 0, 0, 0],
borderColor: '#00cccc',
borderWidth: 1,
backgroundColor: gradient2x,
},{
label: 'Inbound',
data: inbound,//[0, 0, 0, 0, 5, 0, 0, 0, 6, 0, 0, 0, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0],
borderColor: '#00cccc',
borderWidth: 1,
backgroundColor: gradient1x,
}]
},
options: {
maintainAspectRatio: false,
legend: {
display: true,
position:"top",
labels: {
display: true
}
},
scales: {
xAxes: [{
//stacked: true,
barPercentage: 0.5,
ticks: {
beginAtZero:true,
fontSize: 11
},
gridLines: {
display: false,
drawBorder: true
},
}],
yAxes: [{
//stacked: true,
ticks: {
fontSize: 10,
color: '#97a3b9',
min: 0,
max: maxValue
},
gridLines: {
display: false,
drawBorder: true
},
}]
}
}
};
new Chart(ctx6, config );
when both data is from stored variable - see image
data: {
labels: ff,//['May-01', 'May-02', 'May-03', 'May-04', 'May-05', 'May-06', 'May-07', 'May-08', 'May-09', 'May-10', 'May-11', 'May-12', 'May-13', 'May-14', 'May-15', 'May-16', 'May-17', 'May-18', 'May-19', 'May-20', 'May-21', 'May-22', 'May-23', 'May-24', 'May-25', 'May-26', 'May-27', 'May-28', 'May-29', 'May-30', 'May-31'],
datasets: [{
label: 'Outbound',
data: outbound,
borderColor: '#00cccc',
borderWidth: 1,
backgroundColor: gradient2x,
},{
label: 'Inbound',
data: inbound,
borderColor: '#00cccc',
borderWidth: 1,
backgroundColor: gradient1x,
}]
}
when outbound data is a stored variable while the inbound data is raw list/array it shows correct graph-two separate datasets - see image
data: {
labels: ff,//['May-01', 'May-02', 'May-03', 'May-04', 'May-05', 'May-06', 'May-07', 'May-08', 'May-09', 'May-10', 'May-11', 'May-12', 'May-13', 'May-14', 'May-15', 'May-16', 'May-17', 'May-18', 'May-19', 'May-20', 'May-21', 'May-22', 'May-23', 'May-24', 'May-25', 'May-26', 'May-27', 'May-28', 'May-29', 'May-30', 'May-31'],
datasets: [{
label: 'Outbound',
data: outbound,
borderColor: '#00cccc',
borderWidth: 1,
backgroundColor: gradient2x,
},{
label: 'Inbound',
data: [0, 0, 0, 0, 5, 0, 0, 0, 6, 0, 0, 0, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0],
borderColor: '#00cccc',
borderWidth: 1,
backgroundColor: gradient1x,
}]
}
Can someone advise how to fix this?
Thank you.

Select All and Unselect Option for chart.js

I'm Working on Chart.js, wanted to implement Select All and Unselect All option for labels. I'm trying to find it out but couldn't get anything such.
Please do help me out if anything such feature can be implemented.
If you need to show/hide charts selecting/unselecting all labels here is an example:
var barChartData = {
labels: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32],
datasets: [{
label: 'One',
backgroundColor: 'rgba(206, 0, 23, 1)',
data: [0, 1, 3, 0, 2, 0, 0, 2, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 2, 1, 0, 1, 2, 1, 1, 0, 0, 0, 2, 2, 0, 3]
}, {
label: 'Two',
backgroundColor: 'rgba(206, 0, 23, 0.75)',
data: [0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1]
}, {
label: 'Three',
backgroundColor: 'rgba(206, 0, 23, 0.5)',
data: [0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 2, 0, 0, 0, 1, 0, 0, 0, 0, 1]
}]
};
var ctx = document.getElementById('canvas').getContext('2d');
var chartInstance = new Chart(ctx, {
type: 'bar',
data: barChartData,
options: {
title: {
display: false,
},
responsive: true,
scales: {
xAxes: [{
stacked: true,
}],
yAxes: [{
stacked: true
}]
}
}
});
$("#toggle").click(function() {
chartInstance.data.datasets.forEach(function(ds) {
ds.hidden = !ds.hidden;
});
chartInstance.update();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.bundle.min.js"></script>
<button id="toggle">show/hide all</button>
<canvas id="canvas" height="500" width="800"></canvas>
Jsfiddle: https://jsfiddle.net/beaver71/00q06vjp/
Credits: see https://github.com/chartjs/Chart.js/issues/3009
Update: for pie chart use "meta", see: https://jsfiddle.net/beaver71/u0y0919b/
For ChartJS 2.9.3, this works as requested by David in the comments:
const chart = ...
chart.data.datasets.forEach(dataset => {
Object.keys(dataset._meta).forEach(key => {
const current = !dataset._meta[key].hidden
dataset._meta[key].hidden = current || null
})
})
chart.update()
Toggles all with a button, while playing nicely with the individual toggling in the chart legend.
V3 Answer
You can use a custom generateLabels function together with a custom onClick to get it as an extra legendItem like so:
const defaultLegendClickHandler = Chart.defaults.plugins.legend.onClick;
const pieDoughnutLegendClickHandler = Chart.controllers.doughnut.overrides.plugins.legend.onClick;
const options = {
type: 'line',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
borderColor: 'pink'
},
{
label: '# of Points',
data: [7, 11, 5, 8, 3, 7],
borderColor: 'orange'
}
]
},
options: {
plugins: {
legend: {
onClick: (evt, legendItem, legend) => {
const type = legend.chart.config.type;
let allLegendItemsState = [];
if (legendItem.text === 'hide all datasets' || legendItem.text === 'show all datasets') {
if (typeof legend.hideAll === 'undefined') {
legend.hideAll = false;
}
legend.chart.data.datasets.forEach((dataset, i) => {
legend.chart.setDatasetVisibility(i, legend.hideAll)
});
legend.hideAll = !legend.hideAll;
legend.chart.update();
return;
}
if (type === 'pie' || type === 'doughnut') {
pieDoughnutLegendClickHandler(evt, legendItem, legend)
} else {
defaultLegendClickHandler(evt, legendItem, legend);
}
allLegendItemsState = legend.chart.data.datasets.map((e, i) => (legend.chart.getDatasetMeta(i).hidden));
if (allLegendItemsState.every(el => !el)) {
legend.hideAll = false;
legend.chart.update();
} else if (allLegendItemsState.every(el => el)) {
legend.hideAll = true;
legend.chart.update();
}
},
labels: {
generateLabels: (chart) => {
const datasets = chart.data.datasets;
const {
labels: {
usePointStyle,
pointStyle,
textAlign,
color
}
} = chart.legend.options;
const legendItems = chart._getSortedDatasetMetas().map((meta) => {
const style = meta.controller.getStyle(usePointStyle ? 0 : undefined);
return {
text: datasets[meta.index].label,
fillStyle: style.backgroundColor,
fontColor: color,
hidden: !meta.visible,
lineCap: style.borderCapStyle,
lineDash: style.borderDash,
lineDashOffset: style.borderDashOffset,
lineJoin: style.borderJoinStyle,
strokeStyle: style.borderColor,
pointStyle: pointStyle || style.pointStyle,
rotation: style.rotation,
textAlign: textAlign || style.textAlign,
datasetIndex: meta.index
};
});
legendItems.push({
text: (!chart.legend.hideAll || typeof chart.legend.hideAll === 'undefined') ? 'hide all datasets' : 'show all datasets',
fontColor: color,
fillStyle: 'turquoise', // Box color
strokeStyle: 'turquoise', // LineCollor around box
});
return legendItems;
}
}
}
}
}
}
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/3.6.0/chart.js"></script>
</body>
The correct answer result in :
chart.data.datasets.forEach((obj, index) => {
let meta = this.eval_chart.getDatasetMeta(index);
meta.hidden = !meta.hidden || null;
});
chart.update();
As wrote in the documentation : https://www.chartjs.org/docs/latest/configuration/legend.html#custom-on-click-actions

How to change style of the selected point in Google Charts?

I'm using Google Charts to build a Line Graph and I need to change the style of the selected point.
The code below customizes the points individually when the graph loads, but I need to style the point after the user selects/clicks the point. I need to change the color, size and stroke-width of the selected point.
function drawChart() {
var data = google.visualization.arrayToDataTable
([['X', 'Y', {'type': 'string', 'role': 'style'}],
[1, 3, null],
[2, 2.5, null],
[3, 3, null],
[4, 4, null],
[5, 4, null],
[6, 3, 'point { size: 18; shape-type: star; fill-color: #a52714; visible: false }'],
[7, 2.5, null],
[8, 3, null]
]);
var options = {
legend: 'none',
hAxis: { minValue: 0, maxValue: 9 },
curveType: 'function',
pointSize: 7,
dataOpacity: 0.3
};
var chart = new google.visualization.LineChart(document.getElementById('chart_div'));
chart.draw(data, options);
https://jsfiddle.net/api/post/library/pure/

chart js (version 2) bar chart superimpose one data set onto another

I have a horizontal bar chart with two datasets
I am trying to superimpose the blue bars onto red.so that the intesection can be a start time and the bar can indicate a range.
is there any way to do this?
data: {
labels: ["C#", "ASP.NET MVC", "WebAPI", "SQL", "Entity Framework","NServiceBus / MSMQ", "WCF", "WPF / XAML", "",
"HTML / CSS", "JavaScript", "Angular JS v1","",
"DI / IoC", "TDD / Unit Testing", "UI Testing (Seleno)", "CI (Teamcity)"],
datasets: [
{
label:"# years",
data: [3, 2, 1, 4, 6, 2, 0.5, 0.25, 0,
7, 2, 0.5, 0,
2, 2, 0.5, 0.5],
backgroundColor: 'red',
borderWidth: 0
},
{
label:"# years",
data: [6, 4, 3, 6, 6, 2, 0.5, 0.25, 0,
7, 2, 0.5, 0,
2, 2, 0.5, 0.5],
backgroundColor: 'blue',
borderWidth: 0
}
]
}
options:{
scales: {
xAxes: [{ stacked:true}]
}
}

R style subset/replace in Rcpp

In R I have a loop which runs through a data frame of people coming and leaving a site and assigns them to a parking lot until they leave when it releases the spot.
activity = structure(list(ID = c(1, 2, 3, 3, 1, 2, 3, 2, 3, 1, 2, 1),
Lot = structure(c(1L, 3L, 6L, 6L, 1L, 3L, 2L, 5L, 2L, 4L, 5L, 4L),
.Label = c("a", "A", "C", "d", "f", "z"), class = "factor"),
time = c(1, 3, 6, 7, 8, 9, 10, 12, 13, 14, 15, 21),
dir = c(1, 1, 1, -1, -1, -1, 1, 1, -1, 1, -1, -1),
Here = c("no","no","no","no","no","no","no","no","no","no","no","no")),
class = "data.frame",
row.names = c(NA, -12L), .Names = c("ID", "Lot", "time", "dir","Here"))
lots = structure(c(30, 175, 170, 160, 300, 300, 35, 160, 85, 400, 200,
110, 60, 130, 100, 80, 1000, 320, 330, 350, 320, 250, 250, 370,
20, 40, 0, 140, 185, 200, 185, 120, 55, 105, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0), .Dim = c(34L, 2L),
.Dimnames = list(c("a", "b", "c", "d", "e", "f", "g", "h", "i", "j",
"k", "l", "m", "n", "o", "p", "q", "r", "s", "t",
"u", "v", "x", "y", "z", "A", "B", "C", "D", "E",
"F", "G", "H", "I"), c("Capacity", "Utilization")))
for(i in 1:nrow(activity)){
id = activity$ID[i]
l = activity$Lot[i]
d = activity$dir[i]
t = activity$time[i]
lots[l,"Utilization"] = lots[l,"Utilization"] + d
if(d == -1) activity$Here[activity$ID == id & activity$time <= t] = "no"
}
What I want to determine is, in Rcpp is there a way to do the R style subset and replace? e.g., lots[l,"Utilization"] = ... and activity$Here[activity$ID == id & activity$time <= t] = .... I'm specifically wanting to be able to load in 3 matrices, the master record table, the matrix which manages lots and the matrix which manages current locations (in this example I know the lot already, in practice I need to determine where they are likely to park). I have functioning code but it takes ~160 seconds to run and I'm trying to learn how to leverage Rcpp to make this much faster.