I'm generating a BarChart with Google's javascript visualization libraries. I would like to make the bars in the chart to be wider than they currently are, but I can't find anything in the documentation which shows how to configure the width of the bars of each data set.
Any help?
Had this same question, figured I'd post for posterity. The bar.groupWidth appears to be the way to set this.
https://developers.google.com/chart/interactive/docs/gallery/barchart
For example:
var options = {
title: "Density of Precious Metals, in g/cm^3",
width: 600,
height: 400,
bar: {groupWidth: "95%"},
legend: { position: "none" },
};
var chart = new google.visualization.BarChart(document.getElementById("barchart_values"));
chart.draw(view, options);
Try below format so the graph will have decently look, its not fixed but this solved our issue.
options: {
titlePosition: "none",
bar: { groupWidth: "50%" }
// ...
}
data.push([" ", "t1","t2","t3","t4"]); // headings
data.push([" ", 0, 0, 0, 0]); // dummy bar so graph will display good
// push you actual data here
data.push([" ", 0, 0, 0, 0]); // dummy bar so graph will display good
Related
I am using Google Chart to display a bar chart. Please see the screen shot below. Problem is, the highest number on the y-axis is always getting chopped off. In the screenshot, the highest number is supposed to be 55; but, as you can see, only the lower portion of 55 is showing. I have tried changing the height of my div and changing the height of the chart. They didn't solve the problem. I have also tried changing the max value of the y-axis but that does not solve the problem in the sense that the highest number would get chopped off (for example, for the chart in my screen shot, if I were to change the max value to 60, it is true that 55 would show completely but 60 would be chopped off).
How can I show the complete number on the highest value on y-axis in Google Charts?
google.charts.load('current', {packages: ['bar']});
google.charts.setOnLoadCallback(drawChart);
function drawChart() {
var data = new google.visualization.arrayToDataTable([
["", ""],
["Col_1", <?php echo $col1Count; ?>],
["Col_2", <?php echo $col2Count; ?>],
["Col_3", <?php echo $col3Count; ?>],
["Col_4", <?php echo $col4Count; ?>]
]);
var options = {
width: 720,
height: 550,
legend: { position: 'none' },
vAxis: {
viewWindow: {
min: 5,
max: 55
},
ticks: [5,10,15,20,25,30,35,40,45,50,55]
}
};
// Instantiate and draw the chart.
var chart = new google.charts.Bar(document.getElementById('myChart'));
chart.draw(data, google.charts.Bar.convertOptions(options));
google.visualization.events.addListener(chart, 'ready', function () {
html2canvas(document.getElementById('myChart')).then(function(canvas) {
// console.log(canvas.toDataURL('image/png'));
//document.getElementById('myChart').appendChild(canvas);
jQuery.ajax({
type: 'POST',
url: 'https://myURL.com/saveimage.php',
data: {
// send image string as data
imgstr: canvas.toDataURL('image/png')
},
success: function(response) {
alert(response);
}
});
});
});
}
The material Bar chart has far fewer options than the classic charts. I suspect that if you add a title, even if it is just a space character, that will reserve enough space above the chart to show the topmost axis tick label without truncation.
I am open to learning that there is already a way (via configuration, or developing a plugin) to hook into the rendering of the label of an axis, such that I could control aspects of the font used to render each line of a multiline label (e.g., what I need to render would be similar visually to a label and sub-label below it, with the primary label being bolded and a larger font size, while the sub-label directly beneath it would be normal font weight and a smaller size).
I am using ChartJs version 3.5.1 to render a horizontal barchart (meaning that the dataset labels on the left are really configured under the y axis), and have tried a few different things already:
Hooking into the tick callback - but I can't even use this function to duplicate default functionality (the value coming into that function isn't the label text; instead it is the index/ordinal of the data row?). Even if I could get this to work as shown in examples, it appears like this would be more for the content of the label than any of the configuration options themselves.
Setting the font configuration for ticks to be an array - but this only serves to allow me to change the font between data rows (e.g., I can make the label of the top row in my horizontal bar chart be size 22, the second label 10, etc. - but not change font attributes within lines of a given label)
Using a plugin like afterDraw to try to go tweak things - but again, the configuration at that point seems to only consider all of the lines together as one label.
Tried looking through past PRs to the project (mostly centered around adding multiline label support, as well as bug fixes specific to that area) to get any additional insight
If there isn't a way currently (via plugins or existing configuration), does anyone have a good feel for where to start attacking this sort of a change as a new PR?
UPDATE
As was shared as a response to my corresponding ChartJs feature request and as the accepted answer below, a custom plugin seems to be the only way currently to accomplish what I wanted for now.
Here are the key bits from my configuration (admittedly much more "one time use only" than the accepted answer, as I moved some of the configuration inside of the plugin as hard-coded values given my relatively narrow use case):
// this will be passed into the chart constructor...
const options = {
//...
scales: {
//...
// I wanted to impact the lefthand side of a horizontal bar chart
y: {
ticks: {
// make the original labels white for later painting over with custom sub-labels
color: "white",
// we still want this here to be able to take up the same space as the eventual label we will stick here
font: {
size: 22,
weight: "bold"
}
}
},
//...
}
};
// This is my plugin, also later passed into the chart constructor
const customSubLabelsPlugin = {
id: "customSubLabels",
afterDraw: (chart, args, opts) => {
// Set all variables needed
const {
ctx,
// I only cared about altering one specific axis
scales: { y }
} = chart;
const labelItems = y._labelItems;
const fontStringSubTitle = "16px Helvetica,Arial,sans-serif";
const fontStringMain = "bold 22px Helvetica,Arial,sans-serif";
// loop over each dataset label
for (let i = 0; i < labelItems.length; i++) {
let labelItem = labelItems[i];
// For purposes of redrawing, we are going to always assume that each label is an array - because we make it that way if we need to
const label = Array.isArray(labelItem.label)
? labelItem.label
: [labelItem.label];
// Draw new text on canvas
let offset = 0;
label.forEach((el) => {
let elTextMetrics = ctx.measureText(el);
if (labelItem.label.indexOf(el) === 0) {
ctx.font = fontStringMain;
} else {
ctx.font = fontStringSubTitle;
}
ctx.save();
ctx.fillStyle = "#546a6f";
ctx.fillText(
el,
labelItem.translation[0],
labelItem.translation[1] + labelItem.textOffset + offset
);
ctx.restore();
offset +=
elTextMetrics.fontBoundingBoxAscent +
elTextMetrics.fontBoundingBoxDescent;
});
}
}
};
You can use a plugin to redraw the ticks for you, might need some finetuning for your specific needs:
var options = {
type: 'line',
data: {
labels: [
["Red", "subTitle"],
["Blue", "subTitle"],
["Yellow", "subTitle"],
["Green", "subTitle"],
["Purple", "subTitle"],
["Orange", "subTitle"]
],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
borderColor: 'red',
backgroundColor: 'red'
}]
},
options: {
plugins: {
customTextColor: {
color: 'blue',
boxColor: 'white',
fontStringSubTitle: 'italic 12px Comic Sans MS',
fontStringMain: ''
}
}
},
plugins: [{
id: 'customTextColor',
afterDraw: (chart, args, opts) => {
// Set all variables needed
const {
ctx,
scales: {
y,
x
}
} = chart;
const labelItems = x._labelItems;
const {
color,
boxColor,
fontStringMain,
fontStringSubTitle
} = opts;
const defaultFontString = '12px "Helvetica Neue", Helvetica, Arial, sans-serif';
for (let i = 0; i < labelItems.length; i++) {
let labelItem = labelItems[i];
if (!Array.isArray(labelItem.label)) {
continue;
}
let metrics = ctx.measureText(labelItem.label);
let labelWidth = metrics.width;
let labelHeight = metrics.fontBoundingBoxAscent + metrics.fontBoundingBoxDescent;
//Draw box over old labels so they are inviseble
ctx.save();
ctx.fillStyle = boxColor || '#FFFFFF';
ctx.fillRect((labelItem.translation[0] - labelWidth / 2), labelItem.translation[1], labelWidth, labelHeight * labelItem.label.length);
ctx.restore();
// Draw new text on canvas
let offset = 0;
labelItem.label.forEach(el => {
let elTextMetrics = ctx.measureText(el);
let elWidth = elTextMetrics.width;
if (labelItem.label.indexOf(el) === 0) {
ctx.font = fontStringMain || defaultFontString;
} else {
ctx.font = fontStringSubTitle || defaultFontString;
}
ctx.save();
ctx.fillStyle = color || Chart.defaults.color
ctx.fillText(el, (labelItem.translation[0] - elWidth / 2), labelItem.translation[1] + labelItem.textOffset + offset);
ctx.restore();
offset += elTextMetrics.fontBoundingBoxAscent + elTextMetrics.fontBoundingBoxDescent;
});
}
// Draw white box over old label
}
}]
}
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>
I would like to draw a chart to my html, the chart I am using is google chart. However, while my x value is increasing, the chart is getting bigger. But I just want a fixed size window which increase both minimum x value and maximum x value. Like sliding window.
The attachment below is my code. This is the js code which updates the gets the value and updates the chart
// load google charts library
google.load("visualization", "1", {packages:["corechart"]});
// for rest, walk, fast_walk data
var data, options, chart;
var xMin = 0;
var xMax = 10;
var i = 0;
/* initialize chart1 - rest, walk, fast_walk data */
function drawChart(data, options) {
var chart = new
google.visualization.LineChart(document.getElementById('data-container'));
chart.draw(data, options);
return(chart);
}
/* update the chart1 - rest, walk, fast_walk data */
function updateChart(percentage) {
i = (i + 1);
data.addRow([
""+i,
percentage
]);
if(xMax >= 9) {
xMin + 1;
}
xMax + 1;
chart.draw(data, options);
}
$(function() {
data = google.visualization.arrayToDataTable([
['Time', 'percentage'],
['0', 0],
]);
options = {
title: 'Energy data',
"curveType": "function",
vAxis: {
min: xMin,
max: xMax
}
};
chart = drawChart(data, options);
});
/* reset charts */
function reset(){
i = 0;
data = google.visualization.arrayToDataTable([
['Time', 'percentage'],
['0', 0],
]);
options = {
title: 'Energy data',
"curveType": "function",
hAxis: {
viewWindow: {
min: 0,
max: 10
}
}
};
chart = drawChart(data, options);
}
I am wondering if it can be designed into a sliding window, so that the x value doesn't stick with the minimum value 0. instead if we want to see the earliest value, we can just scroll left.
According to the documentation at [https://developers.google.com/chart/interactive/docs/gallery/linechart]
/* copied from site*/
var options = {
chart: {
title: 'Box Office Earnings in First Two Weeks of Opening',
subtitle: 'in millions of dollars (USD)'
},
width: 900, //<--- set fixed width like so
height: 500
};
To get a scrollable div,you can wrap your chart inside another div
<div class='h-scrollable' > <!---- chart code here ----> </div>
and for css
.h-scrollable {
width: 100%;
overflow: hidden; // only if you don't want y axis to be scrollable
overflow-x: auto;
}
Now, for the chart give a width depending on the number of x values you have. You could do a mathematical computation by taking the width of the h-scrollbale div in javascript and dividing it by number of x-points you want in a window and then multiplying it with total x values you have and setting it as chart width.
Update:
inititally get the width of h-scrollable as let viewWidth = document.querySelector(".h-scrollable").offsetWidth
[refer : How to find the width of a div using raw JavaScript?
Then if you want to show 10 x values in a view, divide viewWidth by 10 to get one xWidth. Now you can re-render the chart each time by setting width as no.of X values * xWidth so that it scrolls accordingly
Upon each update, you can just remove the first raw.
I am drawing Charts Using google.visualization API .
The User can select a value from DropDown in Front End and clicks on Go , it fetches data from backend .
Sometimes the data that fetched is more and sometimes less
When the Data is more , the x-axis being overlapped
Please see this fiddle
http://jsfiddle.net/7wYP2/462/
This is my code
google.load('visualization', '1', {packages: ['corechart']});
function drawVisualization() {
// Create and populate the data table.
var data = google.visualization.arrayToDataTable([["strike_pr","CE","PE"],["5500",1875,2025],["6000",61500,104775],["6100",450,13725],["6500",35400,421800],["6600",150,121950],["6700",600,770925],["6800",13650,370425],["6900",33375,586650],["7000",744375,1122075],["7100",229200,355875],["7200",199800,689850],["7300",461550,244425],["7400",442950,439125],["7500",835350,484725],["7600",459000,82800],["7700",482250,48000],["7800",893250,11550],["7900",1215600,13500],["8000",741150,93525],["8100",242325,6150],["8200",326175,1500],["8300",365850,75],["8500",104850,2925],["9000",13050,11775]]);
var options = {
title:"OPTION INDEX distribution",
width: 800,
height: 400,
bar: {groupWidth: "95%"},
legend: { position: "none" },
is3D:true,
"vAxis":{"title":"Open Interest"},
"hAxis":{"title":"Strike Price"},
};
// Create and draw the visualization.
new google.visualization.ColumnChart(document.getElementById('visualization')).
draw(data, options);
}
google.setOnLoadCallback(drawVisualization);
Could you please let me know how to resolve this issue ??
I am currently working on Google Bar Chart-Dual-X and it is working nice.
Issue:
The bar is showing wrongly.For an example: Suppose I want to show Obtained Marks and Total Marks.But Issue is Google Chart shows Obtained Marks Bar bigger than the Total Mark(which is not true at all). You can see below pic :
As you can see in the pic that Chap 6,7,8 is having Obtained Mark Bar is bigger than the Total Mark Bar.
Code
<script type="text/javascript">
google.load("visualization", "1.1", {packages:["bar"]});
google.setOnLoadCallback(drawStuff);
function drawStuff() {
var data = new google.visualization.arrayToDataTable([
['Subject', 'Obtained Marks', 'Total Marks'],
<?php
$i=1;
foreach($sql_get_marks_results as $sql_get_marks_result){
echo "['".$sql_get_marks_result->meta_subject."', ".$sql_get_marks_result->obtained_marks.", ".$sql_get_marks_result->total_marks."]";
if($i != count($sql_get_marks_results)){echo ",";}
$i++;
}
?>
]);
var options = {
width: 900,
chart: {
title: 'Markesheet',
subtitle: 'distance on the left, brightness on the right'
},
bars: 'horizontal', // Required for Material Bar Charts.
series: {
0: { axis: 'obtained' }, // Bind series 0 to an axis named 'distance'.
1: { axis: 'total' } // Bind series 1 to an axis named 'brightness'.
},
axes: {
x: {
obtained: {label: 'Obtained'}, // Bottom x-axis.
total: {side: 'top', label: 'Total'} // Top x-axis.
}
}
};
var chart = new google.charts.Bar(document.getElementById('dual_x_div'));
chart.draw(data, options);
};
</script>
Is anyone here who came across similar problem or anyone can help me out in this ?
Tell me if you want more detail about this.
The display shown in your screen shots is correct.
The "total marks" (red) dataset follows the bottom x-axis.
And the "Obtained" (blue) dataset follows the top x-axis.
I think that the scale (inferred by your data range) of your two X-axis is quite close. And because of this it's easy to confuse them.
Dual x-axis charts are good for complementary datasets with values in very different ranges as in the example given in the documentation.
In your case you'd be better of using a simple (single axis) bar chart to avoid that kind of confusion.