I have a google scatter graph like this:
<html>
<head>
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
<script type="text/javascript">
google.load("visualization", "1", {packages:["corechart"]});
google.setOnLoadCallback(drawChart);
function drawChart() {
var data = google.visualization.arrayToDataTable([
['Age', 'Weight'],
[ 8, 12],
[ 4, 5.5],
[ 11, 14],
[ 4, 5],
[ 3, 3.5],
[ 6.5, 7]
]);
var options = {
title: 'Age vs. Weight comparison',
hAxis: {title: 'Age', minValue: 0, maxValue: 15},
vAxis: {title: 'Weight', minValue: 0, maxValue: 15},
legend: 'none'
};
var chart = new google.visualization.ScatterChart(document.getElementById('chart_div'));
chart.draw(data, options);
}
</script>
</head>
<body>
<div id="chart_div" style="width: 900px; height: 500px;"></div>
</body>
</html>
I would like when click on a circle, showing only those cycles that are within a radius x from the choosen circle. Any idea??
Thank you!
You need to filter the DataTable to get all of the points within the given radius of the selected point. Here's some code that will do this for you:
google.visualization.events.addListener(chart, 'select', function () {
var selection = chart.getSelection();
if (selection.length > 0) {
// get all data points within radius r of the selected point
var r, x, y;
r = <the radius to use>;
x = data.getValue(selection[0].row, 0);
y = data.getValue(selection[0].row, 1);
var rows = [];
for (var i = 0, count = data.getNumberOfRows(), dx, dy; i < count; i++) {
dx = data.getValue(i, 0) - x;
dy = data.getValue(i, 1) - y;
if (Math.sqrt(dx * dx + dy * dy) <= r) {
rows.push(i);
}
}
// do something with filtered rows
}
});
Here's a proof-of-concept demonstrating how it works: http://jsfiddle.net/asgallant/tgshL/
Related
I am using a google timeline similar to the code snippet below. I want my chart to look like the one below. I have managed to get everything to work expect how to add the dashed lines and text notation. Unfortunately, when I am searching for annotations I keep getting the AnnotatedTimeline, which is a different google chart.
Is there a simple way to do this?
<html>
<head>
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<script type="text/javascript">
google.charts.load('current', {'packages':['timeline']});
google.charts.setOnLoadCallback(drawChart);
function drawChart() {
var container = document.getElementById('timeline');
var chart = new google.visualization.Timeline(container);
var dataTable = new google.visualization.DataTable();
dataTable.addColumn({ type: 'string', id: 'President' });
dataTable.addColumn({ type: 'date', id: 'Start' });
dataTable.addColumn({ type: 'date', id: 'End' });
dataTable.addRows([
[ 'Washington', new Date(1789, 3, 30), new Date(1797, 2, 4) ],
[ 'Adams', new Date(1797, 2, 4), new Date(1801, 2, 4) ],
[ 'Jefferson', new Date(1801, 2, 4), new Date(1809, 2, 4) ]]);
chart.draw(dataTable);
}
</script>
</head>
<body>
<div id="timeline" style="height: 180px;"></div>
</body>
</html>
I was able to get this to work by finding the position of the rects. I started by drawing divs for each line I would want to show. Then after the timeline is draw I repositions those divs based on the location of the rectangle. I was not able to get a good minimal working snippet here because of the window positions used in the snippet code, but I got pretty close. In my own code I have it working perfectly.
.hline {
border-left: 5px solid black;
height: 100px;
position:absolute;
visibility:hidden;
top:144px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<html>
<head>
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
</head>
<body>
<div id="timeline" style="height: 180px;"></div>
<div id = "Hline1" class= "hline" > <div style = "position: relative; top:-18px">HLine1</div>
<div id = "Hline2" class= "hline" > <div style = "position: relative; top:-18px">HLine2</div>
<div id = "Hline3" class= "hline" > <div style = "position: relative; top:-18px">HLine3</div>
</div>
</body>
<script>
var options = {
timeline: { showRowLabels: false }
};
const lime="#00ff00" //color for average time
google.charts.load('current', {'packages':['timeline']});
google.charts.setOnLoadCallback(drawChart);
function drawChart() {
var container = document.getElementById('timeline');
var chart = new google.visualization.Timeline(container);
var dataTable = new google.visualization.DataTable();
dataTable.addColumn({ type: 'string', id: 'Project Stage', });
dataTable.addColumn({ type: 'string', id: 'Bar'});
dataTable.addColumn({ type: 'string', role: 'style'});
dataTable.addColumn({ type: 'date', id: 'Start' });
dataTable.addColumn({ type: 'date', id: 'End' });
dataTable.addRows([
[ 'Washington','Washington',lime, new Date(1789, 3, 30), new Date(1797, 2, 4) ],
[ 'Adams', 'Adams',lime, new Date(1797, 2, 4), new Date(1801, 2, 4) ],
[ 'Jefferson','Jefferson',lime, new Date(1801, 2, 4), new Date(1809, 2, 4) ]]);
chart.draw(dataTable,options);
function redraw (){
var rects = $('rect') //get all rectangles on plot.
function checkColor(arr){
var results = [];
for (let i of arr){
var colorCheck=$(i).attr('fill')
var x =$(i).attr('x')
var width = $(i).attr('width')
var x2 =parseFloat(x)+parseFloat(width)
if(colorCheck == lime){results.push(x2)}
};
return results
};
var linPositions = checkColor(rects) //get x coordinates for vertical lines
var yStart = $('rect')
//console.log(linPositions)
yStart = $(yStart[0]).offset().top;
xMargin=$("#timeline").offset().left;
var yHeight = $('rect')
yHeight = $(yHeight[0]).attr('height');
var lineNames=['Hline1','Hline2','Hline3']
for (let i = 0; i < linPositions.length; i++) {
var position = linPositions[i]+xMargin+"px"
var newTop = i*yHeight + yStart
/* set line information based on current chart positions */
document.getElementById(lineNames[i]).style.left = position;
document.getElementById(lineNames[i]).style.visibility = "visible";
document.getElementById(lineNames[i]).style.top = newTop;
document.getElementById(lineNames[i]).style.height = yHeight;
};
};
redraw()
function resizeChart () {
chart.draw(dataTable, options);
}
if (document.addEventListener) {
window.addEventListener('resize', resizeChart);
window.addEventListener('resize', redraw)
}
else if (document.attachEvent) {
window.attachEvent('onresize', resizeChart);
window.attachEvent('onresize', redraw);
}
else {
window.resize = resizeChart;
window.resize = redraw;
}
}
</script>
</html>
In Google Charts, the 'hAxis': {'gridlines': {'count': 3} } statement seems to work, but when I'm using chartWrapper as part of an interactive plot, it does not. I don't really care about vertical gridlines, but I want to control how many labels are on the X axis. I think labels are usually attached to gridlines - one label per gridline.
I have an example from the Google Charts website, where the only thing I changed was to put try and put in 3 gridlines:
https://jsfiddle.net/emorris/gLcq1h2j/
chart option ticks is only supported by a continuous axis
in the fiddle you shared, the view placed on the chart,
converts the first column from type 'date' to 'string',
which results in a discrete axis
// Convert the first column from 'date' to 'string'.
'view': {
'columns': [{
'calc': function(dataTable, rowIndex) {
return dataTable.getFormattedValue(rowIndex, 0);
},
'type': 'string'
}, 1, 2, 3, 4]
}
to control how many labels are on the X axis, remove the view
to build the ticks dynamically here, use the state of the range filter,
to know the date range currently displayed on the chart
the chart will need to be redrawn when the control's 'statechange' event fires
see following working snippet, an axis label is created for every 5 days...
google.charts.load('current', {
callback: drawChartRangeFilter,
packages: ['corechart', 'controls']
});
function drawChartRangeFilter() {
var data = new google.visualization.DataTable();
data.addColumn('date', 'Date');
data.addColumn('number', 'Stock low');
data.addColumn('number', 'Stock open');
data.addColumn('number', 'Stock close');
data.addColumn('number', 'Stock high');
var open, close = 300;
var low, high;
for (var day = 1; day < 121; ++day) {
var change = (Math.sin(day / 2.5 + Math.PI) + Math.sin(day / 3) - Math.cos(day * 0.7)) * 150;
change = change >= 0 ? change + 10 : change - 10;
open = close;
close = Math.max(50, open + change);
low = Math.min(open, close) - (Math.cos(day * 1.7) + 1) * 15;
low = Math.max(0, low);
high = Math.max(open, close) + (Math.cos(day * 1.3) + 1) * 15;
var date = new Date(2012, 0, day);
data.addRow([date, Math.round(low), Math.round(open), Math.round(close), Math.round(high)]);
}
var dashboard = new google.visualization.Dashboard(
document.getElementById('dashboard')
);
var control = new google.visualization.ControlWrapper({
controlType: 'ChartRangeFilter',
containerId: 'control',
options: {
filterColumnIndex: 0,
ui: {
chartType: 'LineChart',
chartOptions: {
chartArea: {
width: '92%'
},
hAxis: {
baselineColor: 'none'
},
height: 72
},
chartView: {
columns: [0, 3]
},
minRangeSize: 86400000
}
},
state: {
range: {
start: new Date(2012, 1, 9),
end: new Date(2012, 2, 20)
}
}
});
var chart = new google.visualization.ChartWrapper({
chartType: 'CandlestickChart',
containerId: 'chart',
options: {
chartArea: {
height: '100%',
width: '100%',
top: 12,
left: 48,
bottom: 48,
right: 48
},
vAxis: {
viewWindow: {
min: 0,
max: 2000
}
},
legend: {
position: 'none'
}
}
});
google.visualization.events.addListener(control, 'statechange', setAxisTicks);
function setAxisTicks() {
var oneDay = (1000 * 60 * 60 * 24);
var dateRange = control.getState().range;
var ticksAxisH = [];
for (var i = dateRange.start.getTime(); i <= dateRange.end.getTime(); i = i + (oneDay * 5)) {
ticksAxisH.push(new Date(i));
}
if (ticksAxisH.length > 0) {
ticksAxisH.push(new Date(ticksAxisH[ticksAxisH.length - 1].getTime() + (oneDay * 5)));
}
chart.setOption('hAxis.ticks', ticksAxisH);
if (chart.getDataTable() !== null) {
chart.draw();
}
}
setAxisTicks();
dashboard.bind(control, chart);
drawDashboard();
$(window).resize(drawDashboard);
function drawDashboard() {
dashboard.draw(data);
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="dashboard">
<div id="chart"></div>
<div id="control"></div>
</div>
I am trying to develop a small web app which query the multiple google spreadsheets and make the graphs on the same page. I can query the single spreadsheet and chart the matching data like this and it is working fine.
<html>
<head>
<title>
Test
</title>
<script src="http://www.google.com/jsapi"></script>
<script src="http://code.jquery.com/jquery-2.0.3.min.js"></script>
<script type="text/javascript" src="https://www.google.com/jsapi">
</script>
<script type="text/javascript">
google.load('visualization', '1', {'packages': ['table', 'controls', 'corechart']});
google.setOnLoadCallback(initialize);
function initialize() {
var urlMonth = 'https://docs.google.com/spreadsheets/d/1y5MgFR67kn1-GHbmeIi6wuC5hmP10x4O8vAs5RWD8Sw/edit#gid=0'
var queryStringMonthly = encodeURIComponent("select A, B, C, D, E, F, G, H, I GROUP BY A LABEL A 'Gene' ");
var queryMonthCurrent = new google.visualization.Query(urlMonth+
queryStringMonthly);
queryMonthCurrent.send(megaData);
}
function megaData(monthData) {
var monthData_table = monthData.getDataTable(firstRowIsHeader = true);
var monthData_tablePivot = new google.visualization.DataTable();
monthData_tablePivot.addColumn('string');
monthData_tablePivot.addColumn('number');
monthData_tablePivot.addColumn({type: 'string', label: 'Gene', role: 'annotation'});
var newRows = []; //
//iterate through each row
for (i = 0; i < monthData_table.getNumberOfRows(); i ++) {
var issue = monthData_table.getValue(i, 0);
//iterate through each column
for (j = 1; j < monthData_table.getNumberOfColumns(); j ++ ){
var newRow = [];
rep = monthData_table.getColumnLabel(j);
newRow.push(rep);
newRow.push(monthData_table.getValue(i, j));
newRow.push(issue);
newRows.push(newRow); //push each newRow to newRows
}
}
monthData_tablePivot.addRows( newRows);
// Create a dashboard.
var dashboard = new google.visualization.Dashboard(
document.getElementById('dashboard_div4'));
// Create filter
var issueFilter = new google.visualization.ControlWrapper({
'controlType': 'StringFilter',
'containerId': 'filter_div4',
'options': {
'filterColumnLabel': 'Gene',
'ui': {
'allowMultiple': false,
'allowNone': false,
}
},
//Set default filter value
'state': {'selectedValues': [monthData_table.getValue(0 , 1)]}
}
);
//create chart
var yearChart = new google.visualization.ChartWrapper({
'chartType': 'ColumnChart',
'containerId': 'current_year',
'options': {
'legend': 'none',
'width': 1100,
'height': 500,
hAxis: {
textStyle: {
color: 'black', // any HTML string color ('red', '#cc00cc')
fontName: 'Times New Roman', // i.e. 'Times New Roman'
fontSize: 12, // 12, 18 whatever you want (don't specify px)
bold: true, // true or false
italic: false // true of false
},
'title': 'Gene', titleTextStyle:{color:'black',fontSize: 16,bold:
true,italic: false}
},
vAxis: {title: 'Expression', titleTextStyle:{color:'black',fontSize:
16,bold: true,italic: false},
textStyle: {
color: 'black', // any HTML string color ('red', '#cc00cc')
fontName: 'Times New Roman', // i.e. 'Times New Roman'
fontSize: 12, // 12, 18 whatever you want (don't specify px)
bold: true, // true or false
italic: false // true of false
}
},
//Set the fontsize of labels so they don't show up crazily
'annotations': {'textStyle': {'opacity': 0},
//use 'line' style so to remove the line
pointer
'style': 'point',
'stemLength': 0
},
}
});
// bind charts and controls to dashboard
dashboard.bind(issueFilter, yearChart);
// Draw the dashboard.
dashboard.draw(monthData_tablePivot);
}
</script>
<style>
.SearchBar input {
height: 30px;
width: 400px;
}
</style>
</head>
<body>
<!--Div that will hold the dashboard-->
<center>
<h2>Seach gene expression</h2>
<div id="dashboard_div4" class="SearchBar" placeholder="Search">
<div id="filter_div4" > </div></center>
<div id="current_year" style="width:1100px; height: 300px;">
</div>
</div>
</html>
This repository is very close to my need but I don't know how to query the multiple spreadsheet. My another spreadsheet look like this
https://docs.google.com/spreadsheets/d/1vmPmaL78N-Ywz7s1y_VRSvQAZxjacN4mo7uKKrWrwzE/edit#gid=0
I made half a donut chart with Google charts and I have a problem that the sum of visible percentage is equal to 50%. Is there any possible solution ?
Image of my chart
you can override the text displayed on the slice by using the following config option...
pieSliceText: 'value'
then in the data, set the formatted value of the cells to the correct percentage...
var data = [
['Task', 'Hours'],
// use formatted values
['A', {v: 19.2, f: '38.4%'}],
['B', {v: 30.8, f: '61.6%'}],
[null, 50]
];
the following working snippet uses the same approach,
but calculates the correct percentages,
rather than hard-coding...
google.charts.load('current', {
callback: function () {
var data = [
['Task', 'Hours'],
['A', 19.2],
['B', 30.8],
[null, 50.0]
];
var total = 0;
for (var i = 1; i < data.length; i++) {
if (data[i][0] !== null) {
total += data[i][1];
}
}
var numberFormat = new google.visualization.NumberFormat({
pattern: '#,##0.0',
suffix: '%'
});
var dataTable = google.visualization.arrayToDataTable(data);
for (var i = 0; i < dataTable.getNumberOfRows(); i++) {
if (dataTable.getValue(i, 0) !== null) {
dataTable.setFormattedValue(i, 1, numberFormat.formatValue(((dataTable.getValue(i, 1) / total) * 100)));
}
}
var chart = new google.visualization.PieChart(document.getElementById('chart_div'));
var options = {
height: 400,
chartArea: {
top: 24
},
colors: ['#8BC34A', '#64B5F6'],
legend: 'none',
pieHole: 0.4,
pieStartAngle: 270,
pieSliceText: 'value',
slices: {
2: {
color: 'transparent'
}
},
theme: 'maximized',
width: 400
};
chart.draw(dataTable, options);
},
packages: ['corechart']
});
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div"></div>
I'm writing a Google Chart. It has stacked columns. On top of that I want to draw 2 lines, which indicate min and max allowed value.
The only solution I came up with, was modifying the first example of ComboCharts. My result looks like this:
Which isn't sufficient. The graph is variable, so if there's only 1 Quartal shown, the line will solely be a dot. My Questions are:
Is there a way to draw the line further, so it hits the left and right boundary of the Graph?
Can I draw markup lines into the graph, without pretending it's another datapoint?
You can fiddle with a ComboChart here if you want.
You can't get the lines to go edge-to-edge with a discrete (string-based) x-axis. If you switch to a continuous (number, date, datetime, timeofday) axis, then you can add one row before your real data and one row after that contain the goal lines (and nulls for the other data series):
function drawChart() {
var data = new google.visualization.DataTable();
data.addColumn('number', 'Quarter');
data.addColumn('number', 'Value 1');
data.addColumn('number', 'Value 2');
data.addColumn('number', 'Value 3');
data.addColumn('number', 'Goal 1');
data.addColumn('number', 'Goal 2');
data.addRows([
[0, null, null, null, 10, 14],
[1, 5, 4, 7, null, null],
[2, 6, 9, 6, null, null],
[3, 2, 6, 4, null, null],
[4, 3, 6, 4, null, null],
[5, null, null, null, 10, 14]
]);
var chart = new google.visualization.ComboChart(document.querySelector('#chart_div'));
chart.draw(data, {
height: 400,
width: 600,
isStacked: true,
legend: {
position: 'top'
},
seriesType: 'bars',
interpolateNulls: true,
series: {
3: {
type: 'line'
},
4: {
type: 'line'
}
},
hAxis: {
format: 'Q#',
ticks: [1, 2, 3, 4],
viewWindow: {
min: 0.5,
max: 4.5
}
},
chartArea: {
left: '10%',
width: '80%'
}
});
}
google.load('visualization', '1', {packages:['corechart'], callback: drawChart});
See working example: http://jsfiddle.net/asgallant/W67qU/
Here is some explanation of what is going on (edit on Nov 24, 2022 by Jorr.it):
At the top and bottom of the DataTable there are extra rows added with the goals only. With the hAxis.viewWindow option the two new goal dots are just cut off the chart, but resulting in a full line over the whole width of the chart. Finally option "interpolateNulls" needs to be set to connect the two invisible dots "over" the null values in the bar rows.
Maybe a bit late but I faced the same issue. I was trying to set max and min lines into a line chart with a lot of data points in the serie and I wanted to avoid adding new series with a lot of repeated points so I used overlays ( https://developers.google.com/chart/interactive/docs/overlays#javascript2 ).
Here are an example, It's just a draft in which I'm working now but maybe can help:
<html>
<head>
<script
type="text/javascript"
src="https://www.gstatic.com/charts/loader.js"
></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.0/jquery.min.js"></script>
<style>
#container {
position: relative;
width: 900px;
height: 500px;
}
.min-bar {
height: 1px;
background-color: red;
position: absolute;
left: 0;
right: 0;
}
</style>
<script type="text/javascript">
$(function() {
$.get(
"https://firebasestorage.googleapis.com/v0/b/manasav-pricetracker.appspot.com/o/products%2F-L6O-CtBKZAc2NTCFq7Z.data?alt=media&token=60e06bb6-59b7-41a9-8fd0-f82f4ddc75f2",
function(data) {
google.charts.load("current", { packages: ["corechart"] });
google.charts.setOnLoadCallback(drawChart);
var downloadedData = JSON.parse("[" + data);
function drawChart() {
var dataTable = [["Time", "New"]];
let min = Number.MAX_VALUE;
let rowMin;
for (var i in downloadedData) {
var d = downloadedData[i];
if (d.new < min) {
rowMin = i;
min = d.new;
}
dataTable.push([new Date(d.date), d.new]);
}
var data = google.visualization.arrayToDataTable(dataTable);
var options = {
title: "Price evolution",
legend: { position: "bottom" },
trendlines: { 0: {} }
};
var chart = new google.visualization.LineChart(
document.getElementById("curve_chart")
);
function placeMarker(dataTable) {
var cli = this.getChartLayoutInterface();
var chartArea = cli.getChartAreaBoundingBox();
document.querySelector(".min-bar").style.top =
Math.floor(cli.getYLocation(min)) + "px";
document.querySelector(".min-bar").style.left =
Math.floor(cli.getXLocation(dataTable.getValue(0,0))) - 25 + "px";
document.querySelector(".min-bar").style.right =
(document.querySelector("#container").offsetWidth - Math.floor(cli.getXLocation(dataTable.getValue(dataTable.getNumberOfRows()-1,0)))) - 25 + "px";
// document.querySelector(".min-bar").style.top =
// Math.floor(cli.getXLocation(dataTable.getValue(rowMin, 1))) +
// "px";
}
google.visualization.events.addListener(
chart,
"ready",
placeMarker.bind(chart, data)
);
chart.draw(data, options);
}
}
);
});
</script>
</head>
<body>
<div id="container">
<div id="curve_chart" style="width: 900px; height: 500px"></div>
<div class="min-bar"></div>
</div>
</body>
</html>
Jsfiddle demo => https://jsfiddle.net/jRubia/8z7ao1nh/