chart.js custom legend - make legend items clickable to select/deselect data - chart.js

I've created a custom html legend using the legendCallback functionality, but I'm not sure how to make the legend items "clickable" to select/deselect the corresponding dataset.
I'm sure this must be possible, but I'm not sure how to do it.
I did find one potential solution here: https://github.com/chartjs/Chart.js/issues/5070
...but I couldn't figure out how to adapt it (or know if it's possible to adapt that approach) to make it work with my custom legend.
UPDATE: I've got part way there, thanks to this post:
https://github.com/chartjs/Chart.js/issues/2565
... I have updated the codepen and codesnippet with some changes that make the legend items clickable... what I still need help with is getting the legend items to toggle class to/from "hidden".
Here's what I've got:
On codepen
var allData = [5.36, 4.75, 5.64, 5.82, 5.43, 5.34, 7.05, 6.50, 5.91, 5.52, 4.66, 5.30, 4.75, 4.41, 4.66, 5.70, 5.34, 6.52, 5.48, 5.43, 5.55, 6.18, 6.14, 5.45];
var femaleData = [5.33, 5.17, 5.44, 5.44, 5.61, 5.61, 6.67, 6.22, 5.83, 5.61, 4.56, 4.67, 5.61, 4.28, 4.11, 5.83, 5.61, 6.33, 5.50, 5.56, 6.22, 5.94, 5.72, 4.83];
var maleData = [5.38, 4.46, 5.77, 6.08, 5.31, 5.15, 7.31, 6.69, 5.96, 5.46, 4.73, 5.73, 4.15, 4.50, 5.04, 5.62, 5.15, 6.65, 5.46, 5.35, 5.08, 6.35, 6.42, 5.88];
// function1Data is G&A
var function1Data = [5.18, 5.18, 6.09, 5.09, 5.36, 5.09, 6.45, 6.55, 5.36, 5.64, 4.55, 5.09, 4.82, 4.55, 4.91, 6.00, 5.91, 5.64, 5.45, 5.27, 6.27, 5.73, 5.64, 4.82];
// function2Data is Sales & Service
var function2Data = [5.63, 4.50, 5.56, 5.88, 5.63, 6.13, 7.19, 6.75, 5.75, 5.69, 4.88, 5.44, 4.75, 4.44, 4.31, 5.94, 5.06, 6.63, 5.44, 5.75, 5.25, 6.50, 6.50, 5.63];
// function3Data is tech
var function3Data = [5.24, 4.71, 5.41, 6.24, 5.29, 4.76, 7.29, 6.24, 6.41, 5.29, 4.53, 5.29, 4.71, 4.29, 4.82, 5.29, 5.24, 7.00, 5.53, 5.24, 5.35, 6.18, 6.12, 5.71];
// function4Data is dev
var program1Data = [5.08, 4.54, 5.58, 5.58, 5.42, 5.29, 7.13, 6.58, 5.63, 5.54, 4.58, 4.79, 4.88, 4.54, 4.46, 6.04, 5.04, 6.67, 5.75, 5.33, 5.33, 6.46, 5.96, 5.00];
var program2Data = [5.21, 4.58, 5.89, 5.58, 5.42, 5.32, 6.89, 6.53, 5.68, 5.42, 4.58, 5.37, 4.47, 4.32, 4.79, 5.84, 5.32, 6.26, 5.68, 5.47, 5.32, 6.21, 6.16, 5.37];
// service1Data is 0-50
var service1Data = [5.50, 4.58, 5.67, 5.50, 5.50, 5.25, 7.00, 6.75, 5.67, 5.58, 4.92, 5.50, 4.67, 4.33, 5.25, 5.42, 5.33, 6.33, 4.92, 5.50, 5.42, 6.17, 6.17, 5.67];
// service2Data is 51-80
var service2Data = [4.90, 5.20, 5.90, 5.60, 5.40, 5.00, 7.20, 6.10, 5.60, 5.00, 4.30, 5.00, 4.90, 4.50, 4.00, 5.60, 5.90, 6.20, 5.90, 5.10, 5.70, 5.80, 5.80, 4.50];
// service3Data is 81-100
var service3Data = [6.25, 4.42, 5.67, 6.08, 5.00, 5.83, 7.08, 6.42, 6.08, 6.33, 4.50, 5.67, 4.75, 4.25, 4.17, 5.17, 4.83, 6.67, 5.08, 4.92, 5.17, 6.50, 6.58, 5.42];
// service4Data is 101-154
var service4Data = [4.60, 4.90, 5.30, 6.10, 5.90, 5.20, 6.90, 6.70, 6.30, 5.00, 4.90, 4.90, 4.70, 4.60, 5.20, 6.80, 5.40, 6.90, 6.20, 6.30, 6.00, 6.20, 5.90, 6.20];
// role1Data is 0-4
var role1Data = [5.33, 4.67, 5.75, 6.50, 5.17, 4.75, 7.42, 6.75, 6.33, 5.42, 4.50, 6.08, 4.17, 4.50, 4.83, 5.42, 5.08, 6.83, 5.83, 5.17, 5.50, 6.50, 6.58, 6.08];
// role2Data is 5-18
var role2Data = [5.27, 5.09, 5.45, 5.64, 5.64, 6.18, 7.18, 6.27, 5.64, 4.91, 4.82, 5.09, 4.73, 4.36, 4.73, 5.82, 5.91, 6.64, 5.36, 5.45, 5.73, 5.73, 5.73, 5.27];
// role3Data is 19-32
var role3Data = [4.78, 4.67, 6.56, 5.22, 6.44, 4.78, 7.00, 6.78, 5.78, 5.56, 5.22, 4.89, 4.56, 4.11, 4.22, 5.89, 5.22, 5.44, 6.44, 6.78, 6.00, 6.33, 6.22, 5.33];
// role4Data is 33-60
var role4Data = [5.50, 5.00, 5.67, 5.58, 5.25, 5.00, 6.50, 5.83, 5.75, 5.83, 4.58, 5.00, 5.08, 4.75, 4.67, 5.58, 5.58, 6.25, 5.25, 5.25, 5.33, 5.83, 5.75, 5.08];
// data from research for global norms/profiles
// sds realistic high
var norm1Data = [5.7, 5.4, 5.7, 6.0, 4.5, 5.2, 5.5, 5.2, 5.9, 6.2, 4.4, 5.7, 4.5, 6.1, 5.9, 5.6, 5.3, 5.9, 5.2, 4.8, 5.3];
// sds realistic low
var norm2Data = [6.1, 6.2, 4.4, 5.2, 4.7, 6.4, 5.4, 5.2, 5.1, 6.0, 4.5, 5.1, 7.2, 5.9, 6.0, 5.1, 6.7, 5.5, 5.2, 5.1, 5.9];
// sds investigative high
var norm3Data = [5.2, 5.8, 5.4, 5.5, 4.4, 4.8, 6.5, 5.1, 5.4, 5.6, 4.5, 5.3, 5.1, 5.8, 6.5, 5.7, 5.8, 5.8, 5.8, 4.6, 5.2];
// sds investigative low
var norm4Data = [6.5, 6.0, 4.8, 5.4, 4.6, 6.7, 4.7, 5.6, 5.4, 6.7, 4.5, 5.7, 6.7, 5.8, 5.7, 5.1, 6.1, 5.2, 5.0, 5.0, 5.9];
// sds social high
var norm5Data = [6.9, 5.6, 4.4, 6.3, 4.4, 6.9, 5.4, 5.3, 5.8, 6.8, 4.5, 6.6, 5.9, 5.9, 6.2, 4.8, 5.9, 6.4, 4.9, 5.0, 5.0];
// sds social low
var norm6Data = [4.1, 6.4, 6.0, 4.6, 4.8, 3.6, 5.9, 5.0, 4.7, 5.4, 4.5, 4.0, 5.4, 6.3, 5.8, 6.6, 6.1, 5.1, 6.3, 5.0, 6.0];
// sds enterprising high
var norm7Data = [6.7, 5.6, 4.8, 6.9, 4.4, 6.6, 5.2, 5.7, 6.8, 6.9, 4.4, 6.6, 5.3, 6.2, 6.2, 5.1, 5.3, 6.3, 5.0, 5.1, 5.6];
// sds enterprising low
var norm8Data = [4.6, 6.6, 4.8, 4.5, 4.2, 4.4, 5.5, 4.6, 4.2, 5.4, 4.1, 4.1, 6.7, 6.1, 6.4, 5.9, 6.7, 5.7, 6.1, 4.3, 5.7];
// sds conventional high
var norm9Data = [5.8, 5.7, 5.8, 5.5, 5.4, 5.8, 5.4, 5.7, 5.6, 6.1, 5.0, 5.4, 5.4, 5.8, 5.0, 5.5, 6.0, 5.3, 5.4, 5.8, 5.5];
// sds conventional low
var norm10Data = [6.1, 5.8, 4.4, 5.9, 3.9, 5.9, 5.2, 5.4, 5.7, 6.3, 3.9, 5.5, 6.3, 6.0, 6.6, 5.0, 5.8, 6.3, 5.3, 4.4, 5.6];
// corporate
var norm11Data = [6.1, 5.0, 5.5, 5.8, 5.9, 6.5, 7.4, 5.0, 6.0, 5.5, 5.9, 6.1, 5.2, 4.1, 4.7, 5.2, 5.1, 6.0, 5.1, 5.5, 5.1];
// engineers
var norm12Data = [5.3, 5.9, 5.4, 5.6, 5.0, 5.3, 7.8, 4.6, 5.5, 5.5, 4.9, 5.4, 4.8, 5.4, 6.0, 5.5, 5.5, 6.2, 5.9, 5.2, 5.6];
// scientists
var norm13Data = [4.5, 5.4, 4.8, 5.4, 4.6, 4.5, 8.3, 4.8, 5.0, 4.8, 4.3, 5.0, 5.4, 5.1, 6.5, 5.8, 5.0, 6.9, 6.7, 4.9, 5.3];
// emotional expressivity high
var norm14Data = [7.3, 5.8, 4.6, 6.2, 5.2, 7.1, 6.6, 5.6, 5.9, 6.9, 4.3, 6.4, 6.0, 5.4, 6.1, 4.5, 6.0, 6.0, 4.2, 5.0, 5.9];
// emotional expressivity low
var norm15Data = [5.1, 5.8, 5.7, 5.0, 5.5, 5.5, 6.5, 5.7, 4.9, 5.5, 5.3, 5.0, 5.3, 5.9, 5.5, 6.1, 6.0, 5.3, 5.8, 5.3, 5.5];
// emotional sensitivity high
var norm16Data = [6.4, 6.0, 4.5, 5.7, 5.2, 6.9, 6.5, 5.3, 5.6, 6.4, 4.9, 5.3, 5.8, 5.8, 6.2, 5.3, 6.4, 6.1, 5.0, 4.9, 5.6];
// emotional sensitivity low
var norm17Data = [5.2, 5.5, 6.1, 5.1, 5.3, 5.2, 6.3, 5.8, 5.2, 5.7, 5.3, 5.2, 5.1, 5.8, 5.3, 6.1, 5.6, 5.0, 5.6, 5.3, 5.6];
// emotional control high
var norm18Data = [5.4, 5.5, 4.0, 5.7, 5.9, 5.5, 6.6, 5.6, 5.5, 5.9, 4.7, 5.4, 5.7, 5.6, 6.2, 6.2, 5.5, 6.1, 5.6, 5.1, 5.5];
// emotional control low
var norm19Data = [6.1, 5.8, 5.4, 5.4, 5.2, 6.4, 6.4, 5.6, 5.4, 6.1, 5.2, 5.6, 5.6, 5.5, 5.4, 5.3, 6.2, 5.4, 5.2, 5.1, 5.6];
// social expressivity high
var norm20Data = [7.4, 5.4, 4.7, 6.0, 4.9, 7.0, 6.5, 5.6, 5.5, 7.3, 4.5, 6.7, 5.7, 5.2, 5.8, 4.6, 5.8, 6.2, 4.1, 4.9, 5.5];
// social expressivity low
var norm21Data = [4.8, 5.8, 5.9, 4.9, 5.8, 5.2, 6.6, 5.6, 4.9, 5.1, 5.2, 4.8, 5.3, 5.8, 5.5, 6.2, 5.9, 5.1, 6.0, 5.3, 5.6];
// social sensitivity high
var norm22Data = [6.0, 7.0, 5.5, 4.7, 4.9, 6.3, 6.3, 4.6, 4.8, 6.3, 5.0, 4.7, 5.6, 5.7, 5.8, 5.2, 7.1, 5.0, 5.0, 5.3, 6.4];
// social sensitivity low
var norm23Data = [5.8, 4.8, 5.5, 5.7, 5.7, 5.8, 6.6, 6.3, 5.7, 5.9, 5.3, 5.9, 5.4, 5.1, 5.2, 5.6, 5.3, 5.7, 5.4, 5.3, 5.1];
// social control high
var norm24Data = [6.7, 4.8, 4.5, 6.4, 5.9, 6.6, 6.8, 6.2, 6.1, 6.3, 4.9, 6.9, 6.1, 4.7, 5.5, 5.0, 5.3, 6.5, 4.7, 5.3, 5.2];
// social control low
var norm25Data = [5.3, 6.2, 5.9, 4.7, 5.4, 5.4, 6.3, 5.2, 4.7, 5.7, 5.4, 4.8, 5.3, 5.8, 5.6, 5.8, 6.3, 5.0, 5.6, 5.2, 5.8];
// empathy high
var norm26Data = [7.0, 5.1, 4.2, 5.9, 4.3, 6.9, 6.4, 6.1, 5.4, 7.1, 4.5, 6.3, 6.2, 5.0, 6.1, 5.1, 5.8, 6.6, 4.5, 4.7, 5.0];
// empathy low
var norm27Data = [4.6, 7.1, 5.8, 5.0, 4.9, 4.6, 6.0, 4.2, 5.2, 5.5, 4.6, 4.1, 5.2, 6.7, 6.3, 6.1, 6.5, 5.1, 6.1, 5.4, 6.3];
// high psych emotional
var norm28Data = [5.9, 3.7, 5.7, 5.9, 6.0, 5.8, 6.1, 7.2, 5.8, 5.3, 5.9, 6.2, 5.2, 5.2, 4.7, 5.3, 3.6, 5.8, 5.0, 5.7, 4.7];
// high psych social
var norm29Data = [7.1, 4.6, 4.9, 6.8, 5.3, 6.8, 6.2, 6.2, 6.4, 6.3, 5.4, 5.4, 5.6, 5.5, 5.5, 4.5, 4.2, 6.1, 4.6, 5.5, 5.2];
// high psych occupational
var norm30Data = [5.8, 4.5, 5.7, 5.3, 5.8, 6.0, 5.9, 6.5, 5.2, 5.3, 6.0, 5.6, 5.3, 5.2, 5.0, 5.5, 4.6, 5.5, 5.0, 5.4, 5.0];
// self-esteem high
var norm31Data = [6.6, 3.6, 5.3, 6.9, 6.0, 6.6, 4.7, 7.1, 7.1, 5.9, 6.0, 6.8, 5.3, 5.2, 5.1, 5.3, 3.8, 6.0, 4.5, 6.1, 4.2];
// self-esteem low
var norm32Data = [4.9, 6.8, 5.5, 4.9, 5.0, 5.1, 4.2, 4.2, 4.7, 5.3, 5.2, 4.6, 5.5, 6.8, 6.7, 6.0, 6.3, 5.0, 5.9, 5.4, 5.6];
var origin = 5.5;
var factorLabels = [
['Extraversion', 'Introverted • Extroverted'],
['Anxiety', 'Low-Anxiety • High-Anxiety'],
['Tough-Mindedness', 'Receptive • Tough-Minded'],
['Independence', 'Accommodating • Independent'],
['Self-Control', 'Unrestrained • Self-Controlled'],
['Warmth (A)', 'Reserved • Warm'],
['Reasoning (B)', 'Concrete • Absract'],
['Emotional Stability (C)', 'Reactive • Emotionally Stable'],
['Dominance (E)', 'Deferential • Dominant'],
['Liveliness (F)', 'Serious • Lively'],
['Rule-Consciousness (G)', 'Expedient • Rule-Conscious'],
['Social Boldness (H)', 'Shy • Socially Bold'],
['Sensitivity (I)', 'Utilitarian • Sensitive'],
['Vigilance (L)', 'Trusting • Vigilant'],
['Abstractedness (M)', 'Grounded • Abstracted'],
['Privateness', 'Forthright • Private'],
['Apprehension (O)', 'Self-Assured • Apprehensive'],
['Openness to Change (Q1)', 'Traditional • Open to Change'],
['Self-Reliant (Q2)', 'Group-Oriented • Self-Reliant'],
['Perfectionism (Q3)', 'Tolerates Disorder • Perfectionistic'],
['Tension (Q4)', 'Relaxed • Tense'],
['Adjustment', 'Emotionally Fragile', ' • Emotionally Resilient'],
['Leadership', 'Non-Leader • Leader'],
['Creativity', 'Status Quo • Innovative']
];
var factorLabelsResearch = [
['Extraversion', 'Introverted • Extroverted'],
['Anxiety', 'Low-Anxiety • High-Anxiety'],
['Tough-Mindedness', 'Receptive • Tough-Minded'],
['Independence', 'Accommodating • Independent'],
['Self-Control', 'Unrestrained • Self-Controlled'],
['Warmth (A)', 'Reserved • Warm'],
['Reasoning (B)', 'Concrete • Absract'],
['Emotional Stability (C)', 'Reactive • Emotionally Stable'],
['Dominance (E)', 'Deferential • Dominant'],
['Liveliness (F)', 'Serious • Lively'],
['Rule-Consciousness (G)', 'Expedient • Rule-Conscious'],
['Social Boldness (H)', 'Shy • Socially Bold'],
['Sensitivity (I)', 'Utilitarian • Sensitive'],
['Vigilance (L)', 'Trusting • Vigilant'],
['Abstractedness (M)', 'Grounded • Abstracted'],
['Privateness', 'Forthright • Private'],
['Apprehension (O)', 'Self-Assured • Apprehensive'],
['Openness to Change (Q1)', 'Traditional • Open to Change'],
['Self-Reliant (Q2)', 'Group-Oriented • Self-Reliant'],
['Perfectionism (Q3)', 'Tolerates Disorder • Perfectionistic'],
['Tension (Q4)', 'Relaxed • Tense']
];
var factorLabelsThemes = ['Investigative', 'Realistic', 'Enterprising', 'Artistic', 'Conventional', 'Social'];
var factorLabelsLeft = ['Introverted', 'Low Anxiety', 'Receptive', 'Accomodating', 'Unrestrained', 'Reserved', 'Concrete', 'Reactive', 'Deferential', 'Serious', 'Expedient', 'Shy', 'Utilitarian', 'Trusting', 'Grounded', 'Forthright', 'Self-Asured', 'Traditional', 'Group-Oriented', 'Tolerates Disorder', 'Relaxed', 'Emotionally Fragile', 'Non-Leader', 'Status Quo'];
var factorLabelsRight = ['Extroverted', 'High Anxiety', 'Tough-Minded', 'Independent', 'Self-Controlled', 'Warm', 'Abstract', 'Emotionally Stable', 'Dominant', 'Lively', 'Rule-Conscious', 'Socially Bold', 'Sensitive', 'Vigilant', 'Abstracted', 'Private', 'Apprehensive', 'Open to Change', 'Self-Reliant', 'Perfectionistic', 'Tense', 'Emotionally Resilient', 'Leader', 'Innovative'];
var globalProfiles = {
labels: factorLabelsResearch,
datasets: []
};
globalProfiles.datasets.push({
data: role1Data.map(function(value) {
return value - origin;
}),
backgroundColor: 'rgba(79,143,0,.75)',
label: '0-4'
});
globalProfiles.datasets.push({
data: role2Data.map(function(value) {
return value - origin;
}),
backgroundColor: 'rgba(83, 134, 155,.75)',
label: '5-18'
});
globalProfiles.datasets.push({
data: role3Data.map(function(value) {
return value - origin;
}),
backgroundColor: 'rgba(182, 87, 56,.75)',
label: '19-32'
});
globalProfiles.datasets.push({
data: role4Data.map(function(value) {
return value - origin;
}),
backgroundColor: 'rgba(103, 182, 93,.75)',
label: '33-60'
});
globalProfiles.datasets.push({
data: service1Data.map(function(value) {
return value - origin;
}),
backgroundColor: 'rgba(79,143,0,.75)',
label: '0-50'
});
globalProfiles.datasets.push({
data: service2Data.map(function(value) {
return value - origin;
}),
backgroundColor: 'rgba(83, 134, 155,.75)',
label: '51-80'
});
globalProfiles.datasets.push({
data: service3Data.map(function(value) {
return value - origin;
}),
backgroundColor: 'rgba(182, 87, 56,.75)',
label: '81-100'
});
globalProfiles.datasets.push({
data: service4Data.map(function(value) {
return value - origin;
}),
backgroundColor: 'rgba(103, 182, 93,.75)',
label: '101-154'
});
globalProfiles.datasets.push({
data: program1Data.map(function(value) {
return value - origin;
}),
backgroundColor: 'green',
label: 'Program 1'
});
globalProfiles.datasets.push({
data: program2Data.map(function(value) {
return value - origin;
}),
backgroundColor: 'green',
label: 'Program 2'
});
globalProfiles.datasets.push({
data: function1Data.map(function(value) {
return value - origin;
}),
backgroundColor: 'rgba(83, 134, 155,.75)',
label: 'G&A'
});
globalProfiles.datasets.push({
data: function2Data.map(function(value) {
return value - origin;
}),
backgroundColor: 'rgba(182, 87, 56,.75)',
label: 'Sales & Service'
});
globalProfiles.datasets.push({
data: function3Data.map(function(value) {
return value - origin;
}),
backgroundColor: 'rgba(103, 182, 93,.75)',
label: 'Technology'
});
globalProfiles.datasets.push({
data: femaleData.map(function(value) {
return value - origin;
}),
backgroundColor: 'rgba(100,190,194,.75)',
label: 'Female'
});
globalProfiles.datasets.push({
data: maleData.map(function(value) {
return value - origin;
}),
backgroundColor: 'rgba(26,78,125,.75)',
label: 'Male'
});
globalProfiles.datasets.push({
data: allData.map(function(value) {
return value - origin;
}),
backgroundColor: 'rgba(103, 182, 93,.75)',
label: 'All'
});
globalProfiles.datasets.push({
data: norm1Data.map(function(value) {
return value - origin;
}),
backgroundColor: 'rgba(26,78,125,.99)',
label: 'High Realistic'
});
globalProfiles.datasets.push({
data: norm2Data.map(function(value) {
return value - origin;
}),
backgroundColor: 'rgba(26,78,125,.35)',
label: 'Low Realistic'
});
globalProfiles.datasets.push({
data: norm3Data.map(function(value) {
return value - origin;
}),
backgroundColor: 'rgba(26,78,125,.75)',
label: 'High Investigative'
});
globalProfiles.datasets.push({
data: norm4Data.map(function(value) {
return value - origin;
}),
backgroundColor: 'rgba(26,78,125,.15)',
label: 'Low Investigative'
});
globalProfiles.datasets.push({
data: norm5Data.map(function(value) {
return value - origin;
}),
backgroundColor: 'rgba(100,190,194,.99)',
label: 'High Social'
});
globalProfiles.datasets.push({
data: norm6Data.map(function(value) {
return value - origin;
}),
backgroundColor: 'rgba(100,190,194,.35)',
label: 'Low Social'
});
globalProfiles.datasets.push({
data: norm7Data.map(function(value) {
return value - origin;
}),
backgroundColor: 'rgba(100,190,194,.75)',
label: 'High Enterprising'
});
globalProfiles.datasets.push({
data: norm8Data.map(function(value) {
return value - origin;
}),
backgroundColor: 'rgba(100,190,194,.15)',
label: 'Low Enterprising'
});
globalProfiles.datasets.push({
data: norm9Data.map(function(value) {
return value - origin;
}),
backgroundColor: 'rgba(255,192,0,.99)',
label: 'High Conventional'
});
globalProfiles.datasets.push({
data: norm10Data.map(function(value) {
return value - origin;
}),
backgroundColor: 'rgba(255,192,0,.35)',
label: 'Low Conventional'
});
globalProfiles.datasets.push({
data: norm11Data.map(function(value) {
return value - origin;
}),
backgroundColor: 'rgba(26,78,125,.85)',
label: 'Corporate'
});
globalProfiles.datasets.push({
data: norm12Data.map(function(value) {
return value - origin;
}),
backgroundColor: 'rgba(26,78,125,.5)',
label: 'Engineers'
});
globalProfiles.datasets.push({
data: norm13Data.map(function(value) {
return value - origin;
}),
backgroundColor: 'rgba(26,78,125,.25)',
label: 'Scientists'
});
globalProfiles.datasets.push({
data: norm14Data.map(function(value) {
return value - origin;
}),
backgroundColor: 'rgba(100,190,194,.75)',
label: 'High Emotional Expressivity'
});
globalProfiles.datasets.push({
data: norm15Data.map(function(value) {
return value - origin;
}),
backgroundColor: 'rgba(26,78,125,.75)',
label: 'Low Emotional Expressivity'
});
globalProfiles.datasets.push({
data: norm16Data.map(function(value) {
return value - origin;
}),
backgroundColor: 'rgba(103, 182, 93,.75)',
label: 'High Emotional Sensitivity'
});
globalProfiles.datasets.push({
data: norm17Data.map(function(value) {
return value - origin;
}),
backgroundColor: 'rgba(79,143,0,.75)',
label: 'Low Emotional Sensitivity'
});
globalProfiles.datasets.push({
data: norm18Data.map(function(value) {
return value - origin;
}),
backgroundColor: 'rgba(83, 134, 155,.75)',
label: 'High Emotional Control'
});
globalProfiles.datasets.push({
data: norm19Data.map(function(value) {
return value - origin;
}),
backgroundColor: 'rgba(182, 87, 56,.75)',
label: 'Low Emotional Control'
});
globalProfiles.datasets.push({
data: norm20Data.map(function(value) {
return value - origin;
}),
backgroundColor: 'rgba(103, 182, 93,.75)',
label: 'High Social Expressivity'
});
globalProfiles.datasets.push({
data: norm21Data.map(function(value) {
return value - origin;
}),
backgroundColor: 'rgba(79,143,0,.75)',
label: 'Low Social Expressivity'
});
globalProfiles.datasets.push({
data: norm22Data.map(function(value) {
return value - origin;
}),
backgroundColor: 'rgba(83, 134, 155,.75)',
label: 'High Social Sensitivity'
});
globalProfiles.datasets.push({
data: norm23Data.map(function(value) {
return value - origin;
}),
backgroundColor: 'rgba(182, 87, 56,.75)',
label: 'Low Social Sensitivity'
});
globalProfiles.datasets.push({
data: norm24Data.map(function(value) {
return value - origin;
}),
backgroundColor: 'rgba(103, 182, 93,.75)',
label: 'High Social Control'
});
globalProfiles.datasets.push({
data: norm25Data.map(function(value) {
return value - origin;
}),
backgroundColor: 'green',
label: 'Low Social Control'
});
globalProfiles.datasets.push({
data: norm26Data.map(function(value) {
return value - origin;
}),
backgroundColor: 'green',
label: 'High Empathy'
});
globalProfiles.datasets.push({
data: norm27Data.map(function(value) {
return value - origin;
}),
backgroundColor: 'rgba(83, 134, 155,.75)',
label: 'Low Empathy'
});
globalProfiles.datasets.push({
data: norm28Data.map(function(value) {
return value - origin;
}),
backgroundColor: 'rgba(182, 87, 56,.75)',
label: 'High Psych Emotional'
});
globalProfiles.datasets.push({
data: norm29Data.map(function(value) {
return value - origin;
}),
backgroundColor: 'rgba(103, 182, 93,.75)',
label: 'High Psych Social'
});
globalProfiles.datasets.push({
data: norm30Data.map(function(value) {
return value - origin;
}),
backgroundColor: 'rgba(100,190,194,.75)',
label: 'High Psych Occupational'
});
globalProfiles.datasets.push({
data: norm31Data.map(function(value) {
return value - origin;
}),
backgroundColor: 'rgba(26,78,125,.75)',
label: 'High Self-Esteem'
});
globalProfiles.datasets.push({
data: norm32Data.map(function(value) {
return value - origin;
}),
backgroundColor: 'rgba(103, 182, 93,.75)',
label: 'Low Self-Esteem'
});
updateDataset = function(e, datasetIndex) {
var index = datasetIndex;
var ci = e.view.myGlobalProfiles;
var meta = ci.getDatasetMeta(index);
// See controller.isDatasetVisible comment
meta.hidden = meta.hidden === null? !ci.data.datasets[index].hidden : null;
// We hid a dataset ... rerender the chart
ci.update();
};
var ctxGlobalProfiles = document.getElementById('global-profiles').getContext('2d');
var myLegendContainer = document.getElementById("chart-legend");
var myGlobalProfiles = new Chart(ctxGlobalProfiles, {
type: 'horizontalBar',
data: globalProfiles,
options: {
elements: {
rectangle: {
borderWidth: 2,
}
},
layout: {
padding: {
left: 0,
right: 0,
top: 0,
bottom: 0
}
},
responsive: true,
legend: {
display: false,
},
legendCallback: function(chart) {
var legendHtml = [];
legendHtml.push('<ul>');
legendHtml.push('<h5>Company Data</h5>');
for (var i = 0; i < 16; i++) {
legendHtml.push('<li onclick="updateDataset(event, ' + '\'' + chart.legend.legendItems[i].datasetIndex + '\'' + ')">');
legendHtml.push('<span class="chart-color" style="background-color:' + chart.data.datasets[i].backgroundColor + '"></span><span>' + chart.data.datasets[i].label + '</span>');
legendHtml.push('</li>')
}
legendHtml.push('<hr />');
legendHtml.push('<h5>Research Data</h5>');
for (var i = 16; i < chart.data.datasets.length; i++) {
legendHtml.push('<li onclick="updateDataset(event, ' + '\'' + chart.legend.legendItems[i].datasetIndex + '\'' + ')">');
legendHtml.push('<span class="chart-color" style="background-color:' + chart.data.datasets[i].backgroundColor + '"></span><span>' + chart.data.datasets[i].label + '</span>');
legendHtml.push('</li>')
}
legendHtml.push('</ul>');
return legendHtml.join("");
},
tooltips: {
enabled: true,
backgroundColor: 'rgba(100,190,194,.95)',
bodyFontColor: 'rgba(26,78,125,.99)',
titleFontColor: 'rgba(26,78,125,.99)',
borderColor: 'rgba(26,78,125,.99)',
borderWidth: 1,
callbacks: {
label: function(tooltipItem, data) {
var label = data.datasets[tooltipItem.datasetIndex].label || '';
if (label) {
label += ': ';
}
label += tooltipItem.xLabel + 5.5;
return label;
}
}
},
scales: {
yAxes: [{
display: true,
offsetGridlines: true
}],
xAxes: [{
ticks: {
min: -4.5,
max: 4.5,
callback: function(value, index, values) {
return value + 5.5;
},
display: true
}
}]
},
title: {
display: true,
text: ''
}
}
});
myLegendContainer.innerHTML = myGlobalProfiles.generateLegend();
jQuery('#toggle-profiles').click(function() {
myGlobalProfiles.data.datasets.forEach(function(ds) {
ds.hidden = !ds.hidden;
});
myGlobalProfiles.update();
});
h4 {
text-align: center;
}
ul {
list-style: none;
}
li {
display: inline-block;
padding: 0 10px;
}
li.hidden {
text-decoration: line-through;
}
li span.chart-color {
border-radius: 5px;
display: inline-block;
height: 10px;
margin-right: 5px;
width: 10px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.bundle.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class='uk-panel uk-panel-box uk-panel-box-primary'>
<h3>Profiles from Research Data <br />and Company Data</h3>
<div class='uk-panel-box uk-panel-box-secondary uk-margin'>
<h4>The 5 Global & 16 Primary Factors</h4>
<button id='toggle-profiles'>show/hide all</button>
<div id="chart-legend"></div>
<canvas id='global-profiles' height='800'></canvas>
</div>

Jumping off what you've already created, add a click event around each HTML generated legend item, and use that click event to hide indiv. datasets, based on matching conditions.
I configured this in Angular, but the logic is similar.
With the below HTML, I am generating a custom legend which displays each of my labels. When a label is clicked, the hideOneDataset fn is called, passing the value of the legendItem clicked.
<div *ngIf="legendData">
<ul class="my-legend">
<li class="legend-item" *ngFor="let legendItem of legendData" (click)="hideOneDataset($event.target.innerText)">
{{ legendItem.text }}
</li>
</ul>
</div>
Then, I configured the hideOneDataset function to loop through each dataset item and determine if the legendItem from my custom HTML legend === that of the current element's label. If yes, hide it.
hideOneDataset(legendItem) {
// GET each dataset in the chart
this.chartComponent.chart.data.datasets.forEach(ele => {
// IF the custom legend item clicked on equals the label of one of our datapoints, hide that data
if (ele.label === legendItem) {
ele.hidden = !ele.hidden;
}
});
this.chartComponent.update();
}
Hope this helps a bit for anyone who stumbles upon this.

Related

Double aggregation of queryset in django

I need perform what is essentially a double aggregation. First, I need to get the average for the same events from different sources per ticker. Next, I need to get the sum of different events per ticker.
I can't figure out how to do this using Django. I've tried:
query1 = queryset.values('ticker', 'event_id').annotate(value_usd=Avg('value_usd'), shares=Avg('shares'), days_to_trade=Avg('days_to_trade'), num_trades=Count('ticker'))
query2 = query1.values('ticker').annotate(value_usd=Sum('value_usd'), shares=Sum('shares'), days_to_trade=Sum('days_to_trade'), num_trades=Count('security'))
but I receive an error django.core.exceptions.FieldError: Cannot compute Sum('value_usd'): 'value_usd' is an aggregate.
My raw data looks like this:
[{
'ticker': 'ACVA-US',
'source': 'INTERNAL',
'event_id': 300,
'value_usd': 3000.0,
'shares': 300.0,
'days_to_trade': 3.0,
'num_trades': 1
},
{
'ticker': 'ACVA-US',
'source': 'INTERNAL',
'event_id': 200,
'value_usd': 2000.0,
'shares': 200.0,
'days_to_trade': 2.0,
'num_trades': 1
},
{
'ticker': 'ACVA-US',
'source': 'EXTERNAL',
'event_id': 200,
'value_usd': 1000.0,
'shares': 100.0,
'days_to_trade': 1.0,
'num_trades': 1
}]
I need to perform what is essentially a double-aggregation. First, I need to take the average of items with the same ticker+event, which would look like:
[{
'ticker': 'ACVA-US',
'event_id': 300,
'value_usd': 3000.0,
'shares': 300.0,
'days_to_trade': 3.0,
'num_trades': 1
},
{
'ticker': 'ACVA-US',
'event_id': 200,
'value_usd': 1500.0,
'shares': 150.0,
'days_to_trade': 1.5,
'num_trades': 2
}]
Next, I need to sum up items across tickers, which would look like:
[{
'ticker': 'ACVA-US',
'value_usd': 4500.0,
'shares': 450.0,
'days_to_trade': 4.5,
'num_trades': 3
}]
I was hoping to do this without having to create a db view that performs the first aggregation, but so far I can't figure it out. I need to perform this at the queryset level without dropping into raw SQL because a bunch of other filtering occurs before and after this. Any advice?

Google Chart bars half the correct height in wkhtmltopdf

My Google Chart works perfectly in the browser:
Works perfectly
However, when I try to render this as a PDF using:
wkhtmltopdf --javascript-delay 2000 --print-media-type chart_dummy.html chart_dummy.pdf
the heights of the bars get halved, and the colour code goes missing:
Rendered PDF with bars half height
I take it there must be some wkhtmltopdf option to correct this, but I can't for the life of me identify one.
I'm using Ubuntu 16.04.7 LTS (Xenial Xerus), and wkhtmltopdf 0.12.5 (with patched qt).
My visualization function is
function drawVisualization() {// Create the data table.
var data = new google.visualization.DataTable();
data.addColumn('string', 'focus name');
data.addColumn('number', 'Exceeded');
data.addColumn('number', 'Achieved');
data.addColumn('number', 'Not Achieved');
data.addColumn('number', 'Regressed');
var width = $($('.container-fluid')[0]).width();
var height = $($('.container-fluid')[0]).height();
var options = {
'width': width,
'height': height,
'chartArea': {top:10},
title: String(),
vAxis: {
title: '% Progress',
minValue: 0,
maxValue: 100,
format: '#\'%\'',
baseline: 0,
},
hAxis: {
title: ''
},
seriesType: 'bars',
series: {
5: {
type: 'line'
}
},
colors: ['#ffe400', '#03ea74', '#ffa000', '#0095ff'],
annotations: {
alwaysOutside: true,
textStyle: {
fontSize: 20,
auraColor: '#eee',
color: '#eee'
}
},
animation: {
duration: 2000,
easing: 'linear',
startup: true
},
legend: 'bottom'
};
reportData = {
"combined": {
"exceeded": "34",
"achieved": "72",
"not_achieved": "14",
"regressed": "8"
}
};
data.addRows([
['All Focus Areas', Number(reportData['combined']['exceeded']), Number(reportData['combined']['achieved']), Number(reportData['combined']['not_achieved']), Number(reportData['combined']['regressed'])]
]);
var chart = new google.visualization.ComboChart(document.getElementById('chart_div'));
chart.draw(data, options);
}
Has anyone a clue how to make the PDF the same as the Browser rendering?

Moving vertical line when hovering over the chart using chart.js

I've been trying to add a vertical line that shows up with a tooltip when hovering over the chart. But I'm using chart.js 2.6 and the syntax from 1.x seems to be outdated.
I've the following code working for 1.x
var data = {
labels: ["JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"],
datasets: [{
data: [12, 3, 2, 1, 8, 8, 2, 2, 3, 5, 7, 1]
}]
};
var ctx = document.getElementById("LineWithLine").getContext("2d");
Chart.types.Line.extend({
name: "LineWithLine",
initialize: function() {
Chart.types.Line.prototype.initialize.apply(this, arguments);
var originalShowTooltip = this.showTooltip;
this.showTooltip = function(activePoints) {
if (activePoints.length) {
var ctx = this.chart.ctx;
var scale = this.scale;
ctx.save();
ctx.strokeStyle = '#aaa';
ctx.beginPath();
ctx.moveTo(activePoints[0].x, scale.startPoint);
ctx.lineTo(activePoints[0].x, scale.endPoint);
ctx.stroke();
ctx.restore();
}
return originalShowTooltip.apply(this, arguments);
}
}
});
new Chart(ctx).LineWithLine(data, {
datasetFill: false,
lineAtIndex: 2
});
<canvas id="LineWithLine" style="width: 98vw; height:180px"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/1.0.2/Chart.js"></script>
External link
Anyone know how to make it work for 2.6
Solution for ChartJS 2.6.0
ꜱᴄʀɪᴘᴛ (ᴇxᴛᴇɴᴅɪɴɢ ʟɪɴᴇ ᴄʜᴀʀᴛ)
Chart.defaults.LineWithLine = Chart.defaults.line;
Chart.controllers.LineWithLine = Chart.controllers.line.extend({
draw: function(ease) {
Chart.controllers.line.prototype.draw.call(this, ease);
if (this.chart.tooltip._active && this.chart.tooltip._active.length) {
var activePoint = this.chart.tooltip._active[0],
ctx = this.chart.ctx,
x = activePoint.tooltipPosition().x,
topY = this.chart.legend.bottom,
bottomY = this.chart.chartArea.bottom;
// draw line
ctx.save();
ctx.beginPath();
ctx.moveTo(x, topY);
ctx.lineTo(x, bottomY);
ctx.lineWidth = 2;
ctx.strokeStyle = '#07C';
ctx.stroke();
ctx.restore();
}
}
});
You would also need to set intersect: false for tooltips.
ᴡᴏʀᴋɪɴɢ ᴇxᴀᴍᴘʟᴇ ⧩
Chart.defaults.LineWithLine = Chart.defaults.line;
Chart.controllers.LineWithLine = Chart.controllers.line.extend({
draw: function(ease) {
Chart.controllers.line.prototype.draw.call(this, ease);
if (this.chart.tooltip._active && this.chart.tooltip._active.length) {
var activePoint = this.chart.tooltip._active[0],
ctx = this.chart.ctx,
x = activePoint.tooltipPosition().x,
topY = this.chart.legend.bottom,
bottomY = this.chart.chartArea.bottom;
// draw line
ctx.save();
ctx.beginPath();
ctx.moveTo(x, topY);
ctx.lineTo(x, bottomY);
ctx.lineWidth = 2;
ctx.strokeStyle = '#07C';
ctx.stroke();
ctx.restore();
}
}
});
var chart = new Chart(ctx, {
type: 'LineWithLine',
data: {
labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul'],
datasets: [{
label: 'Statistics',
data: [3, 1, 2, 5, 4, 7, 6],
backgroundColor: 'rgba(0, 119, 204, 0.8)',
borderColor: 'rgba(0, 119, 204, 0.3)',
fill: false
}]
},
options: {
responsive: false,
tooltips: {
intersect: false
},
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.6.0/Chart.min.js"></script>
<canvas id="ctx" height="200"></canvas>
Try this:
var ctx = this.$refs.canvas.getContext("2d");
// new Chart(ctx, config);
var originalLineDraw = Chart.controllers.line.prototype.draw;
Chart.helpers.extend(Chart.controllers.line.prototype, {
draw: function() {
originalLineDraw.apply(this, arguments);
var chart = this.chart;
var ctx = chart.chart.ctx;
if (this.chart.tooltip._active && this.chart.tooltip._active.length) {
var activePoint = this.chart.tooltip._active[0];
var ctx = this.chart.ctx;
var x = activePoint.tooltipPosition().x;
var topY = this.chart.scales['y-axis-0'].top;
var bottomY = this.chart.scales['y-axis-0'].bottom;
// draw line
ctx.save();
ctx.beginPath();
ctx.moveTo(x, topY);
ctx.lineTo(x, bottomY);
ctx.lineWidth = 0.5;
ctx.strokeStyle = '#eeeeee';
ctx.stroke();
ctx.restore();
}
}});
This will definitely help you.
This question is five years old. Nowadays, we can achieve this using plugins and hook calls in this case beforeTooltipDraw to capture the tooltip.caretX. Also we can use the build-in interaction option to achieve this.
This implementacion works with versions 3.x and 4.0.1 of ChartJS
const $chart = document.getElementById('chart')
const plugin = {
id: 'verticalLiner',
afterInit: (chart, args, opts) => {
chart.verticalLiner = {}
},
afterEvent: (chart, args, options) => {
const {inChartArea} = args
chart.verticalLiner = {draw: inChartArea}
},
beforeTooltipDraw: (chart, args, options) => {
const {draw} = chart.verticalLiner
if (!draw) return
const {ctx} = chart
const {top, bottom} = chart.chartArea
const {tooltip} = args
const x = tooltip?.caretX
if (!x) return
ctx.save()
ctx.beginPath()
ctx.moveTo(x, top)
ctx.lineTo(x, bottom)
ctx.stroke()
ctx.restore()
}
}
const data = {
labels: ["JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"],
datasets: [{
data: [12, 3, 2, 1, 8, 8, 2, 2, 3, 5, 7, 1]
}]
}
const options = {
type: 'line',
data,
options: {
maintainAspectRatio: false,
interaction: {
mode: 'index',
intersect: false,
},
plugins: {
verticalLiner: {}
}
},
plugins: [plugin]
}
const chart = new Chart($chart, options)
<div class="wrapper" style="width: 98vw; height:180px">
<canvas id="chart"></canvas>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.9.1/chart.min.js"></script>

Google charts hAxis grid lines at months

I've got problem with LineChart - I've got my chart date values from mid april to mid june and I want to make hAxis grid lines showing only borders between months from my data. Manually I've made it this way:
hAxis: {
textStyle: { fontSize: 10, color: '#999999' },
gridlines:{ color: '#eee' },
textPosition: 'in',
baselineColor: '#eee',
format: 'M',
ticks: [
new Date(2016, 4, 1),
new Date(2016, 5, 1),
new Date(2016, 6, 1)
]
}
But I want it to be made automatically fitting my data. Anyone can help?
read the data prior to drawing the chart,
and collect the ticks you need displayed
in the following working snippet,
the first day, of each month found, is added to tickMarks
google.charts.load('current', {
callback: function () {
var data = new google.visualization.DataTable();
data.addColumn('date', 'Date');
data.addColumn('number', '2015');
data.addColumn('number', '2016');
data.addRows([
[new Date('04/20/2016'), 200, 210],
[new Date('04/30/2016'), 190, 220],
[new Date('05/06/2016'), 205, 200],
[new Date('05/18/2016'), 220, 230],
[new Date('05/24/2016'), 212, 210],
[new Date('06/01/2016'), 185, 193],
[new Date('06/16/2016'), 196, 207]
]);
var tickMarks = [];
var curMonth = -1;
for (var i = 0; i < data.getNumberOfRows(); i++) {
var testDate = data.getValue(i, 0);
if (testDate.getMonth() > curMonth) {
curMonth = testDate.getMonth();
tickMarks.push(new Date(testDate.getFullYear(), testDate.getMonth(), 1));
}
}
var options = {
height: 400,
hAxis: {
textStyle: { fontSize: 10, color: '#999999' },
gridlines:{ color: '#eee' },
textPosition: 'in',
baselineColor: '#eee',
format: 'M',
ticks: tickMarks
}
};
var chart = new google.visualization.LineChart(document.getElementById('chart_div'));
chart.draw(data, options);
},
packages: ['corechart']
});
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div"></div>

How to change color of annotation text in google-charts

How do you change the color of an annotation text in Google Chart Tools LineChart ?
Here is an example
google.load('visualization', '1', {packages: ['corechart']});
google.setOnLoadCallback(drawChart);
function drawChart() {
var data = new google.visualization.DataTable();
data.addColumn('date', 'Date');
data.addColumn('number', 'Sales');
data.addColumn({id: 'title', label: 'Title', type: 'string', role: 'annotation'});
data.addRows([
[new Date(2012, 3, 5), 80, null],
[new Date(2012, 3, 12), 120, 'New Product'],
[new Date(2012, 3, 19), 80, null],
[new Date(2012, 3, 26), 65, null],
[new Date(2012, 4, 2), 70, null],
]);
var options = {
title: 'Sales by Week',
displayAnnotations: true,
hAxis: {title: 'Date',
titleTextStyle: {color: 'grey'}},
colors: ['#f07f09']
};
var chart = new google.visualization.LineChart(document.getElementById('chart_div'));
chart.draw(data, options);
}
I want the line to be orange and the annotation text in grey. Currently the annotation text is orange.
No need for extra style data column and plumbing code to fill it for every row with ugly (and even incomplete above) formatting string. Only resort to separate styling column if you want to have different annotation color for the different data points.
There's a global setting, search for annotations.textStyle in https://developers.google.com/chart/interactive/docs/gallery/linechart
var options = {
annotations: {
textStyle: {
fontName: 'Times-Roman',
fontSize: 18,
bold: true,
italic: true,
// The color of the text.
color: '#871b47',
// The color of the text outline.
auraColor: '#d799ae',
// The transparency of the text.
opacity: 0.8
}
}
};
Here is a concept code for your case (notice different initialization google.charts, very important):
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
google.charts.load('current', { 'packages': ['corechart', 'line', 'bar'] });
google.charts.setOnLoadCallback(drawChart);
function drawChart() {
var data = new google.visualization.DataTable();
data.addColumn('date', 'Date');
data.addColumn('number', 'Sales');
data.addColumn({id: 'title', label: 'Title', type: 'string', role: 'annotation'});
data.addRows([
[new Date(2012, 3, 5), 80, null],
[new Date(2012, 3, 12), 120, 'New Product'],
[new Date(2012, 3, 19), 80, null],
[new Date(2012, 3, 26), 65, null],
[new Date(2012, 4, 2), 70, null],
]);
var options = {
chart: {
title: 'Sales by Week'
},
hAxis: {
title: 'Date',
titleTextStyle: {color: 'grey'}
},
annotations: {
textStyle: {
color: 'grey',
}
}
colors: ['#f07f09']
};
var chart = new google.visualization.LineChart(document.getElementById('chart_div'));
chart.draw(data, options);
}
You can also change other text formatting of the annotation, like bold, italic, font type, etc. Here is an example where most of the text is configured to be bold:
var options = {
chart: {
title: title
},
hAxis: {
textStyle: {
bold: true
}
},
vAxis: {
format: 'decimal',
textStyle: {
bold: true
}
},
legendTextStyle: {
bold: true
},
titleTextStyle: {
bold: true
},
width: chart_width,
//theme: 'material', // material theme decreases the color contrast and sets the black color items (all text) to 171,171,171 grey -> washed out
annotations: {
alwaysOutside: true,
highContrast: true, // default is true, but be sure
textStyle: {
bold: true
}
}
};
More examples with source repo link: https://mrcsabatoth.github.io/GoogleChartsTalk/
Actually you can. Color of the annotations is the same as line color. Just put a dot in the place you want to make an annotation and set a dot's color to the desirable annotation color.
data.addColumn({type: 'string', role: 'style'});
data.addColumn({type:'string', role:'annotation'});
and then when you add data
'point { size: 14; shape-type: circle; fill-color: #63A74A','Your annotation'
See example at
http://www.marketvolume.com/stocks/stochasticsmomentumindex.asp?s=SPY&t=spdr-s-p-500
If your annotations are not "touching", ie. the points you'd like to annotate are not next to each other, you could add a second line and add the annotations to that line.
In the JSON example below I have a date and a "total balance", as well as an "Ann" line.
"cols":[
{
"id":"date",
"label":"date",
"type":"date",
"p":{
"role":"domain"
}
},
{
"id":"total-balance",
"label":"Total balance",
"type":"number",
"p":{
"role":"data"
}
},
{
"id":"ann",
"label":"Ann",
"type":"number",
"p":{
"role":"data"
}
},
{
"type":"string",
"p":{
"role":"annotation"
}
},
{
"type":"string",
"p":{
"role":"annotationText"
}
}
],
The annotation comes after the "Ann" column so it'll be added to the "Ann" data points.
In my JSON, the date and "total-balance" are always filled in. "Ann" and the annotations are usually empty:
"rows":[
{
"c":[
{
"v":"Date(2013, 0, 1)"
},
{
"v":1000
},
{
"v":null
},
{
"v":null
},
{
"v":null
}
]
},
{
"c":[
{
"v":"Date(2013, 0, 8)"
},
{
"v":1001
},
{
"v":null
},
{
"v":null
},
{
"v":null
}
]
},
When I need an annotation, the "Ann" cell gets the same value as the total balance, and the annotation is added:
{
"c":[
{
"v":"Date(2013, 1, 26)"
},
{
"v":2000
},
{
"v":2000
},
{
"v":"Something!"
},
{
"v":"Something happened here!"
}
]
},
In your GChart's configuration, you can now set two colours. One for the normal line, and one for the "Ann".
colors: ['black','red']
If you have no annotations "touching", GCharts will not draw a line between them and the points will remain "invisible", while the annotations show up at exactly the right place.
Short answer: no, you can't change the text color through standard options (you could write something to find that text in the SVG and change its color with javascript, but that is beyond my level).
You can see an answer from ASGallant on Google Groups here, and his example here.
// code borrowed from Google visualization API playground, slightly modified here
google.load('visualization', '1', {packages: ['corechart']});
google.setOnLoadCallback(drawVisualization);
function drawVisualization() {
// Create and populate the data table.
var data = new google.visualization.DataTable();
data.addColumn('string', 'x');
data.addColumn({type: 'string', role: 'annotation'});
data.addColumn({type: 'string', role: 'annotationText'});
data.addColumn('number', 'Cats');
data.addColumn('number', 'Blanket 1');
data.addColumn('number', 'Blanket 2');
data.addRow(["A", null, null, 1, 1, 0.5]);
data.addRow(["B", null, null, 2, 0.5, 1]);
data.addRow(["C", null, null, 4, 1, 0.5]);
data.addRow(["D", null, null, 8, 0.5, 1]);
data.addRow(["E", 'foo', 'foo text', 7, 1, 0.5]);
data.addRow(["F", null, null, 7, 0.5, 1]);
data.addRow(["G", null, null, 8, 1, 0.5]);
data.addRow(["H", null, null, 4, 0.5, 1]);
data.addRow(["I", null, null, 2, 1, 0.5]);
data.addRow(["J", null, null, 3.5, 0.5, 1]);
data.addRow(["K", null, null, 3, 1, 0.5]);
data.addRow(["L", null, null, 3.5, 0.5, 1]);
data.addRow(["M", null, null, 1, 1, 0.5]);
data.addRow(["N", null, null, 1, 0.5, 1]);
// Create and draw the visualization.
var chart = new google.visualization.LineChart(document.getElementById('visualization'));
chart.draw(data, {
annotation: {
1: {
style: 'line'
}
},
curveType: "function",
width: 500,
height: 400,
vAxis: {
maxValue: 10
}
});
}
The best you can do is to change the style of the line, but it doesn't look like you can currently change the color of the line.
Has this been updated using the 'style' option where one could add a new column {"type":"string","role":"style"} and in each row we would have {"v":"point {size: 4; fill-color: #3366cc;}"}? This allows the annotation to have the same color as the point/marker (which could be changed for each point) but does not allow it to be bold. One example of the data to try would be,
var data =new google.visualization.DataTable(
{
"cols":[
{"label":"Log GDP Per-Capita ","type":"number"},
{"label":"New Chart",
"type":"number"},
{"type":"string","role":"annotation"},
{"type":"string","role":"style"}
],
"rows":[
{"c":[{"v":10.21932},{"v":12.3199676},{"v":"ABW"},{"v":"point {size: 4; fill-color: #3366cc;}"}]},
{"c":[{"v":10.68416},{"v":8.4347518},{"v":"ARE"},{"v":"point {size: 4; fill-color: #3366cc;}"}]},
{"c":[{"v":9.634226},{"v":12.0774068},{"v":"ATG"},{"v":"point {size: 4; fill-color: #3366cc;}"}]},
{"c":[{"v":10.83869},{"v":1.8545959},{"v":"AUS"},{"v":"point {size: 4; fill-color: #3366cc;}"}]},
{"c":[{"v":10.7687},{"v":7.4919999},{"v":"AUT"},{"v":"point {size: 4; fill-color: #3366cc;}"}]}
]
}
);