d3 pie chart problems with exiting entering - javascript

After making several bar charts using enter, update, exit method in D3js, I wanted to try the same with a pie chart. I thought I applied selections correctly, but the pie chart won't update with the new data in JSON. I looked for similar examples online, but couldn't find one which involved an .on("click" method. I want users to compare the lifespans of humans and animals using a donut chart. I'm trying to implement the search tool through the database of animals right now.
here's what a data object looks like for the query Goat:
[{"Animal":"Male","Life_Span":73},{"Animal":"Goat","Life_Span":10}]
I'm having trouble with this code in particular:
var pie = d3.pie()
.sort(null)
.value(function(d) { return d.Life_Span; });
//code for accessing data, etc
//enter remove selections
var path = svg.selectAll("path")
.data(pie(newdata))
var enterdata =
path.enter().append("path")
.attr("d",arc)
path.exit().remove()
enterdata.exit().remove()
I posted the full code on Plunkr here: http://plnkr.co/edit/3QSAPxQpju63tIXRd9p7?p=preview
A few weeks into learning d3js, I'm still struggling with enter,update exit selections even after reading many tutorials on the subject. I would really appreciate any help. Thanks

In D3 v4.x, you need to merge the update and enter selections:
var enterdata = path.enter()
.append("path")
.merge(path)
.attr("d",arc)
You don't need an exit selection because your data array has always 2 objects: except for the first time, your enter selection is always 0, and your exit selection is always 0.
I took the liberty of colouring the paths in different colours, according to their indices:
.attr("fill", (d,i) => i ? "teal" : "brown");
Here is your updated plunker: http://plnkr.co/edit/l6OzmxVfid9Cj7iv7IMg?p=preview
PS: You have some problems in your code, which I'll not change (here I'm only answering your main question), but I reckon you should think about them:
Don't mix jQuery and D3. You can do everything here without jQuery
Don't load all your CSV every time the user chooses an animal. It doesn't make sense. Instead of that, put the click function inside the d3.csv function (that way, you load the CSV only once).

Related

Problems adding interactivity in d3.js Maps [dropdown menu]

I want to produce maps as an output for quantitative analysis.
I Have multiple variables to add to my map, and, I dont want to have n-output, in this case, n-maps. You can have a look of the simplified dataframe (colomns are years, but it could also be a set of different variables) :
Simple data frame
It seems to me d3.js was a good idea, because it can display 1 map with a dropdown menu, and the user can select the variable.
I have produced a map with d3.js before, and I use it as template. I have made it quiet basic and simple (really small dataset, etc), you can found it here in this repo GitHub :
https://github.com/Mathiaslauber/Without_interactivity
Here is the Github repo with my first try of implementing interactivity
https://github.com/Mathiaslauber/Interactivity_first_try
Or if you prefer, I have just made a FiddleJS to make things easier : Fiddle JS Interacivity first try
It was part of a bigger project, you can have a look if you want. GithubPages
So far, I have made deseperates modifications that remain unsucessful, because examples are usually very diffrent in many aspects, so hardly reproductible for me. I'm quiet new AND bad with function implemantation in JavaScript.
The two following links are examples that did not seem that complicated and inspired me :
[A] http://tietyk.github.io/D3/Prototype/part9-9.html
[B] http://bl.ocks.org/rgdonohue/6a30b731230f6e242a54
I have interesting bunch of codes at lines 196-226 below, also in the js file.
Problem is I'm missing clues to make it work.
First one used come from source [A] and it's based on an hover effect.
Second, from source [B] and used button
Both refered to json properties, and I use Csv. The overall format and function implementation is different.
I could spend like a month trying to figure this out myself. So if you have any hints, It would help me a lot : Things i should check, that are missing in my code, etc.
// 2 bunch of codes that were used in order to add interactivity
/*
color();
d3.selectAll("input").on("change", function() {
attribute = this.id;
color();
});
function color(){
d3.selectAll('circle')
.transition()
.attr( "fill", function(d){
return (mycolor.domain())}
)
}
*/
/*
var timeline = d3.selectAll(".time-series")
.on("mouseover", function(d, i) {
year = i;
svg.selectAll("path")
.attr("class", quantify);
d3.selectAll(".time-series")
.attr("class", "time-series");
this.className = "time-series active";
});
*/

D3 multiline chart on update crosses axis

I am trying to plot a multiline d3 chart. I have created a method which should take a new dataset and try to plot it in the same d3 frame for new data update changes (possibly filters).
The first draw works fine but the next draw (mocked data: which is a slice of the previous data and few manipulated values) is not showing correct is crossing the x axis.
[See Image below]
Also the starting origin is missing a tick which should also be 2010 in this example
I also want to create few more lines if there is more datapoints in the future which should be dynamic. Current model is {date, actual, projected}, More expected is mean or difference which will only be shown on trigger.
Any help would be appreciated.
Here is a Stackblitz https://stackblitz.com/edit/angular-rhr39p
References:
Animated line chart: http://bl.ocks.org/atmccann/8966400
Multiline chart: https://bl.ocks.org/larsenmtl/e3b8b7c2ca4787f77d78f58d41c3da91
Dataset updates: https://bl.ocks.org/d3noob/7030f35b72de721622b8
Please keep just one problem per question here at Stack Overflow. This answer will deal with problem #1, consider asking separate questions for the other problems.
The issue here is just your enter/update methodology, that is not correct and. Stick with the idiomatic D3, which is along these lines:
const update = this.svg.selectAll('.records')
.data(records);
const enter = update.enter().append('g')
.attr('class', 'records');
Then, you append new paths using enter and update those paths using update.
You can also ditch the groups and create enter/update/exit selections for the paths directly. That will make your code simpler.
Here is the forked code: https://stackblitz.com/edit/angular-lyd79t?file=src%2Fapp%2Flinechart%2Flinechart.component.ts

Coloring a map using D3.js

I'm new to StackOverflow and I just started using D3.
I need to show the values on a map. I saw this question that is very similar to what I should do.
What I'd like is to color the countries based on the values in the column Date to a CSV and based on selected year by user (radio button).
How can I do that?
I created a gray color scale and have included them in an array, then I created a method chooseColor(value) that returns the correct color based on the value of the country in that year.
I think it is not the most efficient method to do this thing...
Also in my CSV there are not all the countries present in the European Union. For example, I have no data on Russia so I "turned off" some countries putting an if inside the event on mouseover.
But I would also cut part of Russia in the map in order to enlarge the known countries. How can I do also that thing?
I looked at these examples: Choropleth and Threshold Choropleth by Mike Bostock on bl.ocks.org but I have not understand how to color the countries...
(I wanted to put links but I can't post more than 2 links because of my low reputation)
This is my code.
I apologize for my bad English. Thank you all,
Pier
EDIT
I admit I did not understand some things in your code.
Why I need events on mouseover and mouseout? And what are hover and rhover? I thought they were events related to this question. But in my case I don't need it, no?
Use array_values or d is the same, right? Does not change if I use d or array_values, right? It is a stupid question but it confused me.
I modified the makemap method in this way. I understand correctly how to use your code?
function makemap(error, europe, dessease) {
dess = dessease.slice();
counties = topojson.feature(europe, europe.objects.collection);
vector = svg.selectAll("path")
.data(counties.features)
.enter()
.append("path")
.attr("class", "county")
.attr("id", function(d) {
return "coun" + d.properties.indx;
})
.attr("d", path)
.style("fill", function(array_values) {
return color(array_values[d.country]);
});
In this case there is an error concerning d, of course. Sorry, I do not know where I'm wrong...
The country's color will depend on a value. So the color IS a function of "value". To do that you must to define a range of color based on your values:
var color = d3.scale.linear()
.domain([mn,mx]) // <--- min and MAX of your value
.range(["#ffffff","000000"]);
then define the color of your country:
svg.selectAll(".county")
.style("fill", function(array_values) {
return color(array_values[d.country]);
});
Must-Read: Jerome Cukier - d3: scales, and color

Node.Js Map example, adding speed and on-click data?

I've been attempting to learn better visualization with node.js and the mapbox library.
Using this example here: Running Map Example
I'd like to add a graph of speed, and allow a user to click on a node, and see data about that position in a little popup - For today, I just want to get speed working.
It seems to be a recursive algorithm, so I need to implement variables to store the previous position and time, but I've ran into three problems:
I don't know how to use this date format: "2015-01-19T21:24:20Z" or Chroniton's parsing of it to generate a subtractable number to get the difference in time.
I don't know how to get the distance between two points using the code given, I could simply do sqrt((.x(point1) - .x(point2)) + (.y(point1) + .y(point2)), but I'm not sure how coordinates are stored or parsed in this example.
I don't know where to calculate the speed. It seems like the coordinates are only defined after the graphs are displayed, since the coordinates aren't used in the graphics. I am probably wrong, but I need some direction.
Here is what I have now:
Using the elevation display as my template, I think I have made it able to display the line by adding in the following three snippets:
Setting the scale:
var speed = d3.scale.linear()
.range([height, 0])
.domain([0, d3.max(dataRet, function(d) {
return d[1][2];
})]);
Adding in the line, with data:
var SpeedLine = d3.svg.line()
.x(function (d) { return x(d[0]); })
.y(function (d) { return speed(d[2])})
Displaying the line:
svg.append('path')
.datum(dataRet)
.attr('class', 'speed-line')
.attr('d', speedLine);
I know I have to add in a speed function similar to this psudocode:
var dt = chroniton.domain(Time1, Time2)
var speed[i] = LongLat(previousPoint).distanceto(currentPoint)/dt
And on the popup box:
dt.format(something to do with time formatting)
Note 1:, I changed the name of the function datePlaceHeart to dataRet since I'll be adding new things to do it, and datePlaceHeartSpeedStuffAndThings was getting a bit long ;)
Note 2: I haven't been able to start the pop-up because I haven't figured out how to calculate speed using the given data, and well, it seems kinda silly to do the easy one first. (With my luck, its actually not easy)
Please help? Here is my edited code in full (Edited index.js):
Code

d3.js Update circle on line chart

I'm posting there because I couldn't find something on other post or on google.
http://jsfiddle.net/CUQaN/9/
As you can see on the JS fiddle, I have a line chart with circle on each point.
I want to update this chart with new data. The problem is that I can receive less or more point than I already have on the graph. For example, I can have 8 point on my line chart and then when I'm updating the chart, I can have just 4, or even 15 point. And my circle are not updating properly because I'm just changing the value of the circle which already exist.
But I really don't know how to update them properly.
I can have that data sometimes :
var data = [
{"date":"4-May-12","close":Math.random()*568.13,"open":Math.random()*35.12},
{"date":"3-May-12","close":Math.random()*568.13,"open":Math.random()*35.12},
{"date":"2-May-12","close":Math.random()*568.13,"open":Math.random()*35.12},
{"date":"1-May-12","close":Math.random()*568.13,"open":Math.random()*35.12},
{"date":"30-Apr-12","close":Math.random()*354.98,"open":Math.random()*424.56},
{"date":"27-Apr-12","close":Math.random()*24.00,"open":Math.random()*253.89},
{"date":"26-Apr-12","close":Math.random()*490.70,"open":Math.random()*215.54},
{"date":"25-Apr-12","close":Math.random()*42.00,"open":Math.random()*351.23},
{"date":"24-Apr-12","close":Math.random()*210.28,"open":Math.random()*20.23},
{"date":"23-Apr-12","close":Math.random()*20.70,"open":Math.random()*368.34},
{"date":"20-Apr-12","close":Math.random()*412.98,"open":Math.random()*42},
{"date":"19-Apr-12","close":Math.random()*26.44,"open":Math.random()*20.56},
{"date":"18-Apr-12","close":Math.random()*48.34,"open":Math.random()*356.45},
{"date":"17-Apr-12","close":Math.random()*26.44,"open":Math.random()*20.56},
{"date":"15-Apr-12","close":Math.random()*48.34,"open":Math.random()*356.45},
];
And just that data other times : (more or less)
var data = [
{"date":"4-May-12","close":Math.random()*568.13,"open":Math.random()*35.12},
{"date":"3-May-12","close":Math.random()*568.13,"open":Math.random()*35.12},
{"date":"2-May-12","close":Math.random()*568.13,"open":Math.random()*35.12},
{"date":"1-May-12","close":Math.random()*568.13,"open":Math.random()*35.12},
{"date":"30-Apr-12","close":Math.random()*354.98,"open":Math.random()*424.56},
];
Is someone can help me please ?
Thanks a lot !
It might be better to remove the old points and add the new ones rather than trying to move them. To do this you can use an id function to make the points unique - see here
A small example:
svg.selectAll("circle")
.data(myData, function(d) { return d.x; })
.enter()
.append("circle");
The important part here is that points are identified by their x-value, rather than their index in the data point array. Infact this might help in your current situation as the points will only move up/down and not side to side.

Categories