I am working on AmCharts where I load data dynamically. Sometimes, there may be null data sent from the response. I need to handle null data in AmCharts4.
In this link I see the example for Amcharts3 handling null data
var chart = am4core.create("reason_for_failure", am4charts.PieChart);
// Add and configure Series
var pieSeries = chart.series.push(new am4charts.PieSeries());
pieSeries.dataFields.value = "litres";
pieSeries.dataFields.category = "country";
pieSeries.slices.template.stroke = am4core.color("#fff");
pieSeries.slices.template.strokeWidth = 2;
pieSeries.slices.template.strokeOpacity = 1;
// This creates initial animation
pieSeries.hiddenState.properties.opacity = 1;
pieSeries.hiddenState.properties.endAngle = -90;
pieSeries.hiddenState.properties.startAngle = -90;
chart.data = [];
It looks like the sample code he provided is more/less straight out of one of our Pie Chart demos, e.g. Pie Chart With Legend, so I mixed and matched that with the solution in the mirror GitHub issue (demo link on the bottom).
Again, the beforevalidated event is perfect for handling the case of the chart.data being assigned an empty array, e.g.
chart.events.on("beforevalidated", function(event) {
// check if there's data
console.log(event.target.data.length);
if (event.target.data.length == 0) {
// handle null data here
}
});
It would have to be the beforevalidated event, because if there's no data, beforedatavalidated does not trigger.
Demo:
https://codepen.io/team/amcharts/pen/88d11b5385a2669319c1a0fcdaa1e199/
Related
I'm stuck because I can not achive what I want with a dygraph widget created in R.
I have this time series.
#library(xts)
dts <- xts::xts(c(10508,8465,3175,3816,4532,2735,2534,9541,8253,9962),
order.by = seq(from = as.Date("2022-02-01"), to = as.Date("2022-11-01"), by = "month"))
I can plot it in a dygraph widget
#library(dygraph)
object <- dygraph((dts),
ylab = "") %>%
dyRangeSelector(height = 20, strokeColor = "") %>%
dyOptions(fillGraph = FALSE, stackedGraph = FALSE, drawGrid = FALSE, strokeWidth = 3) %>%
dyHighlight(highlightSeriesOpts = list(strokeWidth = 3,highlightCircleSize = 10))
and save it in a html page.
#library(htmlwidgets)
saveWidget(object, "temp.html", selfcontained = FALSE)
Now, I would like to take a screenshot of the plot. I know I can do it with
webshot::webshot(url = "images/temp.html", file = "screenshot.png")
No problem with that. But I should hover the mouse near the last data point before the screenshot, because I would like the chart to show the information of the last point in the legend.
I have tried with
webshot::webshot(url = "images/temp.html", file = "screenshot.png"),
eval = "this.mouse.click(1781, 109);")
I got the X,Y coordinates injecting the following code in the inspection frame of the page.
<html onclick="display(event)">
function display(event) {
let X = event.clientX;
let X = event.clientX;
alert = (X + Y);
}
But it does not seem to work.
I get
but I would like something like this
Actually, I would like to hover the last point regardless the time series.
I know it could be done with ggplot and save me a lot of steps but the dygraph is mandatory and I would like to get the static plot from it.
I know also that it is maybe more of a javascript or casperjs question. If so I wouldn't mind repeat the question in the appropriate forum.
In advance, thank you very much for your help.
I am trying to create a bubble chart using the JS HighChart in Angular2+. Whenever there are more than 50 data points (bubbles), the graph breaks. There are the correct number of bubbles in the correct positions (x,y plots) with all different colors but the sizes are all the same even though the z-values are all different. (I am outputing the z-values in a tooltip and the z-values are accurate)
This function is how I am passing in data to the high-chart configuration.
setSeries() {
this.objData = []
this.Data.forEach(element => {
var x= element['xVal'];
var y = element['yVal'];
var z = element['zVal'].toFixed(0);
var name = element['seriesName'].trim();
var newData =[{
x:x,
y:y,
z:+z,
}]
// SetSeriesData is how i am creating the obj to pass into series=[] in highchart configuration
if(i<50) //If I comment this condition, the graph breaks. Right now, the graph is working properly
this.setSeriesData(sumData, name, this.objData)
i++
})
this.options.series = this.objData;
this.generateChart();
}
This is my setSeriesData function.
setSeriesData(graphData: any, dataName: any, objData: any){
var obj = {};
obj['name'] = dataName;
obj['data'] = graphData;
obj['events'] = {click: function(e) {
//takes me to another link
}};
objData.push(obj)
}
In the above function, I configured the chart so that when you click the bubble, it takes you to another page. When the data points >50, this click functionality is not working either. In addition, the fillOpacity is not correct.
Just a few things to point out
1. I am using Angular 2+
2. The discovered issues are, fillOpacity, click, and size based on z-value.
3. It works perfectly when the data points are less than 50
How can I fix this?
I can't seem to find an easy way to add legend which has switchable functionality for items in a single graph for amcharts. I searched around and found a column chart which has switchable graphs (JSFiddle 1). I found switchable items legend but it doesn't resize properly (JSFiddle 2).
This is the closest I can find to adding legends from multiple items of single graph (CodePen 1). It is from amchart website itself but there is no switchable functionality. How can I add the switchable functionality here which allows column resizing (ie. 2 items will be shown with bigger column than 10 columns)? I tried this initially to just see if switch functionality can be added but it does not work:
AmCharts.addInitHandler(function(chart) {
//check if legend is enabled and custom generateFromData property
//is set before running
if (!chart.legend || !chart.legend.enabled || !chart.legend.generateFromData) {
return;
}
var categoryField = chart.categoryField;
var colorField = chart.graphs[0].lineColorField || chart.graphs[0].fillColorsField;
var legendData = chart.dataProvider.map(function(data) {
var markerData = {
"title": data[categoryField] + ": " + data[chart.graphs[0].valueField],
"color": data[colorField]
};
if (!markerData.color) {
markerData.color = chart.graphs[0].lineColor;
}
return markerData;
});
chart.legend.data = legendData;
// here is the code I add
chart.legend.switchable=true;
}
Update - The AmCharts knowledge base demo has been updated to include the modifications below.
In order to resize the chart outright, you have to actually modify the dataProvider and remove the element from the array and redraw the chart. You can use the legend's clickMarker to store the data item into the event dataItem object and retrieve it as needed through the hidden flag. Combining the fiddles from previous solutions together, I came up with this:
/*
Plugin to generate legend markers based on category
and fillColor/lineColor field from the chart data by using
the legend's custom data array. Also allows for toggling markers
and completely removing/adding columns from the chart
The plugin assumes there is only one graph object.
*/
AmCharts.addInitHandler(function(chart) {
//method to handle removing/adding columns when the marker is toggled
function handleCustomMarkerToggle(legendEvent) {
var dataProvider = legendEvent.chart.dataProvider;
var itemIndex; //store the location of the removed item
//Set a custom flag so that the dataUpdated event doesn't fire infinitely, in case you have
//a dataUpdated event of your own
legendEvent.chart.toggleLegend = true;
// The following toggles the markers on and off.
// The only way to "hide" a column and reserved space on the axis is to remove it
// completely from the dataProvider. You'll want to use the hidden flag as a means
// to store/retrieve the object as needed and then sort it back to its original location
// on the chart using the dataIdx property in the init handler
if (undefined !== legendEvent.dataItem.hidden && legendEvent.dataItem.hidden) {
legendEvent.dataItem.hidden = false;
dataProvider.push(legendEvent.dataItem.storedObj);
legendEvent.dataItem.storedObj = undefined;
//re-sort the array by dataIdx so it comes back in the right order.
dataProvider.sort(function(lhs, rhs) {
return lhs.dataIdx - rhs.dataIdx;
});
} else {
// toggle the marker off
legendEvent.dataItem.hidden = true;
//get the index of the data item from the data provider, using the
//dataIdx property.
for (var i = 0; i < dataProvider.length; ++i) {
if (dataProvider[i].dataIdx === legendEvent.dataItem.dataIdx) {
itemIndex = i;
break;
}
}
//store the object into the dataItem
legendEvent.dataItem.storedObj = dataProvider[itemIndex];
//remove it
dataProvider.splice(itemIndex, 1);
}
legendEvent.chart.validateData(); //redraw the chart
}
//check if legend is enabled and custom generateFromData property
//is set before running
if (!chart.legend || !chart.legend.enabled || !chart.legend.generateFromData) {
return;
}
var categoryField = chart.categoryField;
var colorField = chart.graphs[0].lineColorField || chart.graphs[0].fillColorsField;
var legendData = chart.dataProvider.map(function(data, idx) {
var markerData = {
"title": data[categoryField] + ": " + data[chart.graphs[0].valueField],
"color": data[colorField],
"dataIdx": idx
};
if (!markerData.color) {
markerData.color = chart.graphs[0].lineColor;
}
data.dataIdx = idx;
return markerData;
});
chart.legend.data = legendData;
//make the markers toggleable
chart.legend.switchable = true;
chart.legend.addListener("clickMarker", handleCustomMarkerToggle);
}, ["serial"]);
Demo
I am trying AmCharts for the first time and having trouble with one small thing. I created a graph using the following javascript:
dayGraph = new AmCharts.AmGraph();
dayGraph.valueField = "value";
dayGraph.type = "line";
dayGraph.balloonText = "<b>[[value]]</b>";
dayGraph.connect = false;
dayGraph.lineThickness = 2;
dayGraph.lineColor = "#8B0000";
dayGraph.fillColor = "#8B0000";
dayGraph.fillAlphas = 0.5;
chartCursor = new AmCharts.ChartCursor();
energyChart = new AmCharts.AmSerialChart();
energyChart.categoryField = "time";
/* energyChart.startDuration = 1;*/
energyChart.addGraph(dayGraph);
energyChart.categoryAxis.parseDates = true;
energyChart.categoryAxis.minPeriod = "mm";
energyChart.chartCursor = chartCursor;
energyChart.categoryAxis.equalSpacing = true;
It seems to work well, but I can't seem to find a way to remove the gap at the start of the graph (before the 00:00 value). The first data point is exactly at 00:00, so I would expect this point to sit on the vertical axis. Instead, there is a small gap. See the images below for how it currently is, and how I want it to look.
The current graph looks like this:
I want it to look like this:
Each serial chart already has categoryAxis property with a reference to CategoryAxis object. So you can just set it's startOnAxis property to true:
energyChart.categoryAxis.startOnAxis = true;
or, if you need to instantiate your own:
energyChart.categoryAxis = new AmCharts.CategoryAxis();
energyChart.categoryAxis.startOnAxis = true;
Whatever floats your boat.
Also, it's worth noting, that for date-based category axes, startOnAxis will work only if equalSpacing is set to true.
I am trying to get a radar chart from google api similar to below .I could get everything except the equally distributed 0,0.5,1,1.5,2,2.5,3
In my chart currently it takes min value out of the data given and max value ,and divisions between .its so if 6 is my max value and min value is 3. at very centre of circle it is 3 and then next cud be 3.4,and last extreme edge is 6.What change should i make in below code.to get a distribution ( say 0 to 6) evenly.
function drawVisualization() {
var options = {};
// Chart API chart type 'rs' is radar chart
options.cht = 'r';
// set the line colors
options.colors = ['#00FF00'];
// fill the area under the lines
//options.fill = true;
// create a grid for the chart
// options.chg = '25.0,25.0,4.0,4.0';
// options.chxl: '0:|1|2|3|4|5|6';
var arr = [["165q",1.3333333333333],["160q",6],["161q",6.6666666666667],["162q",7],["163q",8],["164q",5]];
//var pi = '\u03C0';
dataTable = google.visualization.arrayToDataTable(arr, true);
// Treat first row as data as well.
var chart = new google.visualization.ImageChart(document.getElementById('visualization'));
chart.draw(dataTable, options);
}
</script>
Try using the axis-range: chxr parameter with the custom axis labels: chxl parameter:
https://developers.google.com/chart/image/docs/chart_params#axis_range
https://developers.google.com/chart/image/docs/chart_params#axis_labels