I'm creating some pie charts with Plotly.js but I can't figure out how to set the value format. If my number is 19.231, I get 19.2. I want 19.2310, with 4 digit precision. My data and layout follow here:
var data = [{
values: values,
labels: labels,
type: 'pie',
marker: {
colors: colors
},
textfont: {
family: 'Helvetica, sans-serif',
size: 48,
color: '#000'
}
}];
var layout = {
height: 1350,
width: 1500,
title: title,
titlefont: {
family: 'Helvetica, sans-serif',
size: 58,
color: '#000'
},
legend: {
x: 1.1,
y: 0.5,
size: 40,
font: {
family: 'Helvetica, sans-serif',
size: 48,
color: '#000'
}
}
};
As far as I know you cannot do that directly in Plotly but you could add text values with your desired precision and set textinfo to text.
var values = [Math.random(), Math.random(), Math.random()];
var sum = values.reduce(function(pv, cv) { return pv + cv; }, 0);
var digits = 4;
var rounded_values = [];
for (var i = 0; i < values.length; i += 1) {
rounded_values.push(Math.round(values[i]/sum * 100 * 10**digits) / 10**digits + '%');
}
var myPlot = document.getElementById('myPlot');
var data = [{
values: values,
type: 'pie',
text: rounded_values,
textinfo: 'text'
}];
Plotly.plot(myPlot, data);
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
<div id="myPlot"></div>
I saw the document find some rule
about Advanced Hovertemplate it said
data: [
{
type: "scatter",
mode: "markers",
x: x,
y: y,
text: t,
marker: { size: s, sizeref: 4000, sizemode: "area" },
transforms: [{ type: "groupby", groups: c }],
hovertemplate:
"<b>%{text}</b><br><br>" +
"%{yaxis.title.text}: %{y:$,.0f}<br>" +
"%{xaxis.title.text}: %{x:.0%}<br>" +
"Number Employed: %{marker.size:,}" +
"<extra></extra>"
}
],
you can change here %{y:$,.0f} 0f to 4f .
like this
hovertemplate: '%{y:$,.4f}',
Polt.ly JS document
Related
I've been using Chart.JS a little more than a week, and I've faced some problems, but right now I'm really stuck.
I need to create something similar to this, there are 1 product(blue) value and the orange one is an estimate of its value on the next month. So what I need to do is basically (((a — b) * 100) / a (or b I can't really remember)) and this as a label not actual data, and the result would be some percentage that would be used as a line on top of one product.
So far I got only this code, but it's not working like I need to.
{
type: "line",
label: monthsLabels?.mesBaseLabel,
data: [
productsValues?.receitaLiquidaBase[0],
productsValues?.receitaLiquidaOrcado[0],
],
fill: false,
},
{
type: "line",
label: monthsLabels?.mesOrcadoLabel,
data: [
productsValues?.receitaLiquidaBase[0],
productsValues?.receitaLiquidaOrcado[0],
],
// data: productsValues?.receitaLiquidaOrcado,
fill: false,
},
{
type: "bar",
label: monthsLabels?.mesBaseLabel,
data: productsValues?.receitaLiquidaBase,
// [
// productsValues?.receitaLiquidaBase[0],
// productsValues?.receitaLiquidaBase[1],
// ],
backgroundColor: ["rgba(42,62,176, 1)"],
borderWidth: 4,
datalabels: {
// anchor: "end",
// align: "top",
font: {
size: 10,
},
rotation: -90,
color: "white",
formatter: (value, context) => {
// console.log(value);
if (value !== 0) {
return value?.toFixed(2).replace(/\d(?=(\d{3})+\.)/g, "$&,");
} else {
return 0;
}
},
},
},
{
type: "bar",
label: monthsLabels?.mesOrcadoLabel,
data: productsValues?.receitaLiquidaOrcado,
backgroundColor: "orange",
borderWidth: 4,
datalabels: {
// anchor: "end",
// align: "top",
font: {
size: 10,
},
rotation: -90,
color: "black",
formatter: (value, context) => {
// console.log(value);
if (value !== 0) {
return value?.toFixed(2).replace(/\d(?=(\d{3})+\.)/g, "$&,");
} else {
return 0;
}
},
},
},
Objects on, data and label are an array of number coming from some fetching.
You are best off using a custom inline plugin for this:
var options = {
type: 'bar',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
backgroundColor: 'red'
},
{
label: '# of Points',
data: [7, 11, 5, 8, 3, 7],
backgroundColor: 'blue'
}
]
},
options: {
plugins: {
customValue: {
offset: 5,
dash: [5, 15]
}
}
},
plugins: [{
id: 'customValue',
afterDraw: (chart, args, opts) => {
const {
ctx,
data: {
datasets
},
_metasets
} = chart;
datasets[1].data.forEach((dp, i) => {
let increasePercent = dp * 100 / datasets[0].data[i] >= 100 ? Math.round((dp * 100 / datasets[0].data[i] - 100) * 100) / 100 : Math.round((100 - dp * 100 / datasets[0].data[i]) * 100) / 100 * -1;
let barValue = `${increasePercent}%`;
const lineHeight = ctx.measureText('M').width;
const offset = opts.offset || 0;
const dash = opts.dash || [];
ctx.textAlign = 'center';
ctx.fillText(barValue, _metasets[1].data[i].x, (_metasets[1].data[i].y - lineHeight * 1.5), _metasets[1].data[i].width);
if (_metasets[0].data[i].y >= _metasets[1].data[i].y) {
ctx.beginPath();
ctx.setLineDash(dash);
ctx.moveTo(_metasets[0].data[i].x, _metasets[0].data[i].y);
ctx.lineTo(_metasets[0].data[i].x, _metasets[1].data[i].y - offset);
ctx.lineTo(_metasets[1].data[i].x, _metasets[1].data[i].y - offset);
ctx.stroke();
} else {
ctx.beginPath();
ctx.setLineDash(dash);
ctx.moveTo(_metasets[0].data[i].x, _metasets[0].data[i].y - offset);
ctx.lineTo(_metasets[1].data[i].x, _metasets[0].data[i].y - offset);
ctx.lineTo(_metasets[1].data[i].x, _metasets[1].data[i].y - offset - lineHeight * 2);
ctx.stroke();
}
});
}
}]
}
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.4.1/chart.js"></script>
</body>
I want to design a chart like in the foto. The problem is, that I don't know how to put some labels in the bar! Also I don't want to show up the axes. And I also want to put the numbers like variables, because this chart is a result of a calculation of my calculator, is this possible?
<html>
<body>
<div id="chartContainer" style="height: 370px; width: 100;"></div>
</body>
<script>
//--------------------------------------CHART---------------
window.onload = function () {
var chart = new CanvasJS.Chart("chartContainer", {
animationEnabled: true,
title:{
text: "Das können Sie beim Widerspruch einer Lebensversicherung herausholen:",
fontFamily: "arial black",
fontColor: "#695A42"
},
axisX: {
display: false,
interval: 1,
intervalType: "year"
},
axisY:{
display: false,
valueFormatString:"$#0bn",
gridColor: "#B6B1A8",
tickColor: "#B6B1A8"
},
toolTip: {
shared: false
},
data: [{
type: "stackedColumn",
showInLegend: true,
color: "#134d59",
name: "Q1",
dataPoints: [
{ y: 6.75, x: new Date(2010,0) },
{ y: 8.57, x: new Date(2011,0) },
{ y: 10.64, x: new Date(2012,0) }
]
},
{
type: "stackedColumn",
showInLegend: true,
name: "Q2",
color: "#e53011",
dataPoints: [
// { y: 6.82, x: new Date(2010,0) },
{ y: 9.02, x: new Date(2011,0) },
// { y: 11.80, x: new Date(2012,0) }
]
},
{
type: "stackedColumn",
showInLegend: true,
name: "Q3",
color: "#92c13f",
dataPoints: [
// { y: 7.28, x: new Date(2010,0) },
// { y: 9.72, x: new Date(2011,0) },
{ y: 13.30, x: new Date(2012,0) }
]
}]
});
chart.render();
function toolTipContent(e) {
var str = "";
var total = 0;
var str2, str3;
for (var i = 0; i < e.entries.length; i++){
var str1 = "<span style= \"color:"+e.entries[i].dataSeries.color + "\"> "+e.entries[i].dataSeries.name+"</span>: $<strong>"+e.entries[i].dataPoint.y+"</strong>bn<br/>";
total = e.entries[i].dataPoint.y + total;
str = str.concat(str1);
}
str2 = "<span style = \"color:DodgerBlue;\"><strong>"+(e.entries[0].dataPoint.x).getFullYear()+"</strong></span><br/>";
total = Math.round(total * 100) / 100;
str3 = "<span style = \"color:Tomato\">Total:</span><strong> $"+total+"</strong>bn<br/>";
return (str2.concat(str)).concat(str3);
}
}
</script>
<script src="https://canvasjs.com/assets/script/canvasjs.min.js"></script>
</html>
https://jsfiddle.net/c74wtx5n/
For giving labels inside bars you need to append following in your data set.
indexLabel:"{y} $",
indexLabelPlacement: "inside",
For hiding axis and its labels add following in axis options
gridThickness: 0,
lineThickness: 0,
labelFormatter: function(e){
return "";
},
tickLength: 0,
I have modified your Jsfiddle, Here is the link to your solution
If you want to learn more about canvasJs customization go here.
For some reason no matter what we try the labels on our area chart series seem to have a mind of their own. Even though a short label looks like it could fit inside the area of the data, it puts it right on the end line, bleeding out of the area.
We suspect it might be due to having min and max dates that are beyond the series min and max, but these buffer zones are a requirement.
Is there an option to make labels be contained to their own series and not bleed off into whitespace?
Below is the example chart configuration and here is the JSFiddle: http://jsfiddle.net/sLqu34cn/
Highcharts.chart('container', {
chart: {
type: "area",
height: 200
},
legend: {
enabled: false
},
plotOptions: {
area: {
stacking: "percent",
pointPlacement: "on"
},
series: {
lineWidth: 0,
fillOpacity: 1,
marker: {
enabled: false
},
label: {
style: {
color: "white",
textOutline: "1px black"
}
}
}
},
series: [
{
name: "Two",
data: [[1532217600000, 1], [1532822400000, 0]],
color: "#41B6E6"
},
{
name: "Three",
data: [[1532217600000, 0], [1532822400000, 2]],
color: "#0072CE"
}
],
xAxis: {
tickWidth: 1,
title: {
enabled: false
},
labels: {
format: "{value: %b %e}"
},
max: 1533243166375,
min: 1530478366375,
type: "datetime"
},
yAxis: {
tickInterval: 20,
title: {
text: null
},
labels: {
format: "{value}%"
},
max: 100,
min: 0
},
tooltip: {}
});
Probably not the perfect solution, but you can create some customization to position the series labels. This is an example how to manually calculate the center of area in triangle shape:
Highcharts.wrap(Highcharts.Chart.prototype, 'drawSeriesLabels', function(proceed) {
proceed.apply(this, Array.prototype.slice.call(arguments, 1));
var chart = this,
plotTop = chart.plotTop,
plotLeft = chart.plotLeft,
series = chart.series,
height = chart.yAxis[0].height,
x1,
x2,
y1,
y2;
x1 = ((series[0].graphPath[1] + plotLeft) * 2 + series[0].graphPath[4] + plotLeft) / 3;
y1 = (height + plotTop + series[0].graphPath[2] + plotTop + series[0].graphPath[5] + plotTop) / 3;
x2 = (series[1].graphPath[1] + plotLeft + (series[1].graphPath[4] + plotLeft) * 2) / 3;
y2 = ((series[1].graphPath[2] + plotTop) * 2 + series[1].graphPath[5] + plotTop) / 3;
series[0].labelBySeries.attr({
x: x1,
y: y1,
align: 'center'
});
series[1].labelBySeries.attr({
x: x2,
y: y2,
align: 'center'
});
});
Live demo: http://jsfiddle.net/BlackLabel/34z8od5f/
Docs: https://www.highcharts.com/docs/extending-highcharts/extending-highcharts
i have the next problem with Highcharts. This is a new Highchart for an other site.
See here: https://imgur.com/a/VQQLU
The arrow show to -3 Megawatts but the value at the bottom shows another value. At the first pageload the values are identical, but there comes all 5 seconds new values. And they are not updated at the bottom.
Edit: The tolltip will be updated correctly.
My code:
$(function () {
$.getJSON('jsonlive.php', function(chartData) {
var ADatum; var Eheit; var AktL; var MinL; var MaxL; var chartValue; var i;
ADatum = chartData[0].AktDatum;
Eheit = chartData[0].Einheit;
AktL = chartData[0].AktuelleLeistung;
MinL = chartData[0].MinLeistung;
MaxL = chartData[0].MaxLeistung;
var tMin = (MinL*-1); var tMax = MaxL;
var ttt = new Array();
if (tMin < tMax) { chartValue = tMax; } else if (tMin > tMax) { chartValue = tMin; } // Ermitteln ob neg/pos Zahl die größere ist.
ttt[0] = (chartValue*-1); // Skala mit Zahlen beschriften
for (i = 1; i < chartValue; i++) { ttt[i] = (i*-1); }
var tz = ttt.length ;
for (i = 0; i < chartValue; i++) { ttt[(tz+i)] = i; }
ttt[ttt.length] = chartValue;
var gaugeOptions = {
chart:{ events: {
load: function () { setInterval(function () {
$.getJSON('jsonlive.php', function(chartData) {
ADatum = chartData[0].AktDatum;
AktL = chartData[0].AktuelleLeistung;
var point = $('#inhalt').highcharts().series[0].setData([AktL], true);
});}, 5000);}
}, type: 'gauge' },
title: null,
pane: {
center: ['50%', '85%'], size: '140%', startAngle: -90, endAngle: 90,
background: [{
backgroundColor: {
linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
stops: [[0, '#00fb00'],[1, '#003f00']]},
borderWidth: 2,
outerRadius: '109%',
innerRadius: '102%', shape: 'arc' }]
},
series: [{
data: [AktL],
dataLabels: { borderWidth: 0,align: 'center',x: 0,y: 110,
format: '<div style="text-align:center;font-size:24px;color:black">'+AktL+' ' +Eheit+'</span></div>'
}
}],
tooltip: {
formatter: function () { return 'Datum: <b>' + (new Date(ADatum).toLocaleString("de-DE", { timeZone: 'UTC' })) +
'</b> <br>Leistung <b>' + AktL + ' ' + Eheit + '</b>';}, enabled: true },
yAxis: {lineWidth: 10, minorTickInterval: null, tickPixelInterval: 100, tickWidth: 5, title: { y: -250 }, labels: { y: 2 }}
};
// Anzeige
$('#inhalt').highcharts(Highcharts.merge(gaugeOptions, {
yAxis: {
min: (chartValue*-1),max: chartValue,tickPositions: ttt,tickColor: '#666',minorTickColor: '#666',
plotBands: [{ // optionaler Bereich, zeigt von 0-1 grün, 1 bis hälfte maximum gelb, und hälfte max bis max rot
from: 0, to: -1, color: '#55BF3B' }, { // green
from: -1, to: ((chartValue*-1)/2), color: '#DDDF0D' }, { // yellow
from: ((chartValue*-1)/2),to: (chartValue*-1),color: '#DF5353' }, { // red
from: 0,to: 1,color: '#55BF3B' }, { // green
from: 1,to: (chartValue/2),color: '#DDDF0D' }, { // yellow
from: (chartValue/2),to: chartValue,color: '#DF5353' }],// red
title: { style: { color: 'black', fontWeight: 'bold', fontSize: '24px' }, text: 'Leistung in '+Eheit },
labels: { formatter: function () { return this.value; }}},
credits: { enabled: false } // Link auf highcharts rechts unten an/aus
}));
});
});
</script>
The problem here is that you use a hard-coded value (AktL) in your dataLabels.format. In your example format is just a string that's used all the time.
Use {point.y} to have the label updated on every setData():
series: [{
data: [val],
dataLabels: {
// format: val // WONT WORK
format: '{point.y}'
}
}],
Live demo: http://jsfiddle.net/BlackLabel/v28q5n09/
I am using Highcharts and it is working just amazing, i am stuck at a place where i want to plot a pie chart in which every pie slice (in a single pie chart) has a different radius.
Below is the image attached of the expexted pie chart.
You can skip making it a donout or designing it this specific. I just want to know how each pie slice can have different radius.
Each series in a pie chart can have their own size. So, I stacked a bunch of pie series calculating their begin and end angles. You'll have to do a little clean up to get the tooltips displaying the value instead of 100, but I think it's a workable solution.
Note: The following code makes a bad assumption that the data points add to 100. void fixes that assumption in his fiddle http://jsfiddle.net/58zfb8gy/1.
http://jsfiddle.net/58zfb8gy/
$(function() {
var data = [{
name: 'Thane',
y: 25,
color: 'red'
}, {
name: 'Nagpur',
y: 15,
color: 'blue'
}, {
name: 'Pune',
y: 30,
color: 'purple'
}, {
name: 'Mumbai',
y: 30,
color: 'green'
}];
var start = -90;
var series = [];
for (var i = 0; i < data.length; i++) {
var end = start + 360 * data[i].y / 100;
data[i].y = 100;
series.push({
type: 'pie',
size: 100 + 50 * i,
innerSize: 50,
startAngle: start,
endAngle: end,
data: [data[i]]
});
start = end;
};
$('#container').highcharts({
series: series
});
});
Another way I toyed with, that I didn't like as much, was having each series have invisible points:
series = [{
type: 'pie',
size: 100,
innerSize: 50,
data: [{y:25, color: 'red'}, {y:75, color:'rgba(0,0,0,0)'}]
},{
type: 'pie',
size: 150,
innerSize: 50,
data: [{y:25, color: 'rgba(0,0,0,0)'},{y:15, color: 'blue'}, {y:60, color:'rgba(0,0,0,0)'}]
}, ... ];
The variablepie series type, introduced in Highcharts 6.0.0, handles this with less code. In this series type you can specify a z-parameter for each data point to alter its z-size.
For example (JSFiddle, documentation):
Highcharts.chart('container', {
chart: {
type: 'variablepie'
},
title: {
text: 'Variable pie'
},
series: [{
minPointSize: 10,
innerSize: '20%',
zMin: 0,
name: 'countries',
data: [{
name: 'Pune',
y: 35,
z: 25
}, {
name: 'Mumbai',
y: 30,
z: 20
}, {
name: 'Nagpur',
y: 15,
z: 15
} , {
name: 'Thane',
y: 25,
z: 10
}]
}]
});
This requires including:
<script src="https://code.highcharts.com/modules/variable-pie.js"></script>