Is there a way to display the total/sum of values on a stacked chart on the tooltip ?
We currently found a way by inserting total/sum into column labels but they appear also on the x axis labels which sometimes cause the legend to overlap. Ideally we would like the total to appear only on the tooltip. We also tried with tooltip templates but it seems not to handle this case of an additional total/sum value.
<script>
$(document).ready(function () {
let $chart_7790_000;
generateBB(
{
bindto: '#chart_7790_000',
title: {
show: false,
text: '',
position: 'top-left',
padding: {
top: 7,
right: 0,
bottom: 7,
left: 0
}
},
data: {
x: ' ',
columns: [
[
' ',
'1992 (Total: 29.9)',
'1997 (Total: 36.3)',
'2002 (Total: 37.1)',
'2007 (Total: 38.2)',
'2012 (Total: 43.6)',
'2017 (Total: 42.2)'
],
['Obésité', 5.6, 5, 7.4, 8.1, 9.8, 11.8],
['Surpoids', 24.3, 31.3, 29.7, 30.1, 33.8, 30.4]
],
type: 'bar',
colors: { Obésité: '#c53a3c', Surpoids: '#97252a' },
color: null,
axes: { Obésité: 'y', Surpoids: 'y' },
labels: null,
hide: [],
groups: [['Obésité', 'Surpoids']],
order: 'null'
},
axis: {
rotated: false,
x: {
type: 'category',
label: {
text: ' ',
position: 'outer-right'
}
},
y: {
label: {
text: 'En %',
position: 'outer-top'
},
max: 50,
min: null,
padding: {
top: 0,
bottom: 0
},
tick: {
format: function (d) {
return d.toFixed(2);
}
}
},
y2: {
show: false,
max: 0,
min: 0,
padding: {
top: 0,
bottom: 0
}
}
},
legend: {
show: true,
item: {}
},
tooltip: {
format: {
value: function (value, ratio, id, index) {
const dataFloat = parseFloat(value);
if (id == 'Année') {
return dataFloat.toFixed(2);
}
if (id == 'Obésité') {
return dataFloat.toFixed(1);
}
if (id == 'Surpoids') {
return dataFloat.toFixed(1);
}
return dataFloat;
}
},
contents: {
template:
'<div class="bb-tooltip-container"> <table class={=CLASS_TOOLTIP}> <tbody> <tr><th colspan="2">{=TITLE}</th></tr> {{ <tr class={=CLASS_TOOLTIP_NAME}> <td class="name"><span style="background-color:{=COLOR}"></span>{=NAME}</td> <td class="value">{=VALUE}</td> </tr> }} </tbody> </table></div>'
}
}
},
$chart_7790_000
);
});
</script>
You need to construct tooltip content by your own to customize tooltip content.
In this case, try by using tooltip.contents option.
Checkout the example, which the tooltip is showing total of current x Axis value.
const chart = bb.generate({
data: {
columns: [
["data1", 30, 200, 200, 400, 150, 250],
["data2", 130, 100, 100, 200, 150, 50]
],
type: "bar",
groups: [
[
"data1",
"data2"
]
]
},
tooltip: {
contents: function(d, defaultTitleFormat, defaultValueFormat, color) {
const {x} = d[0]
const total = d.reduce((a, c) => a.value + c.value);
let html = `<table class="bb-tooltip">
<tbody>
<tr><th colspan="2">${x}</th></tr>
<tr><td>total</td><td>${total}</td></tr>`;
d.forEach(v => {
html += `<tr class="bb-tooltip-name-${v.id}">
<td class="name"><span style="background-color:${color(v)}"></span>${v.id}</td>
<td class="value">${v.value}</td>
</tr>`
});
return `${html}</tbody></table>`;
}
},
bindto: "#chart"
});
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/billboard.js/dist/theme/datalab.min.css">
<script src="https://cdn.jsdelivr.net/npm/billboard.js/dist/billboard.pkgd.js"></script>
</head>
<body>
<div id="chart"></div>
</body>
</html>
Related
Im using the e-charts libary for creating a bar chart for my data .
like so :
option.series = [
{
name: 'buy',
type: 'bar',
stack: 'one',
data: Object.values(chartData?.data || {}).map(elem => -elem.buy?.total),
color: colors.bought,
label: {
show: true,
position: "bottom",
formatter: (value) => Math.round(Math.abs(value.data))
},
tooltip: {
formatter: (data) => Math.abs(data.value).toString()
},
// barWidth:this.data
},
{
name: 'sell',
type: 'bar',
stack: 'one',
data: Object.values(chartData?.data || {}).map(elem =>elem.sell?.total),
color: colors.sold,
label: {
show: true,
position: "top",
formatter: (value) => Math.round(Math.abs(value.data))
},
tooltip: {
formatter: (data) => Math.abs(data.value).toString()
},
},
{
name: 'profite',
type: 'bar',
stack: 'two',
barGap: '-100%',
z: 100,
data: Object.values(chartData?.data || {}).map(elem => elem.sell?.profit),
color: colors.profit,
label: {
show: true,
position: "insideTop",
textBorderWidth: -1,
offset: [0, -20],
formatter: (value) => Math.round(Math.abs(value.data))
},
tooltip: {
formatter: (data) => Math.abs(data.value).toString()
},
},
]
im trying to set a different width for each bar depending on the value of each bar .
on data property i get a list of numbers rendering .
When i try to add a barWidth property all i can do is change all of the bars in the same chrts like so for example:
barWidth: ${getBarWidth((Object.values(chartData?.data || {}).map((elem) => elem.sell?.amount)))}%
so i returne a different value of my data each time but it didnt changed each bar according to its value (either buy, sell and so on).
Thanks in adavance.
As you pointed out, barWidth sets the width of all the bars of a bar series. And I don't think there is a way to set the width of each bar in the same bar series.
What you should use instead is a custom series.
Custom series have a parameter called renderItem, where you write the render logic of the chart. It's where you'll be able to display custom shapes (custom sized bar in your case), using graphics.
Here is an example I found on their website, doing pretty much what you're looking for.
var container = document.getElementById('main');
var chart = echarts.init(container);
const colorList = [
'#4f81bd',
'#c0504d',
'#9bbb59',
'#604a7b',
'#948a54',
'#e46c0b'
];
const data = [
[10, 16, 3, 'A'],
[16, 18, 15, 'B'],
[18, 26, 12, 'C'],
[26, 32, 22, 'D'],
[32, 56, 7, 'E'],
[56, 62, 17, 'F']
].map(function (item, index) {
return {
value: item,
itemStyle: {
color: colorList[index]
}
};
});
chart.setOption({
title: {
text: 'Profit',
left: 'center'
},
tooltip: {},
xAxis: {
scale: true
},
yAxis: {},
series: [
{
type: 'custom',
renderItem: function (params, api) {
var yValue = api.value(2);
var start = api.coord([api.value(0), yValue]);
var size = api.size([api.value(1) - api.value(0), yValue]);
var style = api.style();
return {
type: 'rect',
shape: {
x: start[0],
y: start[1],
width: size[0],
height: size[1]
},
style: style
};
},
label: {
show: true,
position: 'top'
},
dimensions: ['from', 'to', 'profit'],
encode: {
x: [0, 1],
y: 2,
tooltip: [0, 1, 2],
itemName: 3
},
data: data
}
]
});
#main {
width: 600px;
height: 400px;
}
<html>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/echarts/5.3.2/echarts.min.js"></script>
<div id="main"></div>
</body>
</html>
chart
const data = {
labels: Array(coordinates.length).fill("l"),
datasets: buildDataset(),
options: {
animation: false,
scales: {
// ???????
},
legend: {
display: false
},
tooltips: {
callbacks: {
label: function(tooltipItem) {
return tooltipItem.yLabel;
}
}
},
maintainAspectRatio: false,
scales: {
myScale: {
position: 'left',
}
},
elements: {
point:{
radius: 0
}
}
}
}
return (
<Chart>
<Line
data={data}
width={50}
height={20}
options={data.options}>
</Line>
</Chart>
)
// ~~~~~
let obj = {
label: stops[0].miles == 0 ? index : index + 1,
data: points,
backgroundColor: colors[index],
tension: 0.4,
fill: true
}
These charts are built from an array of obj objects. The points variable that data refers is an array of object like: [{x: 0, y: 10257}, {x: 1, y: 10245}]
How do I get my line chart to display these different datasets side by side? I assume it has something to do with the scales parameter but wasn't able to find anything that worked in the docs.
Thanks!
For the object notation to work chart.js needs values to plot them against (not the index in the array) so you cant just provide an array containing only the value l.
You can either provide a labels array containing increasing numbers to which you match it or remove it and set your x scale to linear.
Labels example:
var options = {
type: 'line',
data: {
labels: [0, 1, 2, 3],
datasets: [{
label: '# of Votes',
data: [{
x: 0,
y: 4
}, {
x: 1,
y: 6
}, {
x: 2,
y: 2
}],
borderColor: 'pink'
},
{
label: '# of Points',
data: [{
x: 2,
y: 2
}, {
x: 3,
y: 3
}],
borderColor: 'blue'
}
]
},
options: {
scales: {}
}
}
var ctx = document.getElementById('chartJSContainer').getContext('2d');
new Chart(ctx, options);
<body>
<canvas id="chartJSContainer" width="600" height="400"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.5.0/chart.js"></script>
</body>
Linear example:
var options = {
type: 'line',
data: {
datasets: [{
label: '# of Votes',
data: [{
x: 0,
y: 4
}, {
x: 1,
y: 6
}, {
x: 2,
y: 2
}],
borderColor: 'pink'
},
{
label: '# of Points',
data: [{
x: 2,
y: 2
}, {
x: 3,
y: 3
}],
borderColor: 'blue'
}
]
},
options: {
scales: {
x: {
type: 'linear'
}
}
}
}
var ctx = document.getElementById('chartJSContainer').getContext('2d');
new Chart(ctx, options);
<body>
<canvas id="chartJSContainer" width="600" height="400"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.5.0/chart.js"></script>
</body>
I am using Angular-nvD3 in my Charts and I would like to change the background of this chart like the picture example. Can anyone help me please?
Here its the HTML code:
<div class="col-md-6">
<nvd3 options="optionsrigidez" data="datarigidez" class="with-3d-shadow with-transitions"></nvd3>
</div>
And here its the angular params:
1. Options:
$scope.optionsrigidez = {
chart: {
type: 'lineChart',
height: 250,
reduceXTicks: true, // if false a tick will show for every data point
margin: {
top: 20,
right: 20,
bottom: 40,
left: 55
},
x: function (d) { return d.x; },
y: function (d) { return d.y; },
useInteractiveGuideline: true,
dispatch: {
stateChange: function (e) { console.log("stateChange"); },
changeState: function (e) { console.log("changeState"); },
tooltipShow: function (e) { console.log("tooltipShow"); },
tooltipHide: function (e) { console.log("tooltipHide"); }
},
yDomain: [0.0, 100.0],
showLegend: false,
xAxis: {
axisLabel: 'Data da análise',
tickFormat: function (d) {
return daysOfReport[d];
},
rotateLabels: -1
},
yAxis: {
axisLabel: 'kV',
tickFormat: function (d) {
return d3.format('.01f')(d);
},
axisLabelDistance: -10
},
callback: function (chart) {
//console.log("!!! lineChart callback !!!");
}
},
title: {
enable: true,
text: 'Rigidez Dielétrica - Calota'
},
caption: {
enable: true,
html: '<b>Gráfico 3.</b> É uma medida da capacidade do óleo resistir à solicitação elétrica. Revela também a presença de impurezas polares como a água e outros oxigenados e sólidos (NBR 6869). Fonte: <a href="http://www.filtroil.ind.br/analise-de-oleo-isolante">Filtroil.<a/>',
css: {
'text-align': 'justify',
'margin': '10px 13px 0px 7px'
}
}
};
Data:
function rigidez_function() {
var rigidez = [];
for (var i = 0; i < $scope.RelatorioOleo_analisesFQ.length; i++) {
rigidez.push({ x: i, y: $scope.RelatorioOleo_analisesFQ[i].calota });
}
//Line chart data should be sent as an array of series objects.
return [
{
values: rigidez, //values - represents the array of {x,y} data points
key: 'Rigidez Dielétrica', //key - the name of the series.
color: '#5A5A5A', //color - optional: choose your own line color.
strokeWidth: 2,
//classed: 'dashed'
}
];
};
$scope.datarigidez = rigidez_function();
Probably a bit late, but yes you can!
You have to create a MultiChart and draw the colored zones as 'stacked areas'. I've created a plunk here: http://plnkr.co/hW3Anw
chart: {
type: 'multiChart',
height: 450,
margin : {
top: 30,
...
testdata[1].type = "area"
testdata[1].yAxis = 1
testdata[1].values = [{x: 0, y: -0.5}, {x: 55, y: -0.5}]
testdata[2].type = "area"
testdata[2].yAxis = 1
testdata[2].values = [{x: 0, y: -5}, {x: 55, y: -5}]
...
I need to plot users office timings (in and out time) of a day in a graph using Angular JS.
For example I have reached office at 10 and then gone out for lunch at 1, then again came at 2 and then gone out at 2:30 for some work and so on.....
So in graph, y axis should show time from 10 to 6 and it should plot time on graph, like 1st it should point at 10, then on 1, then on 2 and then on 2:30 and so on...
So my questions are:
1) Using which graph, this could be achieved in a single bar?
2) I am using stacked highchart, however since stacked chart add the points, I am sending difference between the two data, so first I am sending 10, another I want to point at 1, so I am sending 3 and so on..., however it fill the entire block with a color, like from 10-1 one color, 1-2 one color and so on..., what I need is, first it should point at 10 then at 1,then at 2...and so on it should not fill it with any color.
What I have achieved so far is :https://plnkr.co/edit/CgnFfTbJ3BkyjHzErQGk?p=preview
but what I want to achieve is something like this
Please help.
You could also check the code below:
<html>
<head>
<title>Highcharts Tutorial</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="https://code.highcharts.com/highcharts.js"></script>
</head>
<body>
<div id="container" style="width: 550px; height: 400px; margin: 0 auto"> </div>
<script language="JavaScript">
$(document).ready(function() {
var chart = {
type: 'column'
};
var title = {
text: 'Stacked column chart'
};
var xAxis = {
categories: ['Apples', 'Oranges', 'Pears', 'Grapes', 'Bananas']
};
var yAxis ={
min: 10,
max:18,
tickInterval:1,
title: {
text: 'Total fruit consumption'
},
stackLabels: {
enabled: false,
style: {
fontWeight: 'bold',
color: (Highcharts.theme && Highcharts.theme.textColor) || 'gray'
}
}
};
var legend = {
enabled:false
};
var tooltip = {
enabled:false
};
var plotOptions = {
column: {
stacking: 'normal',
dataLabels: {
enabled: false,
color: (Highcharts.theme && Highcharts.theme.dataLabelsColor) || 'white',
style: {
textShadow: '0 0 3px black'
}
}
}
};
var credits = {
enabled: false
};
var series= [
{ name: 'John',
data: [1]
},
{ name: 'John',
data: [0.5]
},
{ name: 'John',
data: [1]
},
{
name: 'Jane',
data: [3]
}, {
name: 'Joe',
data: [10]
}];
var json = {};
json.chart = chart;
json.title = title;
json.xAxis = xAxis;
json.yAxis = yAxis;
json.legend = legend;
json.tooltip = tooltip;
json.plotOptions = plotOptions;
json.credits = credits;
json.series = series;
$('#container').highcharts(json);
});
</script>
</body>
</html>
</script>
</body>
</html>
Here is a example using columnrange series.
Live example: https://jsfiddle.net/mzb3bpg2/
const options = {
chart: {
type: 'columnrange'
},
series: [{
name: 'Temperatures',
data: [{
borderWidth: 2,
borderColor: Highcharts.getOptions().colors[1],
color: 'rgba(0,0,0,0)',
x: 0,
low: 0,
high: 10
}, {
borderWidth: 2,
borderColor: Highcharts.getOptions().colors[1],
color: 'rgba(0,0,0,0)',
x: 0,
low: 10,
high: 16
}, {
borderWidth: 2,
borderColor: Highcharts.getOptions().colors[1],
color: 'rgba(0,0,0,0)',
x: 0,
low: 16,
high: 20
}]
}]
}
const chart = Highcharts.chart('container', options);
[EDIT]
More complete one:
Live example:
https://jsfiddle.net/fzv2jd3c/
I am creating an element with joint js and putting it inside a paper. The element has an ng-click directive in a pencil. However when I click on the element
The element
joint.shapes.flowie.Rect = joint.shapes.basic.Generic.extend(_.extend({}, joint.shapes.basic.PortsModelInterface, {
markup: '<g class="rotatable" ><g class="scalable"><rect class="body"/></g><text class="label"/><text region="" transform="translate(40,10)" ng-init="alert()" ng-click="loadStep(workflow.steps[this.stepName])" class="fa edit fa-pencil"></text><g class="inPorts"/><g class="outPorts"/></g>',
portMarkup: '<g class="port port<%= id %>"><circle class="port-body"/><text class="port-label"/></g>',
defaults: joint.util.deepSupplement({
type: 'devs.Model',
size: { width: 1, height: 1 },
inPorts: [],
outPorts: [],
attrs: {
'.': { magnet: false },
'.body': {
width: 150, height: 350,
stroke: '#000000'
},
'.port-body': {
r: 8,
magnet: true,
stroke: '#000000'
},
text: {
// 'pointer-events': 'none'
},
'.label': { text: 'Model', 'ref-x': .5, 'ref-y': 10, ref: '.body', 'text-anchor': 'middle', fill: '#000000' },
'.inPorts .port-label': { x:-15, dy: 4, 'text-anchor': 'end', fill: '#000000'},
".inPorts circle": {type:"input", magnet:"passive" },
'.outPorts .port-label':{ x: 15, dy: 4, fill: '#000000',type:"output" }
}
}, joint.shapes.basic.Generic.prototype.defaults),
getPortAttrs: function(portName, index, total, selector, type) {
var attrs = {};
var portClass = 'port' + index;
var portSelector = selector + '>.' + portClass;
var portLabelSelector = portSelector + '>.port-label';
var portBodySelector = portSelector + '>.port-body';
attrs[portLabelSelector] = { text: portName };
attrs[portBodySelector] = { port: { id: portName || _.uniqueId(type) , type: type } };
attrs[portSelector] = { ref: '.body', 'ref-y': (index + 0.5) * (1 / total) };
if (selector === '.outPorts') { attrs[portSelector]['ref-dx'] = 0; }
return attrs;
}
}));
There is a saveStep function triggered by saving a form. The form contains some metadata for each element
I then do the following to add the step to the graph
shape = new joint.shapes.flowie.Start({
position: { x: 10, y: 10 },
size: { width: 100, height: 30 },
attrs: { rect: { fill: 'blue' }, '.label': { text: step.stepName, fill: 'white' } },
stepName:name
});
shape.set('inPorts', []);
shape.set('outPorts', ['OUT']);
graph.addCells([shape])
I have heard of the compile directive but can't figure out a way to use it.