how to draw a d3 bubble chart for a local geojson file - d3.js

I want to plot a d3 bubble chart. By taking the example from d3
This link
i tried to get the bubble chart for my local file i.e myfile.geojson. The code which i tried is in the plunker link. I want to plot a bubble chart based on the value "Profit". Tried everything in the google and youtube but i didnt get the solution to my problem.
Plunker link
I am new to d3. If i do any mistakes in the code please suggest me to make them correct. Thanks In advance.

Your data is way different from flare.json so copying the recurse code will not make your data. Your dataset is very simple it does not need a recursion to flatten the dataset.
function classes(root) {
var classes = [];
function recurse(profit, node) {
if (node.profit) node.profit.forEach(function(child) { recurse(node.profit, child); });
else classes.push({packageName: type, className: node.profit, value: node.profit});
}
recurse(null, root);
return {features: classes};
}
This should have been:
function classes(root) {
var classes = root.features.map(function(f, i) {
//here i is the index
return {
value: f.properties.profit,
className: "Hello" + i,////just giving some dummy values
packageName: i//just giving some dummy values
}
});
return classes;
}
Now pass this data to the bubble layout like this:
var node = svg.selectAll(".node")
.data(bubble.nodes({
children: classes(root)
}).filter(function(d) {
return !d.children;
}))
.enter().append("g")
.attr("class", "node")
.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
});
EDIT
The bubble chart is based on the profit value:
The radius of the circle depends on the value you give here inside the classes function.
return {
value: f.properties.profit,
className: "Hello" + i,////just giving some dummy values
packageName: i//just giving some dummy values
}
Thus more the value or f.properties.profit the bigger will be the radius.
The radius will be relative to the diameter you setting here:
var bubble = d3.layout.pack()
.sort(null)
.size([diameter, diameter])
Read Domain range in d3 https://www.dashingd3js.com/d3js-scales
In place of className and packageName what should i give to get the bubble chart based on the profit value.
This i don't know what to answer I think your concept is not clear so is the naive question.
If you see the code packageName defines the color
.style("fill", function(d) {
return color(d.packageName);
});
and className defines the text to be displayed in the bubble
.text(function(d) {
return d.className;
});
Kindly see the code in fiddle its very simple to understand.
Working code here.

Related

d3 static Cubism chart - can't get data input right

I'm trying to make a static cubism chart like this http://bl.ocks.org/bae25/10797393
The csv file ("cubism_test.csv") looks something like this:
date,one,two,three,four,five
2018-06-01,132.54,18.44,68.36,0,56.63
2018-06-02,146.64,19.18,71.74,0,59.66
2018-06-03,160.77,117.98,75.15,0,62.71
2018-06-04,193.29,171.53,78.59,0,65.76
2018-06-05,275.92,78.64,82.05,0,68.82
<script>
// create context and horizon
var context = cubism.context()
.size(30)
.stop();
var horizon = context.horizon()
.extent([0,2]);
d3.csv("cubism_test.csv", function(data)
{
var format = d3.time.format("%Y-%m-%d");
data.forEach(function(d, i)
{
d.date = format.parse(d.date);
d.one= +d.one;
d.two= +d.two;
d.three= +d.three;
d.four= +d.four;
d.five= +d.five;
})
console.log(data);
// define metric accessor
context.metric(function(start,stop,step,callback)
{
var values = data;
console.log(values);
callback(null, values);
}, name);
d3.select("#graph").selectAll(".horizon")
.data(data)
.enter()
.append("div")
.attr("class", "horizon")
.call(horizon);
// set rule
d3.select("#body").append("div")
.attr("class", "rule")
.call(context.rule());
// set focus
context.on("focus", function(i) {
d3.selectAll(".value")
.style( "right", i == null ? null : context.size() - i + "px");
});
// set axis
var axis = context.axis()
d3.select("#graph").append("div").attr("class", "axis").append("g").call(axis);
});
</script>
Obviously this isn't working, but I don't know to fix it. I can't find a proper recourse on how to work with d3 data. The ones I've found are very basic and tell you how to use data to make simple circles, but not time series.
I don't know how to tell d3 to use the column headers as names or get it to use the values in the columns as the values for each cubism/horizon chart.
Your advice would be highly appreciated.

How can I use 2 range sliders at the same time?

I want to filter data in the table based on the age and height at the same time using 2 range sliders.
I have implemented 2 range sliders (Age and Height) using d3.slider.js and a dc.dataTable. I want to use these 2 range sliders at the same time, but it seems that they are not working properly.
Also, under the table, there is the text "49 selected out of 49 records". The numbers are not changing while using the sliders.
Code:
var dataTable = dc.dataTable("table#list");
var dispatch = d3.dispatch('load','filter');
d3.json('data.json',function(json){
dispatch.load(json)
});
dispatch.on('load',function(json) {
var formatNumber = d3.format( ",d");
var facts = crossfilter(json);
var dimensionAge = facts.dimension(function(d) {
return +d.age;
});
var accessorAge = function(d) {
return d.age;
};
var dimensionHeight = facts.dimension(function(d) {
return +d.height;
});
var accessorHeight = function(d) {
return d.height;
};
var range = d3.extent(json, accessorAge);
var range2 = d3.extent(json, accessorHeight);
var all = facts.groupAll();
d3.select("div#slider3")
.call(d3.slider().axis(true).min(range[0]).max(range[1]).value(range)
.on("slide", function(evt,value) {
dispatch.filter(value);
d3.select("#slider3textmin").text(Math.floor(value[0]));
d3.select("#slider3textmax").text(Math.floor(value[1]))
}))
d3.select("div#slider4")
.call(d3.slider().axis(true).min(range2[0]).max(range2[1]).value(range2)
.on("slide", function(evt,value) {
dispatch.filter(value);
d3.select("#slider4textmin").text(Math.floor(value[0]));
d3.select("#slider4textmax").text(Math.floor(value[1]))
}))
FieldNames = [
"",
"Age",
"Weight",
"Height",
"Eye Color",
"Hair Color",
"Race",
"Sex",
"Annual Income"
];
d3.select("tr#FieldNames").selectAll("th")
.data(FieldNames)
.enter()
.append("th")
.append("text")
.text(function(d){
return d;
});
dataTable
.dimension(dimensionAge)
.group(function(d) {
return d.sex;
})
.columns([
function(d) {return "";},
function(d) {return d.age;},
function(d) {return d.weight;},
function(d) {return d.height;},
function(d) {return d.eyeColor;},
function(d) {return d.hairColor;},
function(d) {return d.race;},
function(d) {return d.sex;},
function(d) {return formatNumber(d.annualIncome);}
]);
dispatch.on('filter',function(value){
dataTable.replaceFilter(dc.filters.RangedFilter(value[0], value[1]));
dataTable.redraw();
})
dc.dataCount(".dc-data-count")
.dimension(facts)
.group(all);
dc.renderAll();
});
Link to the website
Plunker
Original response on the dc.js users group.
Nice use of d3.slider.js - I haven't seen that used with dc.js before.
At a quick glance, I see two problems here. First, you're using one
dispatch for both sliders, so both sliders are filtering the age,
since that's the dimension of the table. You'd probably want to create
another dimension for filtering by height, and you don't really need
to attach that to a chart.
Second, instead of just redrawing the chart with dataTable.redraw(),
you probably want to call dataTable.redrawGroup() so that all charts
in its chart group get redrawn, including the dataCount.
Specifically:
you'll need two filter events in your dispatch
var dispatch = d3.dispatch('load','filterAge','filterHeight');
the age slider will call filterAge
dispatch.filterAge(value);
and the height slider will call filterHeight
dispatch.filterHeight(value);
the current filter event handler will now handle filterAge and it will call redrawGroup
dispatch.on('filterAge',function(value){
dataTable.replaceFilter(dc.filters.RangedFilter(value[0], value[1]));
dataTable.redrawGroup();
})
we add another filterHeight handler which directly filters dimensionHeight and also redraws the chart group
dispatch.on('filterHeight',function(value){
dimensionHeight.filter([value[0], value[1]]);
dataTable.redrawGroup();
})
Reset All will also have to clear dimensionHeight. (Since this dimension isn't used by any chart, dc.filterAll() won't find it.)
Reset All
Fork of your plunker.
this for reset all, the 49 selected out of 49 records already change correcly
replace this
Reset All
to this
Reset All
add this after dispatch on load
dispatch.on('load',function(json) {
//your code
})
function sololo(){
//table
dispatch.filterAge([0,100]);
dispatch.filterHeight([0,100]);
//text slider
d3.select("#slider4textmin").text(0)
d3.select("#slider4textmax").text(0)
d3.select("#slider3textmin").text(0);
d3.select("#slider3textmax").text(0)
//slider
d3.select('#slider3').select('#handle-one').style('left','0%')
d3.select('#slider3').select('#handle-two') .style('right','0%')
d3.select('#slider3').select('div').style('left','0%').style('right','0%')
d3.select('#slider4').select('#handle-one').style('left','0%')
d3.select('#slider4').select('#handle-two') .style('right','0%')
d3.select('#slider4').select('div').style('left','0%').style('right','0%')
}

D3 Transitionning data with sequences sunburst

Introducing
I'm using Sequences Sunburst of d3.js for visualization of data.
I want to add a transition between two datasets (triggered by a button). I would like each arc to animate to display the new data.
Something like this: (1)Sunburst_Exemple, but without changing the accessor.
Research
In the (1)Sunburst_Example, the value accessor is modified. But I want to change the data, not the function that defines how to reach the data.
So, I searched a way for redefining data into path.
I was inspired by (2)Sunburst_Exemple, using each() method to store old values and attrTween() for transitions. But nothing is changing and I have the following error message:
Maximum call stack size exceeded . Maybe caused by the fact I have a method and I'm not in a global scope.
(2) link : _http://ninjapixel.io/StackOverflow/doughnutTransition.html
Then I have tried (3)Zoomable_Sunburst example, but nothing it happens in my case... .
(3) link : _http://bl.ocks.org/mbostock/4348373
My Example
Here is my example : JSFIDDLE
Problem is :
colors are lost
transition is not happening
I think I don't understand how transitioning is really working, I could have missed something that could help me in this case.
Any help ?
-
Listener of button call click method that redefined nodes and path.
/*CHANGING DATA*/
function click(d){
d3.select("#container").selectAll("path").remove();
var nodes = partition.nodes(d)
.filter(function(d) {
return (d.dx > 0.005); // 0.005 radians = 0.29 degrees
}) ;
var path = vis.data([d]).selectAll("path")
.data(nodes)
.enter().append("svg:path")
.attr("display", function(d) { return d.depth ? null : "none"; })
.attr("d", arc)
.attr("fill-rule", "evenodd")
.style("fill", function(d) { return colors[d.name]; })
.style("opacity", 1)
.on("mouseover", mouseover)
.each(stash)
.transition()
.duration(750)
.attrTween("d", arcTween);
;
// Get total size of the tree = value of root node from partition.
totalSize = path.node().__data__.value;
}
_
// Stash the old values for transition.
function stash(d) {
d.x0 = d.x;
d.dx0 = d.dx;
}
// Interpolate the arcs in data space.
function arcTween(a) {
var i = d3.interpolate({x: a.x0, dx: a.dx0}, a);
return function(t) {
var b = i(t);
a.x0 = b.x;
a.dx0 = b.dx;
return arc(b);
};
}
Data Characteristics :
the root node is the same for the two datasets.
the structure is globally the same, only the values are changing.
Some fields disappear but we can add them with value equal to 0.

Multiple nvd3 graphs and select issue

I have multiple nvd3 pie charts in the same page. Now when I try to position them,individually using this code below
d3.select(".nv-pieWrap")
.attr("transform", "translate(0,-35)");
Only the first graph in the page gets repositioned. It is said in the nvd3 support document that the select keyword if used in multiple functions,only selects the first element in the page.
Now when I replace "select" with "selectAll",every graph is re-positioned.
I want to position them separately ie the "translate" coordinates would be different in different cases. How would I accomplish that?. Can anyone help?
d3.selectAll(".nv-pieWrap")
.attr("transform", "translate(0,-35)");
I've got two solutions of the problem.
One solution is you can specify 'transform' attribute not as a constant "translate(0,-35)" but a function instead. And within the function decide which coordinates you need based on the chart's index:
d3.selectAll(".nv-pieWrap")
.attr("transform", function(d, i) {
// i is a chart index
if (i === 0) {
return 'translate(0,-35)';
} else {
return 'translate(100,-35)';
}
});
Another solution is to wrap your code
d3.select(".nv-pieWrap")
.attr("transform", "translate(0,-35)");
into a transforming function which takes a node and transform as a parameter, e.g.
var transform = function(chart, transform) {
return
d3.select(chart)
.attr("transform", transform);
}
draw("#pieChart1", "translate(0,-35)");
draw("#pieChart2", "translate(100,-35)");

how to transition a multiseries line chart to a new dataset

I could really use some guidance setting up a transition on my multiseries line chart. As an example of what I need, I've started with this great multiseries line chart: http://bl.ocks.org/mbostock/3884955. To that code, I've added an update() function that's called once using setInterval(). I've also created a new data set called data2.csv which is similar to data.tsv but has different values.
The update function should change the data that the line chart is displaying. Forget about making a nice smooth transition, I can't even get the data to update in the chart view. When I try using the update function, it looks like the new data is loaded properly into the javascript variables, but the lines on the chart don't change at all.
I've seen variations on this question asked a few times but haven't found an answer yet. Can anyone help me figure out how to transition this multi-series line chart to a new dataset (also multiseries)?
function update() {
d3.csv("data2.csv", function(error, data) {
color.domain(d3.keys(data[0]).filter(function(key) { return key !== "date"; }));
// format the date
data.forEach(function(d) {
d.date = parseDate(d.date);
});
// rearrange the data, same as in the original example code
var cities2 = color.domain().map(function(name) {
return {
name: name,
values: data.map(function(d) {
return {date: d.date, temperature: +d[name]};
})
};
});
// update the .city g's to the new dataset
var city2 = svg.selectAll(".city")
.data(cities2);
// redraw the lines with the new data???
city2.selectAll("path")
.attr("d", function(d) { return line(d.values); });
clearInterval(transitionInterval);
});
}
UPDATE: NikhilS's answer contains the key to the solution in the comment trail.
You should make sure you are following the enter + update process as outlined by Mike Bostock in his stuff on the General Update Pattern. It looks like you haven't invoked any kind of d3 transition. You also haven't specified an enter or exit for the update function, which will cause problems if you have new data coming in and/or old data going out. Try changing this:
var city2 = svg.selectAll(".city")
.data(cities2);
city2.selectAll("path")
.attr("d", function(d) { return line(d.values); });
to the following:
var city2 = svg.selectAll('.city')
.data(cities2);
var cityGroups = city2.enter().append('g')
.attr('class', 'city');
cityGroups.append('path')
.attr('class', 'line');
d3.transition().selectAll('.line')
.attr('d', function(d) { return line(d.values); });
city2.exit().remove();
I made a basic data re-join and update demo a while back, which you can view here.
use d3 Transition, you can make some sort of animation.
If you want to select a sub-interval of the data to plot the graph, no need manipulation on the data, just use a d3 brush and clip the graph
For a multi-series line graph with most of the line graph elements, you could refer to this example: http://mpf.vis.ywng.cloudbees.net/

Resources