I am using Google Charts API to display a vertical line on a LineChart (at a specific point) using annotations.
Is it possible to style the annotation line, to make it more visible (change its color/thickness, in case I add some vertical gridlines etc.)?
Desired output
I'm only interested in the annotation line style, not in the annotation text style, as asked in this question.
I have the following code:
function drawVisualization() {
var data = new google.visualization.DataTable();
data.addColumn('string', 'x');
data.addColumn({type: 'string', role: 'annotation'});
data.addColumn('number', '');
data.addColumn({
type: 'boolean',
role: 'certainty'
});
data.addRows([
["-6", null, 1, true],
["-5", null, 2, true],
["-4", null, 4, true],
["-3", null, 8, true],
["-2", null, 7, true],
["-1", null, 7, true],
["0", '', 8, true],
["1", null, 4, false],
["2", null, 2, false],
["3", null, 3, false],
["4", null, 3, false],
["5", null, 1, false],
["6", null, 1, false]
]);
new google.visualization.LineChart(document.getElementById('visualization')).
draw(data, {
curveType: 'function',
width: 500,
height: 400,
annotations: {
style: 'line'
}
});
}
You can play with the code in this fiddle.
first, recommend using loader.js to load the library (vs. jsapi)
according to the release notes...
The version of Google Charts that remains available via the jsapi loader is no longer being updated consistently. Please use the new gstatic loader (loader.js) from now on.
this will change the load statement, nothing else...
next, to change the annotation line color, use the following config option...
annotations.stem.color
although no option exists for line thickness, it can be changed manually,
when the chart's 'ready' event fires
the annotation is drawn using a <rect> element
just need a way to find it in the dom
the following working snippet uses the annotation line color,
to find the annotation <rect> and change the width
google.charts.load('current', {
callback: drawVisualization,
packages: ['corechart']
});
function drawVisualization() {
var data = new google.visualization.DataTable();
data.addColumn('string', 'x');
data.addColumn({type: 'string', role: 'annotation'});
data.addColumn('number', '');
data.addColumn({
type: 'boolean',
role: 'certainty'
});
data.addRows([
["-6", null, 1, true],
["-5", null, 2, true],
["-4", null, 4, true],
["-3", null, 8, true],
["-2", null, 7, true],
["-1", null, 7, true],
["0", '', 8, true],
["1", null, 4, false],
["2", null, 2, false],
["3", null, 3, false],
["4", null, 3, false],
["5", null, 1, false],
["6", null, 1, false]
]);
var chartDiv = document.getElementById('visualization');
var chart = new google.visualization.LineChart(chartDiv);
var annotationColor = '#ff00ff';
google.visualization.events.addListener(chart, 'ready', function () {
Array.prototype.forEach.call(chartDiv.getElementsByTagName('rect'), function(rect) {
if (rect.getAttribute('fill') === annotationColor) {
rect.setAttribute('width', '8');
}
});
});
chart.draw(data, {
curveType: 'function',
width: 500,
height: 400,
annotations: {
stem: {
color: annotationColor
},
style: 'line'
}
});
}
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="visualization"></div>
Related
I have read some other answers here and accordingly added the role property but it did not work.
<Chart
width={'500px'}
height={'300px'}
chartType="Timeline"
loader={<div>Loading Chart</div>}
data={[
[
{ type: 'string', id: 'President' },
{ type: 'date', id: 'Start' },
{ type: 'date', id: 'End' },
{type: 'string', role: 'style'}
],
['Washington', new Date(1789, 3, 30), new Date(1797, 2, 4), 'gold'],
['Adams', new Date(1797, 2, 4), new Date(1801, 2, 4), 'color: #ccc'],
['Jefferson', new Date(1801, 2, 4), new Date(1809, 2, 4), 'gold'],
]}
options={{
showRowNumber: true,
}}
rootProps={{ 'data-testid': '1' }}
/>
refer: https://react-google-charts.com/timeline-chart
on the timeline chart, the style role will only work when used as the third column.
so you will also need to add the second column for bar label.
but you can use null values for that column, if needed...
<Chart
width={'500px'}
height={'300px'}
chartType="Timeline"
loader={<div>Loading Chart</div>}
data={[
[
{ type: 'string', id: 'President' },
{ type: 'string', id: 'Bar' }, // <-- add bar label here...
{ type: 'string', role: 'style' }, // <-- add style role here...
{ type: 'date', id: 'Start' },
{ type: 'date', id: 'End' }
],
['Washington', null, 'gold', new Date(1789, 3, 30), new Date(1797, 2, 4)],
['Adams', null, '#ccc', new Date(1797, 2, 4), new Date(1801, 2, 4)],
['Jefferson', null, 'gold', new Date(1801, 2, 4), new Date(1809, 2, 4)],
]}
options={{
showRowNumber: true,
}}
rootProps={{ 'data-testid': '1' }}
/>
I got it! I sorted the bars according the role attribute.
I used the role property in data structure.
const data = [ [ { type: "string", id: "Phases" },{ type: "string", id: "Name" }, { type: 'string', role: 'style' }, { type: "date", id: "Start" }, { type: "date", id: "End" } ]];
<Chart chartType="Timeline" data={[...data, ...firstArray, ...secondArray]} width="100%" height={setChartHeight((firstArray.length+secondArray))} options={{ timeline: { } }} />
enter image description here
This is my second answer on Stackoverflow. I still don't understand how to indent the code in the answer.
Show only the data points that have a change.
In order to reduce the clutter, I want to not show the circles when the prev value or next are the same. Still when you hover over them to show the label with information.
This is how I want it to look:
The second and third circles are the same, they must be hidden and only show on hover:
you can use the following options to style the points...
pointBackgroundColor, pointBorderColor, pointBorderWidth
but instead of providing a single value...
pointBackgroundColor: '#ffffff',
pointBorderColor: 'rgb(102, 187, 106)',
pointBorderWidth: 2,
you'll need to provide an array, with values for each point in the dataset,
then you can change the value for the points in question.
for the points you do not want to show, use color such as 'transparent'.
this will hide the point, but still show tooltip on hover.
pointBackgroundColor: ['#ffffff', '#ffffff', 'transparent', 'transparent', '#ffffff', '#ffffff'],
pointBorderColor: ['rgb(102, 187, 106)', 'rgb(102, 187, 106)', 'transparent', 'transparent', 'rgb(102, 187, 106)', 'rgb(102, 187, 106)'],
pointBorderWidth: [2, 2, 0, 0, 2, 2]
see following working snippet...
new Chart(document.getElementById('myChart').getContext('2d'), {
type: 'line',
data: {
labels: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
datasets: [{
backgroundColor: 'rgba(102, 187, 106, 0.2)',
borderColor: 'rgb(102, 187, 106)',
borderWidth: 2,
data: [5, 6, 6, 6, 6, 7, 6, 6, 5, 4],
label: 'y',
lineTension: 0,
pointBackgroundColor: ['#ffffff', '#ffffff', 'transparent', 'transparent', '#ffffff', '#ffffff', '#ffffff', '#ffffff', '#ffffff', '#ffffff'],
pointBorderColor: ['rgb(102, 187, 106)', 'rgb(102, 187, 106)', 'transparent', 'transparent', 'rgb(102, 187, 106)', 'rgb(102, 187, 106)', 'rgb(102, 187, 106)', 'rgb(102, 187, 106)', 'rgb(102, 187, 106)', 'rgb(102, 187, 106)'],
pointBorderWidth: [2, 2, 0, 0, 2, 2, 2, 2, 2, 2]
}]
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.bundle.min.js"></script>
<canvas id="myChart"></canvas>
A slightly different approach to WhiteHat's (ninja'd!) that iterates the series via .forEach to build the colour options:
Edit: Minor tweak to if to account for previous and next value in deciding point visibility and added hover colour settings to show hidden point on hover.
let labels = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'],
series = [10, 5, 5, 5, 5, 2, 3, 3, 3, 10],
pointBackgroundColor = [],
pointBorderColor = [],
pointHoverBackgroundColor = 'white',
pointHoverBorderColor = 'red';
series.forEach(
(value, index) => {
if (value == series[index - 1] && value == series[index + 1]) {
pointBackgroundColor.push('transparent');
pointBorderColor.push('transparent');
} else {
pointBackgroundColor.push('white');
pointBorderColor.push('red');
}
});
myChart = new Chart(document.getElementById('chart'), {
type: 'line',
data: {
labels: labels,
datasets: [{
label: 'series1',
data: series,
pointBackgroundColor: pointBackgroundColor,
pointBorderColor: pointBorderColor,
pointHoverBackgroundColor: pointHoverBackgroundColor,
pointHoverBorderColor: pointHoverBorderColor
}]
},
options: {
maintainAspectRatio: false,
tooltips: {
mode: 'index',
intersect: false
},
hover: {
intersect: false
}
}
});
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.min.js"></script>
<canvas id="chart"></canvas>
WhiteHat solution is good but doesn't achieve the desired effect. When you hover over a hidden data point circle it should make the circle visible.
Here is how I did it
Step 1:
In the backend using PHP, I check if the prev and next point are different, and made a point radius 0.
$countPoints = count($points);
for ($i=1; $i < $countPoints-1; $i++) {
$prevVal = $chartChange[$i-1];
$nextVal = $chartChange[$i+1];
if($chartChange[$i] == $prevVal && $chartChange[$i] == $nextVal){
$points[$i] = 0;
}
}
Step 2 :
Add and pass the imploded array to the options object. Using [3,0,3,3] format
pointRadius: [{/literal}{$points}{literal}]
Edit:
Using only js
let labels = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'],
series = [10, 5, 5, 5, 5, 2, 3, 3, 3, 10],
pointRadius = [],
pointBackgroundColor = "rgb(230, 247, 238)",
pointBorderColor = "rgb(47, 186, 117)";
series.forEach(
(value, index) => {
if (value == series[index - 1] && value == series[index + 1]) {
pointRadius.push(0);
} else {
pointRadius.push(4);
}
});
myChart = new Chart(document.getElementById('myChart'), {
type: 'line',
data: {
labels: labels,
datasets: [{
label: 'series1',
fill: 'start',
pointRadius: pointRadius,
data: series,
backgroundColor:pointBackgroundColor,
borderColor:pointBorderColor,
pointHoverRadius: 4,
pointBackgroundColor: pointBackgroundColor,
pointBorderColor: pointBorderColor,
}]
},
options: {
tooltips: {
// mode: 'index',
intersect: false
},
tooltips: {
mode: 'index',
axis: 'x',
intersect: false
},
hover: {
intersect: false
},
maintainAspectRatio: false
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.bundle.min.js"></script>
<canvas id="myChart"></canvas>
Labels overflow outside the box. Some lables are well inside the box. Others just draw outside.
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: 'Term' });
dataTable.addColumn({ type: 'string', id: 'Name' });
dataTable.addColumn({ type: 'date', id: 'Start' });
dataTable.addColumn({ type: 'date', id: 'End' });
dataTable.addRows([
[ '1', 'George Washington', new Date(1789, 3, 30), new Date(1797, 2, 4) ],
[ '2', 'John Adams', new Date(1797, 2, 4), new Date(1801, 2, 4) ],
[ '2', 'Johndc Adams', new Date(1790, 2, 4), new Date(1810, 2, 4) ],
[ '4', 'Johndc Adams', new Date(1770, 2, 4), new Date(1810, 2, 4) ],
[ '3', 'Thomas Jefferson', new Date(1801, 2, 4), new Date(1809, 2, 4) ]]);
chart.draw(dataTable);
}
Am using google API to implement chart in my Project. Am using Scatter chart.
I need to implement chart like below. How can Achieve this.? Is there any other way to Achieve this by using any other Open source chart.?
Sample Google Chart which I need
Additional requirement
you can use a ComboChart to combine scatter and area series
the area series should be stacked
set the color of the first layer to 'transparent'
use null for values where the series do not coincide
see following working snippet...
google.charts.load('current', {
callback: drawChart,
packages: ['corechart']
});
function drawChart() {
var data = new google.visualization.DataTable();
data.addColumn('number', 'x');
data.addColumn('number', 'area bottom');
data.addColumn('number', 'area top');
data.addColumn('number', 'scatter');
data.addRows([
[1.5, null, null, 1.5],
[3, 3, 3, null],
[6, 3, 3, null]
]);
var options = {
areaOpacity: 1,
colors: ['transparent', '#ff9900', '#3366cc'],
hAxis: {
format: '#,##0.0',
ticks: [0, 1.5, 3, 4.5, 6],
title: 'FINAL SCORE'
},
height: 320,
legend: {
position: 'none'
},
isStacked: true,
seriesType: 'area',
series: {
2: {
type: 'scatter'
}
},
title: 'Final Score',
vAxis: {
format: '#,##0.0',
ticks: [0, 1.5, 3, 4.5, 6],
title: 'FINAL SCORE'
},
width: 320
};
var chart = new google.visualization.ComboChart(
document.getElementById('chart_div')
);
chart.draw(data, options);
}
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div"></div>
UPDATE
just add another area layer for the new requirement...
google.charts.load('current', {
callback: drawChart,
packages: ['corechart']
});
function drawChart() {
var data = new google.visualization.DataTable();
data.addColumn('number', 'x');
data.addColumn('number', 'area bottom');
data.addColumn('number', 'area middle');
data.addColumn('number', 'area top');
data.addColumn('number', 'scatter');
data.addRows([
[1.5, null, null, null, 1.5],
[3, 3, 3, null, null],
[4.5, 3, 3, null, null],
[4.5, 3, 1.5, 1.5, null],
[6, 3, 1.5, 1.5, null]
]);
var options = {
areaOpacity: 1,
colors: ['transparent', '#ff9900', '#f8bbd0', '#3366cc'],
hAxis: {
format: '#,##0.0',
ticks: [0, 1.5, 3, 4.5, 6],
title: 'FINAL SCORE'
},
height: 320,
legend: {
position: 'none'
},
isStacked: true,
seriesType: 'area',
series: {
3: {
type: 'scatter'
}
},
title: 'Final Score',
vAxis: {
format: '#,##0.0',
ticks: [0, 1.5, 3, 4.5, 6],
title: 'FINAL SCORE'
},
width: 320
};
var chart = new google.visualization.ComboChart(
document.getElementById('chart_div')
);
chart.draw(data, options);
}
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div"></div>
This should be simple. How can I assign my own colors to the bars in Google Gantt Charts? The gantt is ignoring my colors and automatically assigning blue, red and yellow colors (in that order) to the bars and I can't seem to figure out the problem. Can someone please point out if I am missing something here or is it not supported at all at this time?
Here is what I have:
function drawChart() {
var data = new google.visualization.DataTable();
data.addColumn({ type: 'string', id: 'task_id' }, 'Task ID');
data.addColumn({ type: 'string', id: 'task_name' }, 'Task Name');
data.addColumn({ type: 'string', id: 'resource' }, 'Resource');
data.addColumn({ type: 'date', id: 'start_date' }, 'Start Date');
data.addColumn({ type: 'date', id: 'end_date' }, 'End Date');
data.addColumn({ type: 'number', id: 'duration' }, 'Duration');
data.addColumn({ type: 'number', id: 'percent_complete' }, 'Percent Complete');
data.addColumn({ type: 'string', id: 'dependencies' }, 'Dependencies');
data.addRows([
['Research', 'Find sources', null,
new Date(2015, 0, 1), new Date(2015, 0, 5), null, 100, null],
['Write', 'Write paper', 'write',
null, new Date(2015, 0, 9), daysToMilliseconds(3), 25, 'Research,Outline'],
['Cite', 'Create bibliography', 'write',
null, new Date(2015, 0, 7), daysToMilliseconds(1), 20, 'Research'],
['Complete', 'Hand in paper', 'complete',
null, new Date(2015, 0, 10), daysToMilliseconds(1), 0, 'Cite,Write'],
['Outline', 'Outline paper', 'write',
null, new Date(2015, 0, 6), daysToMilliseconds(1), 100, 'Research']
]);
var colors = [];
var colorMap = {
write: '#e63b6f',
complete: '#19c362'
}
for (var i = 0; i < data.getNumberOfRows(); i++) {
colors.push(colorMap[data.getValue(i, 2)]);
}
var options = {
height: 275,
gantt: {
criticalPathEnabled: true,
criticalPathStyle: {
stroke: '#e64a19',
strokeWidth: 5
}
},
colors: colors
};
var chart = new google.visualization.Gantt(document.getElementById('chart_div'));
chart.draw(data, options);
}
There is an optiongantt.palette which takes an array of objects.
var options = {
gantt: {
palette: [
{
"color": "#cccccc",
"dark": "#333333",
"light": "#eeeeee"
}
]
}
}
By providing your own array of objects, you can override the default palette.
This is the default palette that the chart uses:
[
{
"color": "#5e97f6",
"dark": "#2a56c6",
"light": "#c6dafc"
},
{
"color": "#db4437",
"dark": "#a52714",
"light": "#f4c7c3"
},
{
"color": "#f2a600",
"dark": "#ee8100",
"light": "#fce8b2"
},
{
"color": "#0f9d58",
"dark": "#0b8043",
"light": "#b7e1cd"
},
{
"color": "#ab47bc",
"dark": "#6a1b9a",
"light": "#e1bee7"
},
{
"color": "#00acc1",
"dark": "#00838f",
"light": "#b2ebf2"
},
{
"color": "#ff7043",
"dark": "#e64a19",
"light": "#ffccbc"
},
{
"color": "#9e9d24",
"dark": "#827717",
"light": "#f0f4c3"
},
{
"color": "#5c6bc0",
"dark": "#3949ab",
"light": "#c5cae9"
},
{
"color": "#f06292",
"dark": "#e91e63",
"light": "#f8bbd0"
},
{
"color": "#00796b",
"dark": "#004d40",
"light": "#b2dfdb"
},
{
"color": "#c2185b",
"dark": "#880e4f",
"light": "#f48fb1"
}
]
I figured out a hacky way of doing it. You basically have to listen to every single event fired by the chart and override them with a function that colors the chart.
This is pretty old, but just in case anyone needs to do this... Not a super elegant solution, but it works.
function changeColors() {
$("text[fill='#5e97f6']").attr('fill',"#0099D8"); // Left Text
$("rect[fill='#5e97f6']").attr('fill',"#0099D8"); // Full bar
$("path[fill='#2a56c6']").attr('fill', '#006B99'); // Percentage completed
$("rect[fill='#2a56c6']").attr('fill', '#0099D8'); // Hover Full Bar
$("path[fill='#204195']").attr('fill', '#006B99'); // Hover Percentage
// Change Old red to new Red
$("text[fill='#db4437']").attr('fill',"#D41647");
$("rect[fill='#db4437']").attr('fill',"#D41647");
$("path[fill='#a52714']").attr('fill', '#A21135');
$("rect[fill='#a52714']").attr('fill', '#D41647');
$("path[fill='#7c1d0f']").attr('fill', '#A21135');
// Change Old Yellow to new Yellow
$("text[fill='#f2a600']").attr('fill',"#FCB813");
$("rect[fill='#f2a600']").attr('fill',"#FCB813");
$("path[fill='#ee8100']").attr('fill', '#C98e03');
$("rect[fill='#ee8100']").attr('fill', '#FCB813');
$("path[fill='#b36100']").attr('fill', '#C98e03');
}
...and then after you draw the chart, add a "ready" and these other event listeners to run changeColors any time anything happens.
chart.draw(data, options);
google.visualization.events.addListener(chart, 'ready', changeColors);
google.visualization.events.addListener(chart, 'onmouseover', changeColors);
google.visualization.events.addListener(chart, 'onmouseout', changeColors);
google.visualization.events.addListener(chart, 'select', changeColors);
google.visualization.events.addListener(chart, 'error', changeColors);
google.visualization.events.addListener(chart, 'click', changeColors);
google.visualization.events.addListener(chart, 'animationfinish', changeColors);
Issues:
There seems to be some switching of the colors in certain situations, as you mouse around on it.