Multiple C3.js charts automatically hidden, except the last one - javascript

I am trying to generate multiple c3 charts with the following code :
var datas=[[
["name", "position", "y", "bigRect", "myBars"],
["One 22", 2, 2, 2, 2],
["One 33", 3, 3, 2, 2],
["One 44", 4, 4, 2, 2]
],[
["name", "position", "y", "bigRect", "myBars"],
["Two 55", 5, 5, 2, 2],
["Two 66", 6, 6, 2, 2],
["Two 77", 7, 7, 2, 2]
],[
["name", "position", "y", "bigRect", "myBars"],
["Three 88", 8, 8, 2, 2],
["Three 99", 9, 9, 2, 2],
["Three 00", 0, 0, 2, 2]
]];
var iData = 0;
var charts = [];
for(iData in datas){
var d = datas[iData];
document.querySelector(".container").innerHTML += "<div id='chart"+iData+"'></div>";
var chartSelector = "#chart"+iData;
charts[iData] = c3.generate({
bindto: d3.select(chartSelector),
data: {
rows: d,
type: "scatter",
types: {
bigRect: "area",
myBars: "bar"
},
x: "position",
y: "y"
},
zoom: {
enabled: true
}
});
}
All the charts look empty except the last one that works perfectly. You can see what it looks like on this JSbin link.
On the hidden charts, all the SVGs are generated, but
the g SVG elements that contain the path drawing the dots and bars are set on opacity: 0, hiding all their contents.
the zoom and the tooltip do not work either
Do you know why c3 is disabling the first charts and how to enable them ?
My apologies for my poor English and thank you very much for your time.

You've got it working now, but I can also get it working by replacing one line like so:
d3.select(".container").append("div").attr("id", "chart"+iData);
//document.querySelector(".container").innerHTML += "<div id='chart"+iData+"'></div>";
It appears adding stuff to and then replacing .innerHtml has side effects for the existing contents, in your case the first charts you build
Is it possible to append to innerHTML without destroying descendants' event listeners?
This includes wiping out event handlers and 'unofficial' (for want of a better term) attributes like the __data__ field d3 populates and uses (it's undefined for the first 2 sets of bars as this code will reveal)
for(iData in datas){
console.log (d3.select("#chart"+iData+" .c3-bars").node().__data__);
}

I finally solved my problem by creating all the #chartX containers in another loop before that calling c3.
I assume it has something to do with the non-procedural execution order of JS but I'm still looking for a precise explanation of the phenomenon.
Here is the link to the corrected JSbin.

Related

How to set individual layout properties for feature points with mapbox-gl?

I have an array of feature points, and wan't to update some layout properties on each feature point, individually. How to I do this?
This is what I have so far.
const features = getVisibleFeatures();
// This updates all. Not what I wan't. Each feature should have different offset.
map.setLayoutProperty("ports", "text-offset", [5, 5]);
Each feature should have it's own text-offset, based on individual values. How do I achieve this?
Update
#steve-bennett offers some great suggestion in the comments below, but unfortunately they don't work with layout properties and the text-offset values.
It's important that a solution can work with this.
After a lot of searching, trial and error, I figured out I could do this:
map.setLayoutProperty("ports", "text-offset", {
property: "id",
type: "categorical",
stops: [
["0", [2, 1]],
["1", [2, 0]],
["2", [0, 2]],
],
default: [0, 0],
});
"0", "1" and "2" is matched against the properties.id field. So I can do something like this:
map.setLayoutProperty("layout-id", "text-offset", {
property: "id",
type: "categorical",
stops: nodes.map((node) => {
const x = node.vx;
const y = node.vy;
return [node.id, [x, y]];
}),
default: [0, 0],
});

Plotly JS: hover event does not contain points

I need the x-axis values, when hovering over my plotly chart.
According to the plotly docs (https://plot.ly/javascript/hover-events/) the hover event callback should contain the field "points" from which I should get the x value.
But if you look at this basic example you can see that the callback does not contain the field "points". Also other fields like "data" are undefined:
HTML
<div id="tester" style="width:600px;height:250px;"></div>
JS
$(document).ready(function(){
var tester = $('#tester');
tester.on('plotly_hover', function(data){
console.log(data)
});
Plotly.plot( 'tester', [{
x: [1, 2, 3, 4, 5],
y: [1, 2, 4, 8, 16] }], {
margin: { t: 0 } } );
})
See this fiddle in order to try it yourself:
https://jsfiddle.net/c1kt3r82/158/
What am I doing wrong?
plotly-basic does not seem to support hover events, use plotly-latest instead
when using jQuery to select the element, it returns a different object than doing it via document.getElementById
the hover events need to be defined after calling plot
$(document).ready(function() {
var tester = document.getElementById('tester');
Plotly.plot(tester, [{
x: [1, 2, 3, 4, 5],
y: [1, 2, 4, 8, 16]
}], {
margin: {
t: 0
}
});
tester.on('plotly_hover', function(data) {
console.log(data)
});
});
<div id="tester" style="width:600px;height:250px;"></div>
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
<script src="https://code.jquery.com/jquery-2.1.4.min.js"></script>

Using context variables as javascript parameters

I'm working on a project in Django, for part of it I'm trying to use Googles chart api, which uses a Javascript function to plot the graph. So what I'm trying to do is generate the graph data in my views.py and then pass the data through the context variables to the script. To test this I tried to do:
graphplot = [['Age', 'Weight'],[ 8, 12],[ 4, 5.5],[ 11, 14],[ 4, 5],[ 3, 3.5],[ 6.5, 7]]
context = {
"graphplot": graphplot,
}
in my views.py then I have:
var data = google.visualization.arrayToDataTable({{graphplot}});
in my template, however this doesn't seem to work.
When I do:
var data = google.visualization.arrayToDataTable([
['Age', 'Weight'],
[ 8, 12],
[ 4, 5.5],
[ 11, 14],
[ 4, 5],
[ 3, 3.5],
[ 6.5, 7]
]);
It does show the graph so I know it's not a problem with the JavaScript.
Any help would be appreciated
Try this, It should work.
var plot_data = {{graphplot}};
var data = google.visualization.arrayToDataTable(plot_data);

How to count and display the occurrence of a number in a json array of numbers

Please forgive me if this is a dumb or basic question but I have not been able to find a good solution. I have a json array of numbers:
[30, 37,34,56,76,87,54,34,2,4,2,5,5,3,4,3,4, 90]
I would like to count how many times each number occurs and use that data to produce a graph using d3js. How can I go about doing this? If there is a D3 method that does this, that would be great. But a javascript/jquery solution would do as well.
In plain Javascript:
var items = [30, 37, 34, 56, 76, 87, 54, 34, 2, 4, 2, 5, 5, 3, 4, 3, 4, 90],
histogram = items.reduce(function (r, a) {
r[a] = (r[a] || 0) + 1;
return r;
}, {});
document.write('<pre>' + JSON.stringify(histogram, 0, 4) + '</pre>');
For the graphing, check out c3. This can be easily done with something like this:
var chart = c3.generate({
data: {
x: 'x',
columns: [
numbers.unshift('x'),
occurrences.unshift('occurrences'),
],
type: 'bar'
} });
where numbers is an array of all distinct numbers and occurrences is an array of the numbers of time each occurs.
Demo

How to change calculation on nv3d when switching to stacked?

I'm using d3.js and nvd3.js to display some data from different datasets. One of the sets (A) contains the absolute number of orders, the other set (B) contains the number of orders from new customers, such that A >= B for every position. Example:
[{
key : 'orders',
values: [[1, 10], [2, 5], [3, 8], ...]
},{
key : 'orders by new customers',
values: [[1, 4], [2, 0], [3, 4], ...]
}]
I'd like to use a stacked multibar chart to display those series. In "Grouped" view, everything works nicely and I have both bars grouped beneath each other. However, when I switch to "Stacked" mode I was expecting, that the overall number does not change. It appeared that nv3d.js is then adding up both values and i get a new overall value.
Is there a way to change the calculation when switching to stacked mode? I was digging through the source code, but could not find a usable method to achieve this.
Thanks in advance!
If I understood your problem correctly, it would make more sense to restructure your data to make it conceptually match with bars being 'stacked' (which implies two values being added together), to something like this where:
orders = recurring orders + orders by new customers
[{
key : 'recurring orders',
values: [[0, 6], [0, 5], [0, 4], ...]
},{
key : 'orders by new customers',
values: [[1, 4], [2, 0], [3, 4], ...]
}]

Categories