D3JS selection selectAll - javascript

I have this piece of code :
var series, seriesChildren;
selection.each(function (data) {
series = d3.select(this).selectAll('.my-series').data([data]);
series.enter().append('g').classed('my-series', true);
console.log(data);
seriesChildren = series.selectAll('.seriesChild')
.data(data, function (d) {
return d.x;
});
seriesChildren.enter()
.append('g')
.classed('seriesChild', true);
}
And I don't understand why it gives me the following :
<g class="my-series"></g>
without the children.
It should be :
<g class="my-series">
<g class="seriesChild"></g>
<g class="seriesChild"></g>
...
</g>
I did a console.log(data) and my data is good, it has thousands of elements within it.
It is working by doing seriesChildren = d3.selectAll('.my-series').selectAll('.seriesChild') but not working with seriesChildren = series.selectAll('.seriesChild')
I'm using D3JS v4.

These two statements are diffrent
1. seriesChildren = series.selectAll('.seriesChild')
2. seriesChildren = d3.selectAll('.my-series').selectAll('.seriesChild')
In 1st series is not a DOM element hence seriesChildren = d3.selectAll('.my-series').selectAll('.seriesChild') will not work as you are expecting
whereas in second case d3.selectAll('.my-series') this represent a DOM element and furter d3.selectAll('.myseries').selectAll('.seriesChild') will select another DOM element.

Related

React JSX Dynamic SVG Translate Error

I'm new to React and trying to do a dynamic Svg Transition where I translate the Position of a Group according to the current Component State. For some reason I get the Error Message:
DOMPropertyOperations.js:139 Error: <g> attribute transform: Expected
'(', "translate:(100 100)".
Here is the render function:
render() {
let turns = Route.Leg.map((turn) => <circle cx={turn.to.location.latitude} cy={turn.to.location.longitude} r="5"></circle>)
let legs = Route.Leg.map((leg) => <line x1={leg.from.location.latitude} y1={leg.from.location.longitude} x2={leg.to.location.latitude} y2={leg.to.location.longitude} stroke="black"></line>)
let move = "translate:(" + this.state.pos.location.latitude + " " + this.state.pos.location.longitude + ")";
return (
<div>
<svg width="800px" height="800px">
<circle cx="400" cy="400" r="10"></circle>
<g transform={move}>
{turns}
{legs}
</g>
</svg>
</div>
);
}
The lines and circles are drawn correctly, and when I log the "move" variable and looks correct every time the dom updates. When I hardcode the translate it also works. Does someone have an idea what is wrong here, or am I just missing something? Cheers in advance
As says in the error Expected (',...
// Look down, there is no ":" character in css syntax. And check for ","
let move = "translate(" + this.state.pos.location.latitude + "," + this.state.pos.location.longitude + ")";
That's because of you are using wrong syntax. You should use translate(... not translate:(....
Also you should comma seperate values inside translate

d3 slider to change csv column

I have a d3 slider with a range from 2001 to 2016 and a csv file with columns name and no_2001 to no_2016. The csv is called in a d3.queue together with a json file to build a choropleth map changing over the years.
My problem is to change the column of the csv file by dragging the slider. Can anyone help? Thanks!
This is what I have so far. In the queue function "+d.no_2015" has to be changed, but my defined "column" does not work if I replace it with "+d.no_2015".
<h2>Year: <span id="year">2016</span></h2>
<div id="slider"></div>
<script>
function csvColumn(data){
column = "no_" + data;
return column // this does not work
};
d3.select('#slider').call(d3.slider()
.min(2001)
.max(2016)
.value(2016)
.step(1)
.axis(d3.svg.axis().tickFormat(d3.format(".0f")).ticks(16))
.on("slide", function(evt, value) {
d3.select('#year').text(value);
csvColumn(value);
}));
var rateById = d3.map();
d3_queue.queue()
.defer(d3.json, "de_landkreis.json")
.defer(d3.csv, "maserndaten.csv", function(d) {rateById.set(d.name, +d.no_2015);}) //here the slider has to act. +d.column does not work.
.await(showData);
function showData(error, de_landkreis) { ... }
</script>
Ok, if I got it right, you should change your code so the column defined by your slider is used instead to populate your map. This I think would do the trick:
<h2>Year: <span id="year">2016</span></h2>
<div id="slider"></div>
<script>
// This is the default value
var selectedColumn = "no_2014";
function csvColumn(data){
return "no_" + data;
};
d3.select('#slider').call(
d3.slider()
.min(2001)
.max(2016)
.value(2016)
.step(1)
.axis(d3.svg.axis().tickFormat(d3.format(".0f")).ticks(16))
.on("slide", function(evt, value) {
d3.select('#year').text(value);
selectedColumn = csvColumn(value);
})
);
var rateById = d3.map();
d3_queue.queue()
.defer(d3.json, "de_landkreis.json")
.defer(d3.csv, "maserndaten.csv", function(d) {
rateById.set(d.name, +d[csvColumn(selectedValue)]);
})
.await(showData);
function showData(error, de_landkreis) { ... }
</script>
Of course, you would need to wire it in a way that changing the slider triggers the redrawing of the data using a different column as source. But the first part is solved.

d3 interaction on click event

I have a map with d3 circles showing the site locations, as well as a linechart showing the time trend for each of the site. I am trying to make a particular line highlight when a corresponding circle is clicked. Here is the code. I can't seem to connect the siteIDs with the following function:
function highlightLine(id) {
lineGroup.classed("g-highlight", function(d) {
return d.siteID == id.siteID;
});
};
Insert a console.log as shown below, and it should become clearer:
function highlightLine(id) {
lineGroup.classed("g-highlight", function(d) {
console.log(d);
return d.siteID == id.siteID;
});
};
Because you're binding to data that you've run through d3.nest, the id of d that you're interested in is actually d.key not d.siteID, which does not exist on that level. So the boolean inside classed should be
return d.key == id.siteID
That will cause the appropriate trendline's <g> to have a "g-highlight" class, however it still will not visibly color the line. I believe that's because your css rule .g-highlight { stroke:... } applies the stroke to the containing <g> instead of the <path> inside it. You can change that css rule to be .g-highlight path { ... } and that will color the path as you'd like.
To bind the click event in d3 you should select the object with that class and bind the click:
d3.selectAll(".g-highlight").on("click", function(d) {
return d.siteID == id.siteID;
});

D3.js ( in Coffeescript) show data on click

I am in the process of creating a bubble chart with D3.js. Now I want it to display a comment in the <h3 id="comment"></h3> tag when I click on each bubble.
Here is my data.csv file:
name,count,group,comment
apple,5,red,"This is the best apple ever."
grape,10,purple,"Grapes are huge."
banana,8,yellow,"Are these bananas even ripe?"
pineapple,1,yellow,"Great for making juice."
...
And in my viz.coffee, I have:
idValue = (d) -> d.name
textValue = (d) -> d.name
groupValue = (d) -> d.group
commentValue= (d) -> d.comment
Originally, I use the following code to display the name of the bubble when clicked:
updateActive = (id) ->
node.classed("bubble-selected", (d) -> id == idValue(d))
if id.length > 0
d3.select("#comment").html("<h3>#{id} is selected.</h3>")
else
d3.select("#comment").html("<h3>Nothing is selected</h3>")
How should I change it, so that when you click on the bubble, the comment displays instead?
I tried:
updateActive = (id) ->
node.classed("bubble-selected", (d) -> id == idValue(d))
if id.length > 0
d3.select("#comment").html(d.comment)
else
d3.select("#comment").html("<h3>Click on a bubble to read its comment.</h3>")
But it doesn't seem to work, because d is undefined, which I can see why, but I'm not sure what I should do. Please help.
Even though I'm not completely sure of your code I think this should work:
updateActive = (id) ->
node.classed("bubble-selected", (d) -> id == idValue(d))
if id
for x in data when idValue(x) is id
d3.select("#comment").html(commentValue(x))
else
d3.select("#comment").html("<h3>Click on a bubble to read its comment.</h3>")
Here data is what you supply to d3 through .data().

How are enter() and exit() detecting updated data in D3?

I am building a small UI where the user has to select a point on each of the two SVGs shown.
These points coordinates are then shown under the SVGs. I would like to achieve this using D3's data-binding with the enter() and exit() methods. However it seems that D3 doesn't always update the part where I display the points coordinates, even if I call the enter() method on the bound elements. When removing data, the exit() methods works however.
Here is the main code :
function showPoints() {
var coordinatesElements = d3.select('#coordinates').selectAll('.point').data(points);
coordinatesElements.enter().append('div').classed('point', true)
.text(function (d) {
var textParts = [];
if (d.firstSvg) { textParts.push('first : '+JSON.stringify(d.firstSvg)); }
if (d.secondSvg) { textParts.push('second : '+JSON.stringify(d.secondSvg)); }
return textParts.join(' - ');
})
.append("span")
.classed('removeCalibrationPoint', true)
.html(" X")
.on('click', function(d, i) {
points.splice(i, 1);
showPoints();
});
coordinatesElements.exit().remove();
}
I have created a JSBin fiddle that demonstrates the problem.
The first problem is that you have an empty div of class point in your HTML. This will be selected by the .selectAll('.point') and cause the first element in your data not to show up.
The second problem is that you're not handling the update selection -- in some cases, you're not adding new data, but modifying existing data. The following code updates the text for the data in the update selection.
coordinatesElements.text(function (d) {
var textParts = [];
if (d.firstSvg) { textParts.push('first : '+JSON.stringify(d.firstSvg)); }
if (d.secondSvg) { textParts.push('second : '+JSON.stringify(d.secondSvg)); }
return textParts.join(' - ');
});
Complete demo here. Notice I've simplified the code slightly by setting the text only on the update selection -- elements added from the enter selection merge into the update selection, so there's no need to do it twice.

Categories