How to handle No Data in pie chart? - amcharts

I am currently working with pie charts in amCharts plugin. Sometimes I had to face no data in pie chart. In this scenario, amCharts loads no graph.
How can I handle no data in pie chart? Is there any method to display inactive pie chart (disabled pie chart or something)?

You can use AmCharts.addInitHandler function to set custom function to call before chart is drawn. You can use it to check if dataProvider is empty and make all kinds of modifications to the chart.
I.e.:
/**
* amCharts Plugin: handle empty pie chart
*/
AmCharts.addInitHandler(function(chart) {
// check if data is mepty
if (chart.dataProvider === undefined || chart.dataProvider.length === 0) {
// add some bogus data
var dp = {};
dp[chart.titleField] = "";
dp[chart.valueField] = 1;
chart.dataProvider.push(dp)
var dp = {};
dp[chart.titleField] = "";
dp[chart.valueField] = 1;
chart.dataProvider.push(dp)
var dp = {};
dp[chart.titleField] = "";
dp[chart.valueField] = 1;
chart.dataProvider.push(dp)
// disable slice labels and balloons
chart.labelsEnabled = false;
chart.balloonText = "";
// add label to let users know the chart is empty
chart.addLabel("50%", "50%", "The chart contains no data", "middle", 15);
// dim the whole chart
chart.alpha = 0.3;
}
}, ["pie"]);
var chart = AmCharts.makeChart("chartdiv", {
"type": "pie",
"theme": "light",
"dataProvider": [],
"valueField": "value",
"titleField": "title"
});
<script src="http://www.amcharts.com/lib/3/amcharts.js"></script>
<script src="http://www.amcharts.com/lib/3/pie.js"></script>
<script src="http://www.amcharts.com/lib/3/themes/light.js"></script>
<div id="chartdiv" style="width: 100%; height: 400px;"></div>

Related

Amcharts V4 plating a chart in percent rather than absolute using valueYShow

I'm trying to create a chart using AMCharts V4. The values are given in absolute, and I want to have the chart in percentages: values, y-axis, etc.
The docs are here: https://www.amcharts.com/docs/v4/tutorials/plotting-series-from-calculated-values/
However, I'm having some trouble. Pls consider the following codepen forked from the official AMCharts documentation:
https://codepen.io/otmezger/pen/RwVzmjv
As the docs suggest, I have valueAxis.calculateTotals = true; enabled.
The line series.dataFields.valueYShow = "totalPercent"; or series.dataFields.valueYShow = "percent"; renders the graph useless.
only if I disable them, the graph will show in absolute numbers.
what am I missing? how can I make series.dataFields.valueYShow = "percent"; work?
If you want to use percent values in the series, you need to set calculatePercent to true on the series as explained here
series.calculatePercent = true;
series.dataFields.valueYShow = "percent";
series.tooltipText = "{dateX}: [b]{valueY.percent}[/]%";
Demo:
// Create chart instance
var chart = am4core.create("chartdiv", am4charts.XYChart);
// Add data
chart.data = [{
"date": new Date(2018, 0, 1),
"value": 10
}, {
"date": new Date(2018, 0, 2),
"value": 15
}, {
"date": new Date(2018, 0, 3),
"value": 2
}];
// Create axes
var dateAxis = chart.xAxes.push(new am4charts.DateAxis());
dateAxis.renderer.grid.template.location = 0;
dateAxis.renderer.minGridDistance = 30;
var valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
valueAxis.calculateTotals = true;
valueAxis.renderer.labels.template.adapter.add("text", function(text) {
return text + "%";
});
// Create series
var series = chart.series.push(new am4charts.LineSeries());
series.dataFields.valueY = "value";
series.dataFields.dateX = "date";
series.calculatePercent = true;
series.dataFields.valueYShow = "percent";
series.tooltipText = "{dateX}: [b]{valueY.percent}[/]%";
series.strokeWidth = 2;
var bullet = series.bullets.push(new am4charts.CircleBullet());
bullet.circle.stroke = am4core.color("#fff");
bullet.circle.strokeWidth = 2;
// Finish up setting chart up
chart.cursor = new am4charts.XYCursor();
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
}
#chartdiv {
width: 100%;
height: 250px;
}
<script src="//www.amcharts.com/lib/4/core.js"></script>
<script src="//www.amcharts.com/lib/4/charts.js"></script>
<div id="chartdiv"></div>

Drawing target line (plotLine) on Kendo Angular Pie Chart

Is it possible to draw a target line on pie chart?
For example, goal is 90% but installed is 70% and not-installed is 30%. I need to show the goal as dotted line as shown in the image below.
You can use the render event of the grid to draw the dotted line on the chart. I would use the visual property of the series to get the center point and radius of the pie, then in the render, draw a path from the pie center at the correct angle.
WORKING DEMO
var center;
var radius;
$("#chart").kendoChart({
theme: "Bootstrap",
legend: {visible: true,position: "bottom"},
seriesDefaults: { labels: {visible: false, }},
series: [{
type: "pie",
data: [{
category: "Installed",value: 45,color: "#52B84D"
}, {
category: "Not Installed",value: 25,color: "#E64F49"
}],
visual: function(e) {
//use this function to get the center and radius
//for use in the render function
center = e.center;
radius = e.radius;
// return the default visual element
return e.createVisual();
},
}],
render: function(e){
var draw = kendo.drawing;
var geom = kendo.geometry;
var chart = e.sender;
//angle is 90% of 270 because 0 is horizontal
var cornerRad = (0.9 * 270) * Math.PI / 180;
var nx = Math.cos(cornerRad)*radius + center.x;
var ny = Math.sin(cornerRad)*radius + center.y;
// The center and radius are populated by now.
var path = new draw.Path({
stroke: {
color: "#000",
width: 2,
dashType: "dash"
}
});
path.moveTo(center).lineTo(nx, ny, 0).close();
// Draw it on the Chart drawing surface
chart.surface.draw(path);
}
});

Chart.js: How to get bar chart labels clickable?

I use chart.js 2.8.0 to create mainly pie and bar charts. The clickable legend on pie charts is really useful, filtering out unwanted data from the result.
When creating a chart there are two kinds of labels:
* An array of labels on chart level, label 1 corresponding to item 1 in each dataset.
* Dataset labels, one for each dataset.
A pie chart as standard get the chart label array turned into a legend with clickable labels, click on a label and that item is filtered out from the chart.
A bar chart, on the other hand, gets the labels shown below the bar but not clickable. Instead the legend here is made out of the dataset label. If you have more than one dataset, a whole dataset is filtered out if you click on that label.
Since I sometimes have several datasets I can not use the "trick" that consists of putting data item into a separate dataset (that was otherwise the closest to what I wanted that I found in my search, the "extra" clickable legend that would create would work as well). The situation is also that the end user should get a drop-down (or similar) so he, from the same data, can select chart type. So the soultion need to work both for pie and bar charts. the same data and (standard) code creates the two shown charts (except for the colors).
The question is now, as stated in the title: Is it possible to get clickable labels for a bar chart with the same filtering functionality as when the chart is of pie type?
I understand that it isn't doable by just setting some options, it would probably have to be done by creating a plugin, but is it at all doable? if so, any pointers for help?
If not clickable labels, maybe make the bars themselves clickable (with the same result)...?
With a slight change to the fiddle given by https://stackoverflow.com/users/3963330/tob%c3%adas in his answer here: Click events on Pie Charts in Chart.js I get a fiddle that also can handle multiple datasets, and on my second try I managed to hide a segment when I clicked on it. And then I relized that if it wasn't a pie chart there would be no clickable legend to use for unhiding that element - so that's not a solution for my bar charts.
Tried combining a couple of SO questions/answers (generating labels by #GRUNT : Bar labels in Legend) but can't get legend labels for bar charts to filter out segments instead of datasets.
Fiddle: https://jsfiddle.net/tommypeters/24ra6egy/9/
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.6.0/Chart.min.js"></script>
<canvas id="canvas"></canvas>
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext('2d');
var myNewChart = new Chart(ctx, {
type: 'bar',
data: {
datasets: [{
data: [300, 50, 100],
backgroundColor: [
"#F7464A",
"#46BFBD",
"#FDB45C"
]
},
{
data: [400, 60, 101],
backgroundColor: [
"#F7464A",
"#46BFBD",
"#FDB45C"
]
}
],
labels: [
"Red",
"Green",
"Yellow"
]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
},
legend: {
labels: {
generateLabels: function(chart) {
var labels = chart.data.labels;
var dataset = chart.data.datasets[0];
var legend = labels.map(function(label, index) {
return {
datasetIndex: 0,
fillStyle: dataset.backgroundColor && dataset.backgroundColor[index],
strokeStyle: dataset.borderColor && dataset.borderColor[index],
lineWidth: dataset.borderWidth,
text: label
}
});
return legend;
}
}
}
}
});
canvas.onclick = function(evt) {
var activePoints = myNewChart.getElementsAtEvent(evt);
if (activePoints[0]) {
var chartData = activePoints[0]['_chart'].config.data;
var idx = activePoints[0]['_index'];
var dIndex = myNewChart.getDatasetAtEvent(evt)[0]._datasetIndex;
var label = chartData.labels[idx];
var value = chartData.datasets[dIndex].data[idx];
// Doesn't hide a slice but a whole dataset...
// var meta = myNewChart.getDatasetMeta(dIndex);
// meta.hidden = meta.hidden === null ? !myNewChart.data.datasets[dIndex].hidden : null;
// myNewChart.update();
var i, ilen, meta;
for (i = 0, ilen = (myNewChart.data.datasets || []).length; i < ilen; ++i) {
meta = myNewChart.getDatasetMeta(i);
if (meta.data[idx]) {
meta.data[idx].hidden = !meta.data[idx].hidden;
}
}
myNewChart.update();
var url = "http://example.com/?label=" + label + "&value=" + value;
console.log(url);
alert(url);
}
}

amchart indicator loading not stopping even chart is appear

im try using Amchart plugin into my system. Chart successful appear when i run basic code for chart. Then im try to use a custom for loading indicator. But the problem is indicator for loading not stopping even chart is appear.
Below is the JS script
am4core.useTheme(am4themes_animated);
// Create chart instance
var chart = am4core.create("chartdiv", am4charts.XYChart);
// Add data
chart.data = [{
"category": "Research",
"value": 450
}, {
"category": "Marketing",
"value": 1200
}, {
"category": "Distribution",
"value": 1850
}];
// Create axes
var categoryAxis = chart.xAxes.push(new am4charts.CategoryAxis());
categoryAxis.dataFields.category = "category";
categoryAxis.renderer.grid.template.location = 0;
//categoryAxis.renderer.minGridDistance = 30;
var valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
// Create series
var series = chart.series.push(new am4charts.ColumnSeries());
series.dataFields.valueY = "value";
series.dataFields.categoryX = "category";
var indicator;
var indicatorInterval;
function showIndicator() {
if (!indicator) {
indicator = chart.tooltipContainer.createChild(am4core.Container);
indicator.background.fill = am4core.color("#fff");
indicator.width = am4core.percent(100);
indicator.height = am4core.percent(100);
var indicatorLabel = indicator.createChild(am4core.Label);
indicatorLabel.text = "Loading stuff...";
indicatorLabel.align = "center";
indicatorLabel.valign = "middle";
indicatorLabel.dy = 50;
var hourglass = indicator.createChild(am4core.Image);
hourglass.href = "https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-160/hourglass.svg";
hourglass.align = "center";
hourglass.valign = "middle";
hourglass.horizontalCenter = "middle";
hourglass.verticalCenter = "middle";
hourglass.scale = 0.7;
}
indicator.hide(0);
indicator.show();
clearInterval(indicatorInterval);
indicatorInterval = setInterval(function() {
hourglass.animate([{
from: 0,
to: 360,
property: "rotation"
}], 2000);
}, 3000);
}
function hideIndicator() {
indicator.hide();
clearInterval(indicatorInterval);
}
showIndicator();
Below is the html code
<script src="//www.amcharts.com/lib/4/core.js"></script>
<script src="//www.amcharts.com/lib/4/charts.js"></script>
<script src="//www.amcharts.com/lib/4/themes/animated.js"></script>
<div id="chartdiv"></div>
im already try a few method, but no lucky for me. Any suggestion
On amchart4 documentation (https://www.amcharts.com/docs/v4/tutorials/custom-loading-indicator/), it only shows how you can create a custom loading indicator. It doesn't hook up hideIndicator() event when the chart is finished rendering.
There is a Ready event you can use now (https://github.com/amcharts/amcharts4/issues/436#issuecomment-441370242). You can just simply hook up hideIndicator() function to the Ready event:
...
chart.events.on("ready", function(ev){
hideIndicator();
});
...
fiddle: https://jsfiddle.net/davidliang2008/akpe5f4b/1/

NVD3 - Show all tick values

My chart needs to have tick values in multiples of 3. For example, if I have 5 data points, my x-axis should show (3, 6, 9, 12, 15). How do I get nvd3 to display all tick numbers? I pasted my code below for reference
var chart = nv.models.lineChart()
.options({
margin: {left: 100, bottom: 100},
x: function(d,i) { return i*3},
showXAxis: true,
showYAxis: true,
showLegend: true,
reduceXTicks: false,
showMaxMin: false,
//values: $scope.data.values.map( function(d,i) { return i*3; }),
useInteractiveGuideline: true,
transitionDuration: 2500,
showControls : true
})
;
chart.xAxis //Chart x-axis settings
.axisLabel('Ager')
.orient('bottom')
//.tickValues( function(d,i) { return i*3;})
.tickFormat(d3.format(',r'));
chart.yAxis //Chart y-axis settings
.axisLabel('Voltage (v)')
.tickFormat(d3.format('.02f')); nv.utils.windowResize(chart.update);
I've tried everything I can think of and read online to get nvd3 show all ticks in multiples of 3. Please help me out of this tricky situation.
Thanks in advance!
You could have read the d3 docs and see that .tickValues does not accept a function.
Construct the array of tick values based on the domain of the x-axis. Because the domain is not yet set you have to construct it yourself based on the data.
Using the SinCos example from the nvd3 site
var myData = sinAndCos();
var xExtent = d3.extent(myData[0].values, d=>d.x);
xExtent = [Math.floor(xExtent[0]), Math.ceil(xExtent[1])+1];
var xTicks = d3.range(xExtent[0], xExtent[1]).filter(n => n%3===0);
chart.xAxis
.axisLabel('Time (ms)')
.tickValues(xTicks)
.tickFormat(d3.format(',r'));
Complete example. It will not run directly from the browser (will not load nvd3 inside an iframe(??)). Copy it to a local file and run it from there.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<link href="https://nvd3.org/assets/css/nv.d3.css" rel="stylesheet"/>
<script src="https://nvd3.org/assets/lib/d3.v3.js"></script>
<script src="https://nvd3.org/assets/js/nv.d3.js"></script>
</head>
<body>
<div id="chart">
<svg style="width:800px;height:500px;"></svg>
</div>
<script>
/*These lines are all chart setup. Pick and choose which chart features you want to utilize. */
nv.addGraph(function() {
var chart = nv.models.lineChart()
.margin({left: 100}) //Adjust chart margins to give the x-axis some breathing room.
.useInteractiveGuideline(true) //We want nice looking tooltips and a guideline!
.transitionDuration(350) //how fast do you want the lines to transition?
.showLegend(true) //Show the legend, allowing users to turn on/off line series.
.showYAxis(true) //Show the y-axis
.showXAxis(true) //Show the x-axis
;
var myData = sinAndCos();
var xExtent = d3.extent(myData[0].values, d=>d.x);
xExtent = [Math.floor(xExtent[0]), Math.ceil(xExtent[1])+1];
var xTicks = d3.range(xExtent[0], xExtent[1]).filter(n => n%3===0);
chart.xAxis //Chart x-axis settings
.axisLabel('Time (ms)')
.tickValues(xTicks)
.tickFormat(d3.format(',r'));
chart.yAxis //Chart y-axis settings
.axisLabel('Voltage (v)')
.tickFormat(d3.format('.02f'));
d3.select('#chart svg') //Select the <svg> element you want to render the chart in.
.datum(myData) //Populate the <svg> element with chart data...
.call(chart); //Finally, render the chart!
//Update the chart when window resizes.
nv.utils.windowResize(function() { chart.update() });
return chart;
});
/**************************************
* Simple test data generator
*/
function sinAndCos() {
var sin = [],sin2 = [],
cos = [];
//Data is represented as an array of {x,y} pairs.
for (var i = 0; i < 100; i++) {
sin.push({x: i, y: Math.sin(i/10)});
sin2.push({x: i, y: Math.sin(i/10) *0.25 + 0.5});
cos.push({x: i, y: .5 * Math.cos(i/10)});
}
//Line chart data should be sent as an array of series objects.
return [
{
values: sin, //values - represents the array of {x,y} data points
key: 'Sine Wave', //key - the name of the series.
color: '#ff7f0e' //color - optional: choose your own line color.
},
{
values: cos,
key: 'Cosine Wave',
color: '#2ca02c'
},
{
values: sin2,
key: 'Another sine wave',
color: '#7777ff',
area: true //area - set to true if you want this line to turn into a filled area chart.
}
];
}
</script>
</body>
</html>

Resources