How can I force annotations to always display above columns? - google-visualization

I want the annotations above columns to always BE ABOVE columns. I set annotations.alwaysOutside to true, but whenever a column reaches the roof of the chart, it will position the annotation within the column. If you run the code on JSFiddle you'll see what I mean.
So, how can I force annotations to ALWAYS display above columns?
https://jsfiddle.net/y7ootfoo/
<link href='https://fonts.googleapis.com/css?family=Lato' rel='stylesheet' type='text/css'>
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<script type="text/javascript">
google.charts.load("current", {
packages: ['corechart']
});
google.charts.setOnLoadCallback(drawChart);
function drawChart() {
var data = google.visualization.arrayToDataTable([
["Mana Cost", "Cards"],
["0", 1],
["1", 2],
["2", 3],
["3", 4],
["4", 4],
["5", 3],
["6", 2],
["7+", 1],
]);
var view = new google.visualization.DataView(data);
view.setColumns([0, 1, {
calc: "stringify",
sourceColumn: 1,
type: "string",
role: "annotation",
}, ]);
var options = {
title: "Cards/Mana Cost",
width: '750',
height: '375',
backgroundColor: "#FFF",
enableInteractivity: false,
bar: {
groupWidth: "90%"
},
legend: {
position: "none"
},
annotations: {
alwaysOutside: true,
stem: {
color: "transparent"
},
textStyle: {
fontName: 'Lato',
fontSize: 18.75,
bold: true,
italic: false,
auraColor: 'transparent',
color: "#000"
}
},
chartArea: {
backgroundColor: "#FFF"
},
titleTextStyle: {
color: "#000",
fontName: "Lato",
fontSize: 25,
bold: true,
italic: false
},
vAxis: {
gridlines: {
color: 'transparent'
},
textPosition: "none"
},
hAxis: {
textStyle: {
color: "#000",
fontName: "Lato",
fontSize: 18.75,
bold: true,
italic: false
}
}
};
var chart = new google.visualization.ColumnChart(document.getElementById("columnchart_values"));
chart.draw(view, options);
}
</script>
<div id="columnchart_values" style="width: 900px; height: 300px;"></div>

set
var options = {
vAxis: {
viewWindow:{
max: maxV, //maximum value of annotations + 1
},
}}
I also add
chartArea: {
width: '95%',
}
https://jsfiddle.net/damiantt/y7ootfoo/1/
complete code:
<link href='https://fonts.googleapis.com/css?family=Lato' rel='stylesheet' type='text/css'>
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<script type="text/javascript">
google.charts.load("current", {
packages: ['corechart']
});
google.charts.setOnLoadCallback(drawChart);
function drawChart() {
var data = google.visualization.arrayToDataTable([
["Mana Cost", "Cards"],
["0", 1],
["1", 2],
["2", 3],
["3", 4],
["4", 4],
["5", 3],
["6", 2],
["7+", 1],
]);
var maxV = 0;
for (var i = 0; i < data.getNumberOfRows(); i++) {
if(data.getValue(i, 1) > maxV) {
maxV = data.getValue(i, 1);
}
}
maxV++;
var view = new google.visualization.DataView(data);
view.setColumns([0, 1, {
calc: "stringify",
sourceColumn: 1,
type: "string",
role: "annotation",
}, ]);
var options = {
title: "Cards/Mana Cost",
width: '750',
height: '375',
backgroundColor: "#FFF",
enableInteractivity: false,
bar: {
groupWidth: "90%"
},
legend: {
position: "none"
},
annotations: {
alwaysOutside: true,
stem: {
color: "transparent"
},
textStyle: {
fontName: 'Lato',
fontSize: 18.75,
bold: true,
italic: false,
auraColor: 'transparent',
color: "#000"
}
},
chartArea: {
width: '95%',
backgroundColor: "#FFF"
},
titleTextStyle: {
color: "#000",
fontName: "Lato",
fontSize: 25,
bold: true,
italic: false
},
vAxis: {
viewWindow:{
max:maxV,
},
gridlines: {
color: 'transparent'
},
textPosition: "none"
},
hAxis: {
textStyle: {
color: "#000",
fontName: "Lato",
fontSize: 18.75,
bold: true,
italic: false
}
}
};
var chart = new google.visualization.ColumnChart(document.getElementById("columnchart_values"));
chart.draw(view, options);
}
</script>
<div id="columnchart_values" style="width: 900px; height: 300px;"></div>

Related

Chartjs and datalabels : automatic y axis (and dynamic data) hide datalabels

I have a chart (chartjs) with labels (datalabels).
When my data changes, my chart updates automatically. However, the largest datalabels are most of the time hidden by the automatic resizing of the y axis. Do you have any idea to fix that ?
It should be a 3 up there :)
Here is my code:
const completionOptions = {
responsive: true,
plugins: {
legend: {
display: false,
},
tooltip: {
backgroundColor: 'rgb(85, 85, 85, 1)',
displayColors: false,
// https://www.chartjs.org/docs/latest/configuration/tooltip.html
},
datalabels: {
color: 'rgb(203, 203, 203)',
anchor: 'end',
align: 'end',
labels: {
title: {
font: {
family: 'karla',
weight: '600',
size: 12,
},
}
}
}
},
scales: {
display: false,
y: {
beginAtZero: true,
display: false,
grid: {
display: false,
},
ticks: {
padding: 10
}
},
x: {
grid: {
display: false,
},
ticks: {
autoSkip: false,
maxRotation: 0,
minRotation: 0,
font: {
size: 20,
}
}
},
}
}
You can use the grace option to add extra space to the y axes:
Chart.register(ChartDataLabels)
const options = {
type: 'bar',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [12, 20, 3, 5, 2, 3],
backgroundColor: 'pink'
}]
},
options: {
scales: {
y: {
grace: '10%'
}
},
plugins: {
legend: {
display: false
},
datalabels: {
anchor: 'end',
align: 'end'
}
}
}
}
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.8.0/chart.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chartjs-plugin-datalabels/2.0.0/chartjs-plugin-datalabels.js"></script>
</body>

chart.js labels text font size and digits text font size too small

I would like to increase the size of the following elements. Could you please edit the code below to make these elements bigger:
the label text size (the NaCl and SalinityDrift boxes above the
chart)
the numbers themselves in x,y,y2 axes
Script:
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.5.1/chart.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/date-fns/1.30.1/date_fns.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns/dist/chartjs-adapter-date-fns.bundle.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/hammer.js/2.0.8/hammer.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chartjs-plugin-zoom/1.1.1/chartjs-plugin-zoom.min.js"></script>
<canvas id="myChart"></canvas>
<script type="text/javascript">
$("#myChart").width( $(window).width() *0.97 );
$("#myChart").height( $(window).height() * 0.8 );
var ctx = document.getElementById('myChart').getContext('2d');
const options = {
type: 'line',
data: {
datasets: [
{
label: 'NaCl',
data: natriumChrolideData,
borderColor: 'blue',
yAxisID: 'y',
},
{
label: 'Salinity drift',
data: salinityDriftData,
borderColor: 'red',
yAxisID: 'y2',
},
]
},
options: {
parsing: false,
normalized: true,
animation: false,
responsive: false,
scales: {
x: {
type: 'time',
title: {
display: true,
text: 'Time (client time zone)',
font: {
size: 24
}
},
},
y: {
title: {
display: true,
text: 'NaCl storage, kg',
font: {
size: 24
}
}
},
y2: {
title: {
display: true,
text: 'Salinity drift, %',
font: {
size: 24
},
ticks: {
min: 0,
},
}
},
},
plugins: {
zoom: {
pan: {
enabled: true,
onPanStart({chart, point}) {
// alert("pan works!");
},
mode: 'x',
},
zoom: {
wheel: {
enabled: true,
},
pinch: {
enabled: true
},
mode: 'x',
}
}
},
}
}
new Chart(ctx, options);
</script>
Produced plot example:
Note: I found some solutions to use fontSize or tick.font or tick.fontSize, but either I implemented them wrongly or they do not work for some reason.
You are putting the ticks config in the scale title while its supposed to be on the root of the scale itself. Also for the boxes font size on top you need to configure it in the options.plugins.legend.labels namespace.
Live example:
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: {
plugins: {
legend: {
labels: {
font: {
size: 20
}
}
}
},
scales: {
x: {
ticks: {
font: {
size: 20
}
}
},
y: {
ticks: {
font: {
size: 20
}
}
}
}
}
}
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/3.5.1/chart.js"></script>
</body>

Chart.js - Tooltips overlapped by bar values

In bar charts, label above bars overlaps tooltip. Please see screenshots below.
Bar chart - original
Bar chart - tooltip problem
Please see my code below.
<!doctype html>
<html>
<head>
<title>Single Bar Chart</title>
<script src="Chart.min.js"></script>
<style>
canvas {
border:1px solid #367ee9;
}
#container{
width: 950px;
}
</style>
</head>
<body>
<div id="container">
<canvas id="canvas"></canvas>
</div>
<script>
var barChartData = {
labels: ["Jul 19", "Aug 19", "Sep 19", "Oct 19", "Nov 19", "Dec 19", "Jan 20", "Feb 20", "Mar 20", "Apr 20", "May 20", "Jun 20"],
datasets: [{
//label: 'Jan 20',
backgroundColor: '#367ee9',
borderColor: '#367ee9',
borderWidth: 1,
data: [33111, 27510, 27377, 14947, 4312, 7279, 70988, 2903, 29575, 65, 9861, 3416],
data_action: ["bar1_action", "bar2_action", "bar3_action", "bar4_action", "bar5_action", "bar6_action", "bar7_action", "bar8_action", "bar9_action", "bar10_action", "bar11_action", "bar12_action"],
data_alt: ["Click here to see results of bar1_alt", "bar2_alt", "bar3_alt", "bar4_alt", "bar5_alt", "bar6_alt", "bar7_alt", "bar8_alt", "bar9_alt", "bar10_alt", "bar11_alt", "bar12_alt"],
}]
};
window.onload = function() {
var ctx = document.getElementById('canvas').getContext('2d');
window.myBar = new Chart(ctx, {
type: 'bar',
data: barChartData,
options: {
responsive: true,
onHover: (event, chartElement) => {
event.target.style.cursor = chartElement[0] ? 'pointer' : 'default';
},
hover: {
animationDuration: 0,
},
animation: {
duration: 1000,
onComplete: function () {
var chartInstance = this.chart,
ctx = chartInstance.ctx;
ctx.font = Chart.helpers.fontString(Chart.defaults.global.defaultFontSize, Chart.defaults.global.defaultFontStyle, Chart.defaults.global.defaultFontFamily);
ctx.textAlign = 'center';
ctx.textBaseline = 'bottom';
//ctx.canvas.style.zIndex = 5;
this.data.datasets.forEach(function (dataset, i) {
var meta = chartInstance.controller.getDatasetMeta(i);
meta.data.forEach(function (bar, index) {
var val = dataset.data[index];
var data = "$" + val.toLocaleString();
if(val > -1){
ctx.fillText(data, bar._model.x, bar._model.y - 5);
}
else{
ctx.fillText(data, bar._model.x, bar._model.y + 14);
}
});
});
}
},
onClick:function(evt) {
var firstPoint = this.getElementAtEvent(evt)[0];
if (firstPoint) {
var value = this.data.datasets[firstPoint._datasetIndex].data_action[firstPoint._index];
alert(value);
}
},
legend: {
display: false,
position: 'top',
onHover:function(){
event.target.style.cursor = 'pointer';
},
},
title: {
display: true,
text: 'Total Benefits Exceeded ($231,345) (Claim Date)',
fontColor: '#000',
fontSize: '15',
},
tooltips: {
yAlign:'top',
displayColors: false, // hide color box
yPadding: 10,
xPadding: 10,
backgroundColor: '#fff',
borderColor: '#000',
borderWidth: 1,
bodyFontFamily: 'tahoma,Verdana,Arial, Helvetica, sans-serif',
bodyFontSize: 13,
bodyFontColor:'#000',
callbacks: {
title: function(tooltipItem, data) {
return; // hide title
},
label: function(tooltipItem, data) {
barCount = tooltipItem.index;
barIndex = tooltipItem.datasetIndex;
var label = data.datasets[barIndex].data_alt[barCount];
return label;
},
}
},
scales: {
yAxes: [{
display: false,
scaleLabel: {
display: true,
labelString: 'Denied Charges ($)',
fontColor: '#000',
fontSize: '15',
fontStyle: 'bold',
},
ticks: {
callback: function(value, index, values) {
return '$' + value.toLocaleString();
}
},
}]
}
}
});
};
</script>
</body>
</html>
Is there any way to avoid this?
I tried to find details about setting z-index in above code. But, I haven't got much help.
Other than this, the graphs work great.
Thanks,
Sandeep
At the begin of the animation.onComplete callback function, you should add the following lines:
ctx.save();
ctx.globalCompositeOperation='destination-over';
And at the end of animation.onComplete, you need to invoke ctx.restore().
For further details about ctx.globalCompositeOperation='destination-over', have a look at this answer.
Please take a look at your amended code and see how it works.
var barChartData = {
labels: ["Jul 19", "Aug 19", "Sep 19", "Oct 19", "Nov 19", "Dec 19", "Jan 20", "Feb 20", "Mar 20", "Apr 20", "May 20", "Jun 20"],
datasets: [{
//label: 'Jan 20',
backgroundColor: '#367ee9',
borderColor: '#367ee9',
borderWidth: 1,
data: [33111, 27510, 27377, 14947, 4312, 7279, 70988, 2903, 29575, 65, 9861, 3416],
data_action: ["bar1_action", "bar2_action", "bar3_action", "bar4_action", "bar5_action", "bar6_action", "bar7_action", "bar8_action", "bar9_action", "bar10_action", "bar11_action", "bar12_action"],
data_alt: ["Click here to see results of bar1_alt", "bar2_alt", "bar3_alt", "bar4_alt", "bar5_alt", "bar6_alt", "bar7_alt", "bar8_alt", "bar9_alt", "bar10_alt", "bar11_alt", "bar12_alt"],
}]
};
var ctx = document.getElementById('canvas').getContext('2d');
window.myBar = new Chart(ctx, {
type: 'bar',
data: barChartData,
options: {
responsive: true,
onHover: (event, chartElement) => {
event.target.style.cursor = chartElement[0] ? 'pointer' : 'default';
},
hover: {
animationDuration: 0,
},
animation: {
duration: 1000,
onComplete: function() {
var chartInstance = this.chart,
ctx = chartInstance.ctx;
ctx.save();
ctx.globalCompositeOperation='destination-over';
ctx.font = Chart.helpers.fontString(Chart.defaults.global.defaultFontSize, Chart.defaults.global.defaultFontStyle, Chart.defaults.global.defaultFontFamily);
ctx.textAlign = 'center';
ctx.textBaseline = 'bottom';
//ctx.canvas.style.zIndex = 5;
this.data.datasets.forEach(function(dataset, i) {
var meta = chartInstance.controller.getDatasetMeta(i);
meta.data.forEach(function(bar, index) {
var val = dataset.data[index];
var data = "$" + val.toLocaleString();
if (val > -1) {
ctx.fillText(data, bar._model.x, bar._model.y - 5);
} else {
ctx.fillText(data, bar._model.x, bar._model.y + 14);
}
});
});
ctx.restore();
}
},
onClick: function(evt) {
var firstPoint = this.getElementAtEvent(evt)[0];
if (firstPoint) {
var value = this.data.datasets[firstPoint._datasetIndex].data_action[firstPoint._index];
alert(value);
}
},
legend: {
display: false,
position: 'top',
onHover: function() {
event.target.style.cursor = 'pointer';
},
},
title: {
display: true,
text: 'Total Benefits Exceeded ($231,345) (Claim Date)',
fontColor: '#000',
fontSize: '15',
},
tooltips: {
yAlign: 'top',
displayColors: false, // hide color box
yPadding: 10,
xPadding: 10,
backgroundColor: '#fff',
borderColor: '#000',
borderWidth: 1,
bodyFontFamily: 'tahoma,Verdana,Arial, Helvetica, sans-serif',
bodyFontSize: 13,
bodyFontColor: '#000',
callbacks: {
title: function(tooltipItem, data) {
return; // hide title
},
label: function(tooltipItem, data) {
barCount = tooltipItem.index;
barIndex = tooltipItem.datasetIndex;
var label = data.datasets[barIndex].data_alt[barCount];
return label;
},
}
},
scales: {
yAxes: [{
display: false,
scaleLabel: {
display: true,
labelString: 'Denied Charges ($)',
fontColor: '#000',
fontSize: '15',
fontStyle: 'bold',
},
ticks: {
callback: function(value, index, values) {
return '$' + value.toLocaleString();
}
},
}]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<div id="container">
<canvas id="canvas"></canvas>
</div>

HideOverlappingLabels in ApexCharts for xAxis type category

I have this apexcharts definition and when i've got more than e.g. 300 datasamples for my series things are overlapping on the xAxis like this
i would rather see something like this though
The option "hideOverlapLabels" does not work since it only works with timeseries from what i've read.
I know i can reduce the ticks but i want the chart to be zoomable and have all data in it.
Is there a way how i can prevent the labels to overlap?
var options_apex = {
series: null,
colors: [ '#0054ff', '#FF0000' ,'#FF0000'],
chart: {
height: 450,
type: 'line',
zoom: {
enabled: true
},
animations: {
enabled: false
}
},
stroke: {
width: [3, 3, 3],
curve: 'straight'
},
labels: null,
title: {
text: "Serial Data",
align: 'center',
margin: 10,
offsetX: 0,
offsetY: 0,
floating: false,
style: {
fontSize: '14px',
fontWeight: 'bold',
fontFamily: undefined,
color: '#263238'
},
},
subtitle: {
text: "the reckoning",
align: 'center',
margin: 10,
offsetX: 0,
offsetY: 20,
floating: true,
style: {
fontSize: '12px',
fontWeight: 'normal',
fontFamily: undefined,
color: '#9699a2'
},
},
xaxis: {
type:"category",
labels: {
rotate: -90,
rotateAlways: true,
hideOverlappingLabels: true,
style: {
colors: [],
fontSize: '7px',
fontFamily: 'Roboto',
fontWeight: 100,
cssClass: 'apexcharts-xaxis-label',
}
},
axisTicks: {
show: true,
borderType: 'solid',
color: '#78909C',
height: 6,
offsetX: 0,
offsetY: 0
},
tickAmount: undefined,
title: {
text: "STEP ID",
offsetX: 0,
offsetY: 0,
style: {
color: "#0000ff",
fontSize: '12px',
fontFamily: 'Helvetica, Arial, sans-serif',
fontWeight: 600,
cssClass: 'apexcharts-xaxis-title',
},
}
},
};
i used: tickAmount:15 , and work for my , this show 15 values and hide anothers, also you can try applied formatt and if condicional, to xaxis with:
formatter: function (value) {
if(value && ((value.split(':')[1][1] === '0') || (value.split(':')[1][1] === '5'))){
return (value);
}else{
value='';
return('');
}
}
I think i found the solution
xaxis: {
type:"category",
tooltip: {
enabled: false,
formatter: undefined,
offsetY: 0,
style: {
fontSize: 0,
fontFamily: 0,
},
},
labels: {
rotate: -45,
rotateAlways: true,
hideOverlappingLabels: true,
style: {
colors: [],
fontSize: '6px',
fontFamily: 'Roboto',
fontWeight: 80,
//cssClass: 'apexcharts-xaxis-label',
},
axisTicks: {
show: true,
borderType: 'solid',
color: '#78909C',
height: 6,
offsetX: 0,
offsetY: 0
},
},
With this setup and setting not the Labels but Categories with
options_apex.xaxis.categories = labels;
things seem to work without overlapping.

google charts vAxis to the right

I'm using google visualization
var data2 = new google.visualization.DataTable();
data2.addColumn('string', 'time');
data2.addColumn('number', 'amount');
data2.addColumn({ type: 'string', role: 'tooltip' });
data2.addRows(rows_data);
var options2 = {
vAxis: { textPosition: 'none', title: '', textStyle: { fontName: 'arial'} },
hAxis: { slantedText: false, textStyle: { color: '#E6EFFA' }, gridlines: { color: '#E6EFFA', count: 20} },
backgroundColor: '#E6EFFA',
legend: 'none',
chartArea: { top: 0 },
colors: ['#435988'],
chartArea: { width: 800 }
};
chart2 = new google.visualization.LineChart(document.getElementById('chart_div_volume'));
I want the vAxis position to be on the right.
is it possible ?
Short Answer: Yes, but it's tricky.
Long Answer:
You need to set up a multi-axis chart. Basically, you create a dummy axis with no labels or anything to make it look like an axis. Then you configure a secondary axis. You create one set of dummy values (hidden) to put on the first axis, and plot your real data on the second.
Here is an example:
function drawVisualization() {
// Create and populate the data table.
var data = google.visualization.arrayToDataTable([
['Year', 'Dummy', 'Sales', 'Expenses'],
['2004', 0, 1000, 400],
['2005', null, 1170, 460],
['2006', null, 660, 1120],
['2007', null, 1030, 540]
]);
var options = {
title: 'Company Performance',
series: { 0: {targetAxisIndex: 0, visibleInLegend: false, pointSize: 0, lineWidth: 0},
1: {targetAxisIndex: 1},
2: {targetAxisIndex: 1}
},
vAxes: {
0: {textPosition: 'none'},
1: {},
}
};
var chart = new google.visualization.LineChart(document.getElementById('visualization'));
chart.draw(data, options);
}
google.charts.load('current', { 'packages': ['corechart'] });
google.charts.setOnLoadCallback(drawVisualization);
function drawVisualization() {
var data = new google.visualization.DataTable();
data.addColumn('string', 'Productivity');
data.addColumn('number', 'Composite');
data.addColumn({ type: 'number', role: 'annotation' });
data.addColumn('number', 'Average(N=5)');
var compositeDataArry = [];
compositeDataArry.push(["Ravi", 11, 11, 5]);
compositeDataArry.push(["Wasif", 5, 5, 5]);
compositeDataArry.push(["Vipin", 2, 2, 5]);
compositeDataArry.push(["Ankur", 3, 3, 5]);
compositeDataArry.push(["Pankaj", 1, 1, 5]);
compositeDataArry.push(["Dheeraj", 4, 4, 5]);
data.addRows(compositeDataArry);
var options = {
title: 'My Chart',
titleTextStyle: { color: '#264158', fontSize: 24 },
seriesType: 'bars',
annotations: {
alwaysOutside: true,
textStyle: {
color: '#000000',
fontSize: 15
}
},
hAxis: {
slantedText: true,
slantedTextAngle: -45
},
series: {
0: { targetAxisIndex: 0, },
1: { targetAxisIndex: 1, type: 'line' }
},
vAxes: {
0: { textPosition: 'none' },
1: {}
}
};
var chart = new google.visualization.ColumnChart(document.getElementById('chart_div'));
chart.draw(data, options);
}
<html>
<head>
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
</head>
<body>
<div id="chart_div" style="height: 500px; width: 100%"></div>
</body>
</html>