Getting selected objects in topojson object - d3.js

So I am trying to use topojson to load a map of the US and display the 50 states. When a state is clicked, I want to the display the counties within that state. The problem I am running in to though is that based on the formatting of the topojson file, I can't figure out how to know WHICH state is clicked and therefore don't know how to grab the corresponding counties from the file.
I am using a very similar implementation to the one presented by Mike Bostock on his site here: https://bl.ocks.org/mbostock/9656675
I am also using his version of the topojson file which can be found here:http://bl.ocks.org/mbostock/raw/4090846/us.json
When I click on a specific state, I can look at the "this" object but that ends up being just a bunch of boundary points.
Any ideas? (I can clarify if I am being too vague as well)
Clarification:
I realized that states have an id (sometimes a few depending on islands) numbered between 1-78.
If I try to create state groupings to add to the SVG like this:
g.append("g")
.attr("class", "states")
.selectAll("path")
.data(state_features)
.enter().append("path")
.attr("class", "states")
.attr("d", path)
.on("click", clicked);
I can later tell which state was clicked in the function that handles clicks like so:
function clicked(d) {
//can reference it in here with "this"
console.log(this.id);
}
This gives me the id of the state, but it seems like counties don't correspond to a given state so I don't know how to get the counties corresponding to that state.

Related

Linked tooltip on heatmap and sparkline

I created a heatmap and sparklines next to the heatmap.
HERE the Plunker
Now I would like that when the user hovers over a cell of the heatmap, a red dot is displayed on the corresponding sparkline.
On the other hand, when the user hovers over the sparkline, the corresponding cell in the heatmap is highlighted.
I hope it's clearer with some drawings:
I thought I could change the code at this point:
var cells = svg.selectAll('rect')
.data(data)
.enter()
.append('g')
.append('rect')
//...
.on('mouseover', tip.show) // <- HERE
.on('mouseout', tip.hide);
I should keep track of the rectangle on which the mouse is located and somehow pass this data to the piece of code that controls the sparkline.
But I don't really know how to do it and I have not found similar examples.
Thanks!
HERE MY PLUNKER
add this liblary:
<script src="https://code.jquery.com/jquery-3.1.0.js"></script>
To solve your problem, you need understand the concept,
The D3 can holding data when you put on it
The D3 can select base on class and id
The DOM element can hold attribute (Ex: attr-id)
Scale linear can be invers, that mean if you have domain you can have range and if you have range you can have domain
Element that draw with D3 is updatable & deletable
understand the liblary you use (d3-tip)
What i Change
i add class and id to element i want to select
if i want to use data, i save data to data-attribute
i make function to track my mouse on Line-chart, and invers it to get value
i draw object tip i want to use
read the code if you want to understand ask me which line you dont understand, if you need explanation

Strange Axis Behavior

I have a color coded map of China, and it was working fine until I added a color scale and an axis to the right of the map. You may view it here:
https://bl.ocks.org/diggetybo/4c42aafc20c21e416585c9e37079eda2
The problem is, a province went missing after I added the axis. By missing, I mean it is not visible anymore. I'm not sure if it's actually still there but has a fill of none, or for some reason the path was not drawn altogether. It is a very large province too, in the northwest of China. For those hard core in geography, the name of the province is Xinjiang.
At first I was convinced it was user error on my part, but after much toiling I slowly started to suspect it could be a bug of some kind. I did manage to narrow it down to which line: line 69, or the .call(axis); line in the snippet below:
var axisNodes = svg.append('g')
.attr('transform', 'translate(' + (margins.left+865) + ',' + (margins.top) + ')')
.call(axis);
styleAxisNodes(axisNodes);
I literally commented out every other line, and only the .call(axis); line makes the province disappear. You can try for yourself, just comment out line 69 and the province will reappear.
My question: What does an axis have to do with a totally different section of my code, the fill of a json parsed map path? Why did it only affect that province? And what can I do to avoid this?
Thank you
When you do this inside your d3.json function:
svg.selectAll("path")
You are in fact selecting an already existing path, which is the axis' path, and binding data to it.
Because of that, your "enter" selection will have one element less.
Solution: select something that doesn't exist:
svg.selectAll("foo")
Here is your updated bl.ocks: https://bl.ocks.org/anonymous/387781c5bccb0339141b519c098f5605
PS: another solution is calling the axis after painting the map.
PPS: "Why did it only affect that province?" That province is the first one in the data.

Adding labels to nodes in Flowing Data Interactive Network Demo

I tried adding permanent labels (names of nodes) to the Interactive Network Demo shared by Jim. (https://flowingdata.com/2012/08/02/how-to-make-an-interactive-network-visualization/)
Being a novice in D3 and Coffee, I couldn't achieve the goal despite spending good amount of time trying to understand D3 and Coffee scripting.
Following is the coffee script i tried to add:
node.enter().append("text")
.attr("cx", (d) -> d.x)
.attr("cy", (d) -> d.y)
.text("text", (d) -> d.name)
Some help in achieving the same would be highly appreciated.
That example uses D3 v3.x. Unfortunately, there is a "magic" in v 3.x that will prevent you to achieve what you want (not to mention that text doesn't have cx or cy):
This is the node selection, which is the data binding selection:
node = nodesG.selectAll("circle.node")
.data(curNodesData, (d) -> d.id)
However, the next line is:
node.enter().append("circle")
And here comes the problematic magic:
The enter and append modify the data binding selection. So, when after that you try to append a text to node, you're actually appending a text element to a circle element, and that will not work!
Solution: create SVG groups, where you can append both circles and texts.

transitioning multiple elements with d3

I'm having a heck of a time with transitions in D3js. I posted a fiddle here: dynamic area graph. The problem that I run into is that when trying to follow this tutorial path transitions, I run into sync problems with the xAxis. Bostock indicates that the domain should be skewed slightly so that the data appears to "shift" in from the side. However, when I do that, the data reflected will be listed under a tick mark that is "2 minutes" behind the actual time it should be listed. If I just update the data as-is, without doing the tricky stuff with the clip-path, it works fine. All of the data is in sync. Just for reference, the xAxis is an integer, linear scale. Dealing with date strings was madding, even though d3 has great time manipulation, I just find dealing with epoch easier. If someone could check out the fiddle and let me know how to transition the entire drawing...I want it to be smooth like in the examples that bostock has.
Since SO requires some code, here's the data structure that I'm generating. The rest is in the fiddle:
setInterval(function(){
lastTime = lastTime.add('m',1);
var data = {"apikey":"FOO",
"description":"a dumb description",
"beg_effective_dt_tm":lastTime,
"data":{
"sum":getRandomInt(385,4000),
}
};
tick(data);
},1000)
I think this is close to what you are after: http://jsfiddle.net/JJ7Rj/1/
It is close because the graph is delayed by one value.
Most of the architecture was already there, and your concern that you might lose the sync between the xAxis and the data was correct. Mike gets around it by changing his range of the scales. The other (and better, IMO) way is to do it by changing the domains. I made the following two primary changes.
The domain of the axis
I have modified the minMax function such that it does not include the latest and the last point in the domain of the xAxis. Note that this means that the most recent value (as well as the oldest value) is actually displayed outside the visible region. This is an unfortunate limitation of using the monotone interpolation, which Mike talks about at the bottom of his post.
function minMax(pd) {
return [
d3.min(pd.slice(1).slice(0, -1),function(d){ return d.beg_effective_dt_tm; }),
d3.max(pd.slice(1).slice(0, -1),function(d){ return d.beg_effective_dt_tm; })
];
}
If you want to have all the values visible, then you'll get the wiggling effect of the discontinuous tangent suddenly forming when the new value comes in. You can obtain that by removing the .slice(0, -1).
The initial transform
For each element, I have initially placed the DOM element one step to the right.
var step = x(newVal.beg_effective_dt_tm) - x(pd[pd.length - 1].beg_effective_dt_tm);
// ...
.attr("transform", 'translate(' + step + ')');
// ...
Then finally, I have transitioned everything back to their rightful place:
clipPath.selectAll("path,circle,.dp").transition()
.ease("linear")
.attr("transform", "translate(" + 0 + ",0)");
Also, I have enabled the transition for the xAxis.

D3.js Bar Chart axis label having select box

We have requirement to add drop down with axis label so that user can change the data from there.We require this drop down box effect on only specific label.
One approach we have tried is to add svg:image with label and the functionality is working fine but the other label is having the down arrow image that is not required. So can anybody help me out how I can select only one label? Actually there are multiple labels and its index is getting changed on chart update. Please find below code which is working for adding images to all labels.
e.g.
g.selectAll('.nv-x.nv-axis').selectAll('.tick.major').append("svg:image").
on("click", click)
.attr("xlink:href", "images/top-bar-logo.png")
.attr("width", 20)
.attr("height", 20).attr("x", -20);
You can use the filter() function to select the ticks that you need to append the image to. The documentation I've linked to has a few examples -- you might be able to do it without filter() by passing a different selector to selectAll().

Resources