How to swap out data via unload and load in C3.js - c3.js

I'm trying to swap out data sets in a C3.js graph.
The code I assumed would work based on the C3 docs looks like this:
chart.unload();
chart.load({
columns: [
['data3', 100, 90, 80, 70, 60, 50]
]
});
But this doesn't work. You'll notice that the graph rendered on the following Plunkr renders improperly, so I'm clearly doing something wrong: https://jsfiddle.net/7rfm9om9/
What is the idiomatic way to replace data in a C3 chart?

Ah, it appears that chart.unload() does some asynchronous work that, if you call chart.load() immediately after in a synchronous fashion, will break the graph.
I got this working by loading the new data in a function passed to chart.unload's done callback.
chart.unload({
done: function() {
chart.load({
columns: [
['data3', 100, 90, 80, 70, 60, 50]
]
});
}
});
Working fiddle: https://jsfiddle.net/1g5v1s24/1/

According to the c3 documentation, the way to do this is to use the unload param of the load function.
chart.load({
unload: true,
columns: ['data1', 100]
});
There are issues with rendering and animations otherwise when trying to use .unload() and then .load().
This note is included in the .unload() documentation:
http://c3js.org/reference.html#api-unload
Note: If you call [the] load API soon after/before unload, unload
param of load should be used. Otherwise chart will not be rendered
properly because of [cancelation] of animation.
done will be called after data loaded, but it's not after rendering.
It's because rendering will finish after some transition and there is
some time lag between loading and rendering.
According to the documentation for .load():
http://c3js.org/reference.html#api-load
If unload given, data will be unloaded before loading new data. If
true given, all of data will be unloaded. If target ids given as
String or Array, specified targets will be unloaded.
Note: unload should be used if some data needs to be unloaded
simultaneously. If you call unload API soon after/before load instead
of unload param, chart will not be rendered properly because of cancel
of animation.
Format would be along the lines of the following snippets:
All Data
chart.load({
unload: true,
columns: [
['data3', 100, 90, 80, 70, 60, 50]
]
});
Specified Targets
chart.load({
unload: ['data1', 'data2'],
columns: [
['data3', 100, 90, 80, 70, 60, 50]
]
});
JSFiddle:
https://jsfiddle.net/d8g015n2/

Related

Highstock dataGrouping not working with live data

I am currently working on a project for my company, where I need to plot highstock charts, which show energy-data of our main buildings.
Since it is live data, new datapoints come per Websocket every few-or-so seconds. However, the graph should only show one datapoint every hour. I wanted to clear this with the highstock dataGrouping, but it does not really work. It groups the points yes, but it still shows the „transmission“, the graph-line, between them. Thus making the whole graph completely irreadable.
In an other Version of the project, the graph only shows the latest datapoint of each group (as specified in the „approximate“ object in the chart options), but also does not start a new group after the chosen Interval runs through.
I've been sitting on this problem for about 3 days now and have not found any proper completely working solution yet.
Unfortunately, due company policy and due to hooks and components necessary, which are only used here in the company, I'm not able to give you a jsfilddle or similar, even though I'd really love to. What I can do is give you the config, mabye you find something wrong there?
const options = {
plotOptions: {
series: {
dataGrouping: {
anchor: 'end',
approximation: function (groupData: unknown[]) {
return groupData[groupData.length - 1];
},
enabled: true,
forced: true,
units: [['second', [15]]],
},
marker: {
enabled: false,
radius: 2.5,
},
pointInterval: minutesToMilliseconds(30),
pointStart: currentWeekTraversed?.[0]?.[0],
},
},
}
This would be the plotOptions.
If you need any more information, let me know. I'll see then, what and how I can send it to you.
Thank you for helping. ^^
This is example how dataGrouping works with live data,
try to recreate your case in addition or use another demo from official Highcharts React wrapper page.
rangeSelector: {
allButtonsEnabled: true,
buttons: [{
type: 'minute',
count: 15,
text: '15S',
preserveDataGrouping: true,
dataGrouping: {
forced: true,
units: [
['second', [15]]
]
}
}, {
type: 'hour',
count: 1,
text: '1M',
preserveDataGrouping: true,
dataGrouping: {
forced: true,
units: [
['minute', [1]]
]
}
}
},
Demo: https://jsfiddle.net/BlackLabel/sr3oLkvu/

JXA: Manipulating windows by their ID

Instead of
Application("Preview").windows[0].bounds = {"x": 1440, "y":25, "width":1440, "height": 2535}
I'd like to move the window but instead of using an index, I'd like to use the window's ID. I got the ID with
Application("Preview").windows[0].id();
But when I replace the index with the ID:
Application("Preview").windows.whose({id: 15596}).bounds = {"x": 1440, "y":25, "width":1440, "height": 2535}
I get
Error -1728: Can't get object.

AmChart not appearing in md-dialog

I have an AmChart that I want to appear in an md-dialog. It's passed a JSON dataProvider and yet nothing appears.
dialog.tmpl.html:
<md-dialog aria-label="Project Zone Chart">
<md-toolbar>
<div class="md-toolbar-tools">
<h2>Project Zone Chart</h2>
<span flex></span>
<md-button class="md-icon-button" ng-click="closeDialog()">
<md-icon aria-label="Close dialog">close</md-icon>
</md-button>
</div>
</md-toolbar>
<md-dialog-content>
<p><div id="projZoneChart" style="width: 100%; height: auto;"></div></p>
</md-dialog-content>
</md-dialog>
controller.js:
var projZoneChartOps = {
type: "serial",
valueAxes: [{
minorGridAlpha: 0.08,
minorGridEnabled: true,
position: "top",
gridAlpha: 0,
precision: 0
}],
startDuration: 1,
graphs: [{
type: "column",
fillAlphas: 1,
lineAlpha: 0,
valueField: "value",
colorField: "color",
lineAlpha: 0
}],
rotate: true,
categoryField: "metric",
categoryAxis: {
gridPosition: "start",
parseDates: false,
gridAlpha: 0
}
};
createChart($scope.chartdata, projZoneChartOps);
function createChart(chartData, chartOps){
$scope.projZoneChart = AmCharts.makeChart("projZoneChart", chartOps);
$scope.projZoneChart.dataProvider = chartData;
However nothing appears in the dialog at all. Is there a problem with my chartOps?
Note: the chartData variable is a JSON object with two fields, startOfWeek (supposed to be the x-axis) and metric (supposed to be the y-axis)
There are a few issues/comments:
1) Why aren't you assigning the data to the chartOps object before calling makeChart?
chartOps.dataProvider = chartData;
$scope.projZoneChart = AmCharts.makeChart("projZoneChart", chartOps);
This will actually make the chart start off with your data. The way you're doing it will require that you call validateData() on your chart object after manually setting the dataProvider, which is unnecessary overhead compared to including it directly in makeChart.
$scope.projZoneChart = AmCharts.makeChart("projZoneChart", chartOps);
$scope.projZoneChart.dataProvider = chartData;
$scope.projZoneChart.validateData(); //required if you're doing it this way but unneccessary overhead compared to simply including it inside of makeChart directly as you're essentially remaking the chart after you create it for the sake of rendering your data.
2) Make sure your *field properties match. startOfWeek isn't mentioned in your chart config at all, even though you're saying it's in your JSON data. Your valueField is set to "value" - you might want to set it to "startOfWeek" instead unless you're modifying your JSON object somewhere else.
3) Displaying charts inside a modal or other dynamic/hidden elements typically require that you call the chart object's invalidateSize method when the modal/tab/etc containing the chart is visible so that it will render correctly. You'll want to check for whatever event md-dialog offers to determine when it is visible before calling $scope.projZoneChart.invalidateSize().

How to set C3JS tooltip content

I have a situation similar to the example shown in http://c3js.org/samples/data_json.html My simple intention is to get the name of the row (i.e. 'www.site1.com') into the tooltip header. My problem: I cannot find it in the d-values.
Can anyone help?
You cannot find it in d-values, because it's not a value actually - it's a category.
Have a look at Category Axis example, maybe it helps you:
var chart = c3.generate({
data: {
columns: [
['data1', 30, 200, 100, 400, 150, 250, 50, 100, 250]
]
},
axis: {
x: {
type: 'category',
categories: ['cat1', 'cat2', 'cat3', 'cat4', 'cat5', 'cat6', 'cat7', 'cat8', 'cat9']
}
}
});
I solved it by using the d-value to address the right category of my JSON, or rather the array in my JSON. (Seemed more complicated since I load the data after I create the chart.)

Arrow overlaps connection

I use JsPlumb to connect various div. The options i use for connection is as follows,
var option = {
anchors: ["RightMiddle", "Bottom"],
connectorStyle: { strokeWidth: 0.5, stroke: "#243CA8"},
connector: ["Flowchart", { stub: [35, 70], midpoint: 0, cornerRadius: 1 }],
paintStyle: { stroke: "#243CA8", strokeWidth: 30},
overlays: [["Arrow", { location: 1, width: 65, length: 32 }]]
};
But the arrow overlaps on connector and output is not looking good.
I also tried setting overlay options 'location:-1' but still does not make any difference and also tried setting 'gap:10' for connector but it applies for both arrow overlay and connector by which the problem is still same but with space between element and connector. I cannot find anyother solution. Can anyone please suggest a solution. Thanks!
I was trying different options and accidentally came across the solution which is mentioned nowhere.
I just changed the 'location: 1' option of overlays to 'location: [0,1]' and it worked. Had no idea it was possible and it is mentioned nowhere. This is to help those who are struggling with the same issue!

Resources