How to access elements from dataset in d3 - javascript

I have a parallel coordinates plot and I want to show lines onclick for d.dataset = train else hide them.
I wanted to access the row using .filter() like this:
data.filter(function(d) { return d.dataset == "train"; }).attr("visibility", "hidden");
and then set the attr visibility to hidden so that afterwards I can write a function with onclick to make the visibility visible, something like this:
// On Click, we want to add data to the array and chart
svg.on("click", function() {
var line = d3.mouse(this);
if (d.dataset === "train"){
//Display line of d.dataset === train
// line.attr("visibility", "visible");
}
});
This one I found also d3.selectAll("[dataset=train]").attr("visibility", "hidden"); but this doesn't work when doing with data elements right?
Right now I tried these and nothing happens. This is the jsfiddle I am working in. The line with "dataset":"train", is visible and doesn't hide.
How can I hide the lines when "dataset":"train", and then show them when onclick to the other lines in the parallel coordinates plot?
Any help would be highly appreciated.

First, make some marks on each path, for example, give a class name like coorPath so that it will be easier to find them. I added it for both background and foreground since I didn't know their difference.
svg.append("g")
.attr("class", "background coorPath") // add classname
.selectAll("path")
.data(dataSet)
.enter().append("path")
.attr("d", draw);
// CHANGE: duplicate with below code
/* svg.append("g")
.attr("class", "foreground coorPath")
.selectAll("path")
.data(dataSet)
.enter().append("path")
.attr("d", draw); */
// USE THE COLOR SCALE TO SET THE STROKE BASED ON THE DATA
foreground = svg.append("g")
.attr("class", "foreground coorPath")
.selectAll("path")
.data(dataSet)
.enter().append("path")
.attr("d", draw)
.style("stroke", function(d) {
var company = d.type.slice(0, d.type.indexOf(' '));
return color(company);
})
Then, find out the line of train, and make it invisible at first
let trainline = d3.selectAll("path").filter(function(d) { return d.dataset == "train"; })
trainline.attr("visibility", "hidden");
Show the line of train when one of other lines is clicked.
svg.selectAll(".coorPath").on("click", function(d) {
// show train when click others
trainline.attr("visibility", "visible")
});
a demo here

Related

D3 Adding dots to dynamic line chart

I have a scrolling line chart that is being updated in realtime as data comes in. Here is the js fiddle for the line chart. https://jsfiddle.net/eLu98a6L/
What I would like to do is replace the line with a dot graph, so each point that comes in would create a dot, and the scrolling feature is maintained.This is the type of chart I would like to create dow jones dot graph and ultimately I would like to remove the line underneath.
This is the code I have used to try and add dots to my graph.
g.append("g")
.selectAll("dot")
.data(4)
.enter("circle")
.attr("cx", "2")
.attr("cy", "2");
So far I haven't had any success. I'm very new to d3, so any help is appreciated. Thanks!
Based on your code an approach for this can be :
var circleArea = g.append('g'); /* added this to hold all dots in a group */
function tick() {
// Push a new data point onto the back.
data.push(random());
// Redraw the line.
/* hide the line as you don't need it any more
d3.select(this)
.attr("d", line)
.attr("transform", null);
*/
circleArea.selectAll('circle').remove(); // this makes sure your out of box dots will be remove.
/* this add dots based on data */
circleArea.selectAll('circle')
.data(data)
.enter()
.append('circle')
.attr('r',3) // radius of dots
.attr('fill','black') // color of dots
.attr('transform',function(d,i){ return 'translate('+x(i)+','+y(d)+')';});
/* here we can animate dots to translate to left for 500ms */
circleArea.selectAll('circle').transition().duration(500)
.ease(d3.easeLinear)
.attr('transform',function(d,i){
if(x(i )<=0) { // this makes sure dots are remove on x=0
d3.select(this).remove();
}
return 'translate('+x(i-1)+','+y(d)+')';
});
/* here is rest of your code */
// Slide it to the left.
d3.active(this)
.attr("transform", "translate(" + x(-1) + ",0)")
.transition()
.on("start", tick);
// Pop the old data point off the front.
data.shift();
}
See it in action : https://codepen.io/FaridNaderi/pen/weERBj
hope it helps :)

Changing Edge color with D3

I am reading a D3 tutorial and am following the code in this link:
http://www.d3noob.org/2013/03/d3js-force-directed-graph-example-basic.html
I understand the content so far, but am trying to learn more styling by changing different colors. I am trying to change the edge color between the nodes, but this is not working. I know I need to do
path.style("stroke", red)
for instance. But this changes every edge color as expected.
However, I want to change the color of the edge based on the value in the links array. So, if the links.value is < 1 I want green else I want an orange link.
I am somewhat stuck I know I need to use
.style("stroke", function(d) {if d.value < 1 {return 'green'} else {return 'orange'} });
I just can't figure out where to put this in the sample code. I'm just trying to learn by example from some basic D3. Thanks!
You set the style in the "enter" selection of the edges:
var path = svg.append("svg:g")
.selectAll("path")
.data(force.links())
.enter()
.append("svg:path")
.attr("class", function(d) { return "link " + d.type; })
.attr("class", "link")
.style("stroke", function(d){
if(d.value < 1) {return 'green'} else {return 'orange'}
})
.attr("marker-end", "url(#end)");
Here is the plunker: https://plnkr.co/edit/tOBZdHXVrvcAmh9aHlsl?p=preview
You should be able to add your chain your methods on to the end of:
// add the links and the arrows
var path = svg.append("svg:g").selectAll("path")
.data(force.links())
.enter().append("svg:path")
.attr("class", "link")
.attr("marker-end", "url(#end)");
It's approx line 73 of the sample code

In D3 How to enable mouse over event for current particular path?

I was creating a world map using d3.js.In that map i need to bind the mouseover event for every country.
For example: If i mouseover the india i need to change the Fill(Background) color for india only.
I implemented the mouseover event.But my problem is whenever i mouseover over the country(India) that function effecting all the countries.I mean fill color effecting all the countries.But it need to effect only current country.
I tried using this also but no luck for me.
.on("mouseover", function(){d3.select(this).style("fill", "aliceblue");})
Please help any one to solve my problem.
My Full Code
var width = 1000,
height = 500;
var projection = d3.geo.robinson()
.scale(150)
//.translate(100,100)
.precision(.5);
var path = d3.geo.path()
// .attr("class","path")
.projection(projection);
var svg = d3.select('#'+id)
.append('svg')
.attr("width", width)
.attr("height", height)
.attr("style", "background:" + json.bc);
//shape
d3.json("world.json", function(error, world) {
svg
.datum(topojson.feature(world, world.objects.countries))
.append("path")
.on("mouseover", function(){d3.select(this).style("fill", "red");})
.on("mouseout", function(){d3.select(this).style("fill", "white");})
.attr("style", "fill:" + json.cbc)
.attr("class", "country")
.attr("d", path)
;
});
Before mouseover
After MouseOver
This code:
svg
.datum(topojson.feature(world, world.objects.countries))
.append("path")
...
says --> I have one piece of data, draw me a path from it.
Change it up to this:
svg.selectAll(".countries")
.data(topojson.feature(world, world.objects.countries).features)
.enter()
.append("path")
...
which says --> I have multiple data (features), bind the data to my selection (selectAll) and draw me a path for each component.
Example here.

D3js : mouseover of one element change opacity of several others elements

Thanks to previous answers, I've made a map and a related graph with D3js.
The bar and the map are in specific divs, and I don't use the same data source. That's a part of my problem.
For the map, I used queue.js to load several files at a time. One of these files is a .csv which follow specifically the same order than the geojson where polygons are stocked. If I sort differently .csv's data, the correspondance with my .geojson's polygons is bad and my choropleth map become false.
Here's the associated code for the interactive polygons of the map :
svg.append("g").attr("class","zones")
.selectAll("path")
.data(bureaux.features) //"bureaux" is a reference to the geojson
.enter()
.append("path")
.attr("class", "bureau")
.attr("d", path)
.attr("fill", function(d,i){
if (progression[i].diff_ries<-16.1){ //"progression" is the reference to my .csv
return colors[0] // colors is a previous array with the choropleth's colors
}
else if (progression[i].diff_ries<-12.6){
return colors[1]
}
else if (progression[i].diff_ries<-9){
return colors[2]
}
else {return colors[3]
}
})
.on('mouseover', tip.show) // tip.show and tip.hide are specific functions of d3.js.tip
.on('mouseout', tip.hide)
};
No problem here, the code works fine. We arrived now to the graph. He used a .json array called at the beginning of the script, like this
var array=[{"id_bureau":905,"diff_keller":4.05,"diff_ries":-15.02},{etc}];
"id_bureau" is the common' index of my .geojson, my .csv and this .json's array. Then, I sort the array with a specific function. Here's a part of the code associated to the graph :
svg2.selectAll(".bar")
.data(array)
.enter().append("rect")
// I colour on part of the bars like the map
.attr("fill", function(d,i){
if (array[i].diff_ries<-16.1){
return colors[0]
}
else if (array[i].diff_ries<-12.6){
return colors[1]
}
else if (array[i].diff_ries<-9){
return colors[2]
}
else {return colors[3]
}
})
.attr("x", function (d) {
return x(Math.min(0, d.diff_ries));
})
.attr("y", function (d) {
return y(d.id_bureau);
})
.attr("width", function (d) {
return Math.abs(x(d.diff_ries) - x(0));
})
.attr("height", y.rangeBand());
// this part is for the other bars
svg2.selectAll(".bar")
.data(tableau)
.enter().append("rect")
// the others bars are always blue, so I used a simple class
.attr("class", "bar_k")
.attr("x", function (d) {
return x(Math.min(0, d.diff_keller));
})
.attr("y", function (d) {
return y(d.id_bureau);
})
.attr("width", function (d) {
return Math.abs(x(d.diff_keller) - x(0));
})
.attr("height", y.rangeBand());
svg2.append("g")
.attr("class", "x axis")
.call(xAxis);
svg2.append("g")
.attr("class", "y axis")
.append("line")
.attr("x1", x(0))
.attr("x2", x(0))
.attr("y2", height2);
So now, what I wan't to do is, when the mouse is over one polygon, to keep the correspondent bar of the graph more visible than the others with an opacity attribution (and when the mouse out, the opacity of all the graph returns to 1).
Maybe it seems obvious, but I don't get how I can correctly link the map and the graph using the "id_bureau" because they don't follow the same order like in this question : Change class of one element when hover over another element d3.
Does somebody know if I can easily transform the mouseover and mouseout events in the map's part to change at the same time my graph?
To highlight a feature on the map
To perform a focus on one feature, you just need a few line of CSS:
/* Turn off every features */
#carte:hover .bureau {
opacity:0.5;
}
/* Turn on the one you are specifically hovering */
#carte:hover .bureau:hover {
opacity:1;
}
To highlight a bar in your second chart
First of all, you need to distinguish the two kind of bar with two classes :
// First set of bars: .bar_k
svg2.selectAll(".bar_j")
.data(tableau)
.enter().append("rect")
// Important: I use a common class "bar" for both sets
.attr("class", "bar bar_j")
// etc...
// Second set of bars: .bar_k
svg2.selectAll(".bar_k")
.data(tableau)
.enter().append("rect")
.attr("class", "bar bar_k")
// etc...
Then you have to change your mouseenter/mouseleave functions accordingly:
svg.append("g").attr("class","zones")
.selectAll("path")
.data(bureaux.features)
.enter()
// creating paths
// ...
// ...
.on('mouseover', function(d, i) {
// You have to get the active id to highligth the right bar
var id = progression[i].id_bureau
// Then you select every bars (with the common class)
// to update opacities.
svg2.selectAll(".bar").style("opacity", function(d) {
return d.id_bureau == id ? 1 : 0.5;
});
tip.show(d,i);
})
.on('mouseout', function(d, i) {
// To restore the initial states, select every bars and
// set the opcitiy to 1
svg2.selectAll(".bar").style("opacity", 1);
tip.hide(d,i);
});
Here is a demo.
Performance issue
This implementation is kind of slow. You might improve it by toggling an "active" class to the bars you want to highlight.
An other good tail might be to gather the two kinds of bar in a single group that you describe singularly with an id (ie bureau187 for instance). That way you could select directly the bar you want into the mouseenter function and turn it on with an "active" class.
With this class you could mimic the strategy I implemented to highlight a feature and then remove svg2.selectAll(".bar").style("opacity", 1); from the mouseleave function :
/* Turn off every bars */
#carte:hover .bar {
opacity:0.5;
}
/* Turn on the one you want to highligth */
#carte:hover .bar.active {
opacity:1;
}

Fading chords in d3js chord graph

I'm a total beginner with d3js, so please be patient if my question looks dumb.
I'm trying to reproduce a chord graph like the one proposed by Mike Bostock. In the code by Bostock if you go with your mouse on an arc, all the chords that are not involved (as target as well as source) in the arc will fade.
I'd like to change it in order to let all the chords fade except the one on which there is a mouse (in order to emphasize one single two-way relationship).
I've added a fade_single function that is triggered when the mouse is over a chord:
svg.append("g")
.attr("class", "chord")
.selectAll("path")
.data(chord.chords)
.enter().append("path")
.style("fill", function(d) { return fill(d.target.index); })
.attr("d", d3.svg.chord().radius(r0))
.style("opacity", 1)
.on("mouseover", fade_single(0.1))
.on("mouseout", fade_single(1));
The fade_single function follows:
function fade_single(opacity) {
return function(g, i) {
svg.selectAll("g.chord path")
.filter(function(d) {
//return d.source.index != 0 && d.target.index != 0;
})
.transition()
.style("opacity", opacity);
};
}
The problem is that I don't know what to put in the commented line, i.e. to filter out all the relationship that are have not the row and column of the single chord. I've tried to play with the subindexes but the parameter i only gives you the row, so I don't know how to isolate the chord I want to exclude from the fading.
Any idea? Any hint?
Thank you,
Elisa
To fade everything but the current elemeent, the easiest way is to use the this reference to the current DOM element:
function fade_single(opacity) {
return function() {
var me = this;
svg.selectAll("g.chord path")
.filter(function(d) {
return this != me;
})
.transition()
.style("opacity", opacity);
};
}

Categories

Resources