How to add gradient colors in Plotly - javascript

I am trying to add gradient colors in edges of a force directed graph made in Plotly.js.
I have taken the input through Json file and have also used 'color_continuous_scale' to add the colors. But the desired result is not coming.
Full code:
<html>
<head>
<script src="https://cdn.plot.ly/plotly-1.58.5.min.js"></script>
<style>
.graph-container {
display: flex;
justify-content: center;
align-items: center;
}
.main-panel {
width: 70%;
float: left;
}
.side-panel {
width: 30%;
background-color: lightgray;
min-height: 300px;
overflow: auto;
float: right;
}
</style>
</head>
<body>
<div class="graph-container">
<div id="myDiv" class="main-panel"></div>
<div id="lineGraph" class="side-panel"></div>
</div>
<script>
fetch('data.json')
.then(response => response.json())
.then(data => {
var nodes = data.nodes;
var edges = data.edges;
var x = [];
var y = [];
var z = [];
for (var i = 0; i < nodes.length; i++) {
x.push(nodes[i].x);
y.push(nodes[i].y);
z.push(nodes[i].z);
}
const edge_x = [];
const edge_y = [];
const edge_z = [];
for (var i = 0; i < edges.length; i++) {
const a = nodes[data.edges[i].source];
const b = nodes[data.edges[i].target];
edge_x.push(a.x, b.x, null);
edge_y.push(a.y, b.y, null);
edge_z.push(a.z, b.z, null);
}
const traceEdges = {
x: edge_x,
y: edge_y,
z: edge_z,
type: 'scatter3d',
mode: 'lines',
line: { color: 'traceEdges', color_continuous_scale: 'Inferno', width: 10},
opacity: 0.8
};
var traceNodes = {
x: x, y: y, z: z,
mode: 'markers',
marker: { size: 12, color: 'red' },
type: 'scatter3d',
text: [0, 1, 2, 3, 4],
hoverinfo: 'text',
hoverlabel: {
bgcolor: 'white'
},
customdata: nodes.map(function(node) {
if (node.value !== undefined)
return node.value;
}),
type: 'scatter3d'
};
var layout = {
margin: { l: 0, r: 0, b: 0, t: 0 }
};
Plotly.newPlot('myDiv',[traceEdges, traceNodes], layout);
// max y value for the line plot
const ymax = Math.max(...nodes.map(n => n.value).flat());
document.getElementById('myDiv').on('plotly_click', function(data){
var nodeIndex = data.points[0].pointNumber;
var values = nodes[nodeIndex].value;
Plotly.newPlot('lineGraph', [{
type: 'scatter',
mode: 'lines',
x: [0, 1, 2],
y: values
}], {
margin: { t: 0 },
yaxis: {autorange: false, range: [0, ymax + 1]}
}
);
});
})
</script>
</body>
</html>
As you can see in the above image that the plot is showing only one color in the edges. I want to change this attribute to gradient coloring. Any changes in the code will be welcomed.

You need to specify a color array so that values from that array can be mapped to a colorscale :
color - Sets the line color. It accepts either a specific color or an array of numbers that are mapped to the colorscale relative to the max and min values of the array or relative to line.cmin and line.cmax if set.
colorscale - Sets the colorscale. Has an effect only if in line.color is set to a numerical array. The colorscale must be an array containing arrays mapping a normalized value to an rgb, rgba, hex, hsl, hsv, or named color string [...]. Alternatively, colorscale may be a palette name string [...].
For example by setting color: edge_y, edges are colored according to their positioning on the y axis (y coordinates of the source and target nodes) :
const traceEdges = {
x: edge_x,
y: edge_y,
z: edge_z,
type: 'scatter3d',
mode: 'lines',
line: {
autocolorscale: false,
colorscale: 'Cividis',
color: edge_y,
width: 10
},
opacity: 0.8,
};
Nb. color_continuous_scale is specific to plotly.express (python), and the 'Inferno' color scale as well. You can't use it with plotly.js.

Related

Why are the edge lines misplaced in plotly.js network graph? [duplicate]

I am trying to plot a 3d network using plotly.js
<html>
<head>
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
</head>
<body>
<div id="myDiv"></div>
<script>
var nodes = [
{ x: 0, y: 0, z: 0 },
{ x: 1, y: 1, z: 1 },
{ x: 2, y: 0, z: 2 },
{ x: 3, y: 1, z: 3 },
{ x: 4, y: 0, z: 4 }
];
var edges = [
{ source: 0, target: 1 },
{ source: 1, target: 2 },
{ source: 2, target: 3 },
{ source: 3, target: 4 }
];
var x = [];
var y = [];
var z = [];
for (var i = 0; i < nodes.length; i++) {
x.push(nodes[i].x);
y.push(nodes[i].y);
z.push(nodes[i].z);
}
var xS = [];
var yS = [];
var zS = [];
var xT = [];
var yT = [];
var zT = [];
for (var i = 0; i < edges.length; i++) {
xS.push(nodes[edges[i].source].x);
yS.push(nodes[edges[i].source].y);
zS.push(nodes[edges[i].source].z);
xT.push(nodes[edges[i].target].x);
yT.push(nodes[edges[i].target].y);
zT.push(nodes[edges[i].target].z);
}
var traceNodes = {
x: x, y: y, z: z,
mode: 'markers',
marker: { size: 12, color: 'red' },
type: 'scatter3d'
};
var traceEdges = {
x: [xS, xT],
y: [yS, yT],
z: [zS, zT],
mode: 'lines',
line: { color: 'red', width: 2},
opacity: 0.8,
type: 'scatter3d'
};
var layout = {
margin: { l: 0, r: 0, b: 0, t: 0 }
};
Plotly.newPlot('myDiv', [traceNodes, traceEdges], layout);
</script>
</body>
</html>
The nodes of the network are visible but the edges are not visible. Suggestions on
how to fix this issue will be really helpful.
The problem is how traceEdges is built. On each axis, there should be a list of (source, target) coordinates separated by a null value, ie. :
x: [source_0.x, target_0.x, null, source_1.x, target_1.x, null, ...]
We use null values to properly isolate each edge from the others and prevent chaining them all together (we want to draw a line between source_0 and target_0, but not between target_0 and source_1).
So instead of having [xS, xT], [yS, yT], and [zS, zT] we will just have edge_x, edge_y, and edge_z, defined as follows :
const edge_x = [];
const edge_y = [];
const edge_z = [];
for (var i = 0; i < edges.length; i++) {
const a = nodes[edges[i].source];
const b = nodes[edges[i].target];
edge_x.push(a.x, b.x, null);
edge_y.push(a.y, b.y, null);
edge_z.push(a.z, b.z, null);
}
const traceEdges = {
x: edge_x,
y: edge_y,
z: edge_z,
type: 'scatter3d',
mode: 'lines',
line: { color: 'red', width: 2},
opacity: 0.8
};
// (rest of the code doesn't change)
Here is the output :

Plotting 3d network graphs in plotly

I am trying to plot a 3d network using plotly.js
<html>
<head>
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
</head>
<body>
<div id="myDiv"></div>
<script>
var nodes = [
{ x: 0, y: 0, z: 0 },
{ x: 1, y: 1, z: 1 },
{ x: 2, y: 0, z: 2 },
{ x: 3, y: 1, z: 3 },
{ x: 4, y: 0, z: 4 }
];
var edges = [
{ source: 0, target: 1 },
{ source: 1, target: 2 },
{ source: 2, target: 3 },
{ source: 3, target: 4 }
];
var x = [];
var y = [];
var z = [];
for (var i = 0; i < nodes.length; i++) {
x.push(nodes[i].x);
y.push(nodes[i].y);
z.push(nodes[i].z);
}
var xS = [];
var yS = [];
var zS = [];
var xT = [];
var yT = [];
var zT = [];
for (var i = 0; i < edges.length; i++) {
xS.push(nodes[edges[i].source].x);
yS.push(nodes[edges[i].source].y);
zS.push(nodes[edges[i].source].z);
xT.push(nodes[edges[i].target].x);
yT.push(nodes[edges[i].target].y);
zT.push(nodes[edges[i].target].z);
}
var traceNodes = {
x: x, y: y, z: z,
mode: 'markers',
marker: { size: 12, color: 'red' },
type: 'scatter3d'
};
var traceEdges = {
x: [xS, xT],
y: [yS, yT],
z: [zS, zT],
mode: 'lines',
line: { color: 'red', width: 2},
opacity: 0.8,
type: 'scatter3d'
};
var layout = {
margin: { l: 0, r: 0, b: 0, t: 0 }
};
Plotly.newPlot('myDiv', [traceNodes, traceEdges], layout);
</script>
</body>
</html>
The nodes of the network are visible but the edges are not visible. Suggestions on
how to fix this issue will be really helpful.
The problem is how traceEdges is built. On each axis, there should be a list of (source, target) coordinates separated by a null value, ie. :
x: [source_0.x, target_0.x, null, source_1.x, target_1.x, null, ...]
We use null values to properly isolate each edge from the others and prevent chaining them all together (we want to draw a line between source_0 and target_0, but not between target_0 and source_1).
So instead of having [xS, xT], [yS, yT], and [zS, zT] we will just have edge_x, edge_y, and edge_z, defined as follows :
const edge_x = [];
const edge_y = [];
const edge_z = [];
for (var i = 0; i < edges.length; i++) {
const a = nodes[edges[i].source];
const b = nodes[edges[i].target];
edge_x.push(a.x, b.x, null);
edge_y.push(a.y, b.y, null);
edge_z.push(a.z, b.z, null);
}
const traceEdges = {
x: edge_x,
y: edge_y,
z: edge_z,
type: 'scatter3d',
mode: 'lines',
line: { color: 'red', width: 2},
opacity: 0.8
};
// (rest of the code doesn't change)
Here is the output :

Chartjs-gauge create circumference until certain value from data

I am creating 5 sections of gauge using chartjs-gauge. I am using the following data.
[150,200,250,300,400]
From this data, I want to display the circumference until 300. But the angle should calculated by including the last section value too. I had custom the text showing in section by setting it to empty string if more than 300. For section colour, I set 4 colours["green", "yellow", "orange", "red"]. Now, last section showing as silver colour which is default background of gauge. I have add rgba(0,0,0,0) to colour array ["green", "yellow", "orange", "red","rgba(0,0,0,0)"] which will show transparent colour for last section. But, when hover on section, it is responsive showing border. I would like to know if have other way to show the circumference until certain value from our data ,but calculating section area in chart using all value from data.
var data = [150, 200, 250, 300, 400];
var config = {
type: "gauge",
data: {
labels: ['Success', 'Warning', 'Warning', 'Error'],
datasets: [{
data: data,
value: 300,
backgroundColor: ["green", "yellow", "orange", "red"],
borderWidth: 2
}]
},
options: {
responsive: true,
title: {
display: true,
text: "Gauge chart with datalabels plugin"
},
layout: {
padding: {
bottom: 30
}
},
needle: {
// Needle circle radius as the percentage of the chart area width
radiusPercentage: 2,
// Needle width as the percentage of the chart area width
widthPercentage: 3.2,
// Needle length as the percentage of the interval between inner radius (0%) and outer radius (100%) of the arc
lengthPercentage: 80,
// The color of the needle
color: "rgba(0, 0, 0, 1)"
},
valueLabel: {
formatter: Math.round
},
plugins: {
datalabels: {
display: true,
formatter: function(value, context) {
//return '>'+value;
if (value <= 300) {
return value;
} else {
return '';
}
},
color: function(context) {
//return context.dataset.backgroundColor;
return 'black';
},
//color: 'rgba(255, 255, 255, 1.0)',
/*backgroundColor: "rgba(0, 0, 0, 1.0)",*/
borderWidth: 0,
borderRadius: 5,
font: {
weight: "bold"
}
}
}
}
};
window.onload = function() {
var ctx = document.getElementById("chart").getContext("2d");
window.myGauge = new Chart(ctx, config);
};
canvas {
-moz-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!DOCTYPE html>
<html lang="en-US">
<head>
<script src="jQuery/jquery-3.4.1.min.js"></script>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Gauge Chart with datalabels plugin</title>
<script src="https://unpkg.com/chart.js#2.8.0/dist/Chart.bundle.js"></script>
<script src="https://unpkg.com/chartjs-gauge#0.3.0/dist/chartjs-gauge.js"></script>
<script src="https://unpkg.com/chartjs-plugin-datalabels#0.7.0/dist/chartjs-plugin-datalabels.js"></script>
</head>
<body>
<div id="canvas-holder" style="width:100%">
<canvas id="chart"></canvas>
</div>
</body>
</html>
var data = [150, 200, 250, 300, 400];
colour_array = ["#11d8ee", "#3cc457", "#f12b0e", "#dda522", "#808080"];
let sum = data.reduce(function(a, b) {
return a + b;
}, 0);
var perc = 0;
perc_array = [];
for (i = 0; i < data.length; i++) {
perc = (data[i] / sum * 100).toFixed(2);
perc_array.push(perc);
}
Chart.plugins.register({ //increase distance between legend and chart
id: 'paddingBelowLegends',
beforeInit: function(chart, options) {
chart.legend.afterFit = function() {
this.height = this.height + 50; //custom 50 to value you wish
};
}
});
//when want to disable this plugin in other chart, paddingBelowLegends: false in plugin{}
var config = {
type: "doughnut",
data: {
labels: ['A', 'B', 'C', 'D', 'Others'],
datasets: [{
data: data,
value: data[(colour_array.length - 1)], //300
backgroundColor: colour_array,
borderWidth: 2
}]
},
options: {
responsive: true,
cutoutPercentage: 60,//thickness of chart
title: {
display: true,
text: "Gauge chart with datalabels plugin"
},
layout: {
padding: {
bottom: 30
}
},
valueLabel: {
formatter: Math.round,
display: false // hide the label in center of gauge
},
plugins: {
beforeInit: function(chart, options) {
chart.legend.afterFit = function() {
this.height = this.height + 50;
};
},
outlabels: {
display: true,
//text: '%l %v %p',//(label value percentage)the percentage automatically roundoff
//hide chart text label for last section-https://github.com/Neckster/chartjs-plugin-piechart-outlabels/issues/10#issuecomment-716606369
text: function(label) {
console.log(label);
highest_index = label['labels'].length - 1; //get highest index from the labels array
current_index = label['dataIndex']; //current index
value = label['dataset']['data'][label['dataIndex']]; //value of current index
const v = parseFloat(label['percent']) * 100;
if (current_index != highest_index) //to hide last section text label on chart.
{
//return value + ' , ' + `${v.toFixed(2)}%`;
return value+',\n'+`${v.toFixed(2)}%`;
} else {
return false;
}
},
color: 'white',
stretch: 12, //length of stretching
font: {
resizable: true,
minSize: 10,
maxSize: 14
},
padding: {
/*left:25,
right: 0
top:0,
bottom:0*/
}
},
//inner label:
datalabels: { //label on arc section
display: false,
formatter: function(value, context) {
if (value <= data[(colour_array.length - 2)]) //hide datalabel for last section
{
id = data.indexOf(value);
perc = perc_array[id];
return value + ' , ' + perc + '%';
} else {
return '';
}
},
color: function(context) {
return 'black';
},
borderWidth: 0,
borderRadius: 10,
font: {
weight: "bold",
},
anchor: "end" //'center' (default): element center, 'start': lowest element boundary, 'end': highest element boundary
}
},
legend: { //filter last section from legend chart labels
display: true,
//position: 'right',
labels: {
filter: function(legendItem, data) {
//ori-return legendItem !=1;
return !legendItem.text.includes('Others');
},
boxWidth: 20
}
},
rotation: 1 * Math.PI,
circumference: 1 * Math.PI,
tooltips: {
enabled: true,
mode: 'single',
filter: function(tooltipItem, data) { //disable display tooltip in last section
var label = data.labels[tooltipItem.index];
if (label == "Others") {
return false;
} else {
return true;
}
},
callbacks: { //custom tooltip text to show percentage amount (by default,showing real amount)
label: function(tooltipItem, data) {
var dataset = data.datasets[tooltipItem.datasetIndex];
hovered_index = tooltipItem.index;
data_length = data.datasets[0].data.length;
var total = dataset.data.reduce(function(previousValue, currentValue, currentIndex, array) {
return previousValue + currentValue;
});
var currentValue = dataset.data[tooltipItem.index];
var percentage = (currentValue / total * 100).toFixed(2);
return currentValue + ' , ' + percentage + "%";
}
}
}
}
};
window.onload = function() {
var ctx = document.getElementById("chartJSContainer").getContext("2d");
window.myGauge = new Chart(ctx, config);
};
<html>
<head>
<script src="https://unpkg.com/chart.js#2.8.0/dist/Chart.bundle.js"></script>
<script src="https://unpkg.com/chartjs-gauge#0.3.0/dist/chartjs-gauge.js"></script>
<script src="https://unpkg.com/chartjs-plugin-datalabels#0.7.0/dist/chartjs-plugin-datalabels.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-piechart-outlabels"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
</head>
<body>
<div id="canvas-holder" style="width:50% align:center">
<canvas id="chartJSContainer"></canvas>
</div>
</body>
</html>

Add percentage to label badge of doughnut chart.js [duplicate]

I've been doing a lot of research but I wasn't able to figure out, how to enter percentage into labels badge like this image below.
update:
I'm using this laravel wrapper : https://github.com/ConsoleTVs/Charts
so was the reason I didn't want to confuse viewers.
I just want to know the name of the option..
my code is this:
$perTopicChart = (new AnsweredPerTopic);//->percentageInnerCutout(70);
$perTopicChart->options([
"events" => [],
"legend" => [
"labels" => [
"defaultFontFamily" => "Tahoma",
"fontSize" => 16,
],
"position" => 'bottom'
],
"cutoutPercentage" => 80,
'tooltips' => [
"show" => true
]
])->displayAxes(0);
// put the labels (keys)
$perTopicChart->labels($keys->map(function ($q) use ($perTopic) {
$topic = Topic::find($q);
$str = $topic->name;
foreach ($perTopic as $key => $value) {
if ($key == $q) {
$str .= ' ' . round($value) . '%';
}
}
return "topic name " . '-'. $topic->id;
})->push('other'))
->options([]);
// get random color
// $color = RandomColor::many(count($keys), array(
// 'luminosity' => 'bright',
// 'hue' => ['pink', 'green', 'orange'] // e.g. 'rgb(225,200,20)'
// ));
$color = [
"#38c172",
"#9F9",
"#Fa0",
"pink",
"red",
];
$perTopicChart->dataset("Practice per Category", "doughnut", $values->map(function ($q) {
return round($q);
})->push($remainingPercenteg))
->backgroundColor($color)
->options([
'borderWidth' => 2.5,
]);
the first image the current result and the second is what I wanted.
thanks in advance.
Even I researched a lot, couldn't find anything for this kind of behavior in chartjs library, So come up with a hack.
Hack is something like, Do not let chart js to draw legends, Instead we just get the HTML of legends from chart js library, and put it in our container. By doing this we have full access of legends and we can do whatever we want.
https://jsfiddle.net/1kxenzpr/
const data = [70, 30, 0];
debugger;
var ctx = document.getElementById("myChart").getContext('2d');
var chart = new Chart(ctx, {
type: 'pie',
data: {
labels: ["Green", "Blue", "Gray", "Purple", "Yellow", "Red", "Black"],
datasets: [{
backgroundColor: [
"#2ecc71",
"#3498db",
"#95a5a6",
"#9b59b6",
"#f1c40f",
"#e74c3c",
"#34495e"
],
data: data
}]
},
options: {
legend: {
display: false
},
}
});
var myLegendContainer = document.getElementById("legend");
myLegendContainer.innerHTML = chart.generateLegend();
var legendItems = myLegendContainer.getElementsByTagName('li');
for (var i = 0; i < legendItems.length; i++) {
legendItems[i].querySelectorAll('span')[0].innerHTML = data[i] + '%'
}
.container {
width: 80%;
margin: 15px auto;
}
[class$="-legend"] {
list-style: none;
cursor: pointer;
padding-left: 0;
}
[class$="-legend"] li {
display: inline-block;
padding: 0 5px;
}
[class$="-legend"] li.hidden {
text-decoration: line-through;
}
[class$="-legend"] li span {
display: inline-block;
margin-right: 10px;
width: 50px;
font-size: 12px;
text-align: center;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<div class="container">
<div>
<canvas id="myChart"></canvas>
<div id="legend"></div>
</div>
</div>
No way (By setting X or Y). You should use legendCallback:
https://www.chartjs.org/docs/latest/configuration/legend.html#html-legends
In general, your Q does not follow StackOverflow guidelines (This is more a mission, not Q).
https://stackoverflow.com/help/how-to-ask
Anyway, this is +- the idea (convert to % by basic JS). To take this step forward you should generate full generate HTML legend (To put a number inside a color div). Related: Custom Legend with ChartJS v2.0
var myData = [4, 9, 5];
var data = {
labels: ["Africa", "Asia", "Europe"],
datasets: [{
label: "Population (millions)",
backgroundColor: ["#3e95cd", "#8e5ea2","#3cba9f"],
data: myData
}]
};
/* get total */
const reducer = (accumulator, currentValue) => accumulator + currentValue;
var total = myData.reduce(reducer);
var options = {
responsive: true,
title: {
text: 'Show % calucate on fly',
position: 'top',
display: true
},
legend: {
display: true,
labels: {
/* generateLabels */
generateLabels(chart) {
const data = chart.data;
if (data.labels.length && data.datasets.length) {
/* inner loop throw lables */
return data.labels.map((label, i) => {
var backgroundColor = data.datasets[0].backgroundColor[i];
var current = data.datasets[0].data[i];
var percentage = ((current * 100) / total).toFixed(2) + '%';
return {
text: label + " | " + percentage,
fillStyle: backgroundColor,
// Extra data used for toggling the correct item
index: i
};
});
}
return [];
}
},
},
scales: {
xAxes: [{
display: true
}],
yAxes: [{
display: true
}]
}
};
new Chart(document.getElementById("chart"), {
type: 'pie',
data: data,
options: options
});
<canvas id="chart" width="800" height="450"></canvas>
<script src="https://cdn.jsdelivr.net/npm/chart.js#2.8.0"></script>

Flotchart stacked bar total label

I am using Flotcharts to create a stacked bar chart to show breakdown of values. I have this working so that once I hover over the stack it will show a tool tip with the value for that stack in it (you can see this in the second column).
What I need is at the top of all the stacks that it shows a label of the total value.
Something like High Charts Stacked Column.
You can see my code below. I loop through the data (using Smarty) and set it there.
// set the data
var data = [
{
label: 'Tenant',
data: [
{foreach $metrics.rent_applied_by_month as $rent_applied}
[{$rent_applied#index}, {$rent_applied.tenant_value|number_format:2:'.':''}],
{/foreach}
],
color: '#008000'
},
{
label: 'Benefit',
data: [
{foreach $metrics.rent_applied_by_month as $rent_applied}
[{$rent_applied#index}, {$rent_applied.benefit_value|number_format:2:'.':''}],
{/foreach}
],
color: '#0000ff'
}
];
// set the xasis labels
var ticks = [
{foreach $metrics.rent_applied_by_month as $rent_applied}
[{$rent_applied#index}, '{$rent_applied.period}'],
{/foreach}
];
// chart options
var options = {
series: {
stack: 0,
bars: {
show: true,
align: "center",
barWidth: 0.6,
fill: .75,
}
},
xaxis: {
ticks: ticks,
tickLength: 1
},
grid: {
hoverable: true,
clickable: true,
borderWidth: {
top: 0,
right: 0,
bottom: 1,
left: 1
},
borderColor: {
top: "#e5e5e5",
right: "#e5e5e5",
bottom: "#a5b2c0",
left: "#a5b2c0"
}
},
legend: {
show: true,
noColumns: 2,
position: "nw",
margin: [10, 0],
labelBoxBorderColor: null
}
};
$.plot("#rent_applied", data, options);
You'll need to loop through each of the bars in each stack to get the total value of all bars in each stack. With that total value in hand, you can pass it into flot's plot.pointOffset() method to get the position of the top of the stacked bars.
The code below has a sample method to get all of the values of a stack of bars, then uses the plot.pointOffset() to append a div showing the value on top of the bar.
$(function() {
var data = [{
data: [ [0, 21.51], [1, 32.50], [2, 47.14], [3, 10] ],
stack: 0,
label: 'Bottom'
}, {
data: [ [0, 37.77], [1, 24.65], [2, 7.67], [4, 15]],
stack: 0,
label: 'Top'
}];
var options = {
series: {
bars: {
show: true,
barWidth: .5,
align: "center"
},
points: { show: false }
}
};
var plot = $.plot($('#graph'), data, options);
displayBarValues();
// display values on top of bars
function displayBarValues() {
var plotData = plot.getData();
var xValueToStackValueMapping = [];
// loop through each data series
for (var i = 0; i < plotData.length; i++) {
var series = plotData[i];
// loop through each data point in the series
for (var j = 0; j < series.data.length; j++) {
var value = series.data[j];
// if the x axis value is not in the mapping, add it.
if (!xValueExistsInMapping(xValueToStackValueMapping, value[0])) {
xValueToStackValueMapping.push([value[0], 0]);
}
// add the value of the bar to the x value mapping
addValueToMapping(xValueToStackValueMapping, value[0], value[1]);
}
}
// loop through each of our stacked values and place them on the bar chart
$.each(xValueToStackValueMapping, function(i, value) {
// find the offset of the top left of the bar
var leftoffset = plot.pointOffset({ x: value[0] - .5, y: value[1] });
// find the offset of the top right of the bar (our bar width is .5)
var rightoffset = plot.pointOffset({ x: value[0] + .5, y: value[1] });
$('<div class="data-point-value">' + value[1] + '</div>').css({
left: leftoffset.left,
top: leftoffset.top - 14,
width: rightoffset.left - leftoffset.left,
textAlign: 'center'
}).appendTo(plot.getPlaceholder());
});
}
function xValueExistsInMapping(mapping, value) {
for (var i = 0; i < mapping.length; i++) {
if (mapping[i][0] !== undefined && mapping[i][0] === value) {
return true;
}
}
return false;
}
function addValueToMapping(mapping, xValue, yValue) {
for (var i = 0; i < mapping.length; i++) {
if (mapping[i][0] === xValue) {
mapping[i][1] = mapping[i][1] + yValue;
}
}
}
});
#graph {
margin: 0 auto;
text-align: center;
width: 600px;
height: 400px;
}
.data-point-value {
position: absolute;
white-space: nowrap;
font-size: 11px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/flot/0.8.3/jquery.flot.js"></script>
<script src="https://rawgit.com/flot/flot/master/jquery.flot.stack.js"></script>
<div id="graph"></div>

Categories