D3 Force layout fix positions - javascript

I'm using D3's forced layout graph to plot the data.
When I call the update function using setInterval with new data, the force layout graph nodes start from a random position. How can I fix this?
I read other answers such as using d.x d.y or alpha(0) , in case of alpha(0) it did not work but d.x d.y using was successful until the data is changed and then the new node is not in same position as it is supposed to be.
My Current working fiddle: https://jsfiddle.net/mootqvs1/5/

In D3.js version 3 you have a property fixed for the node to stay at the current position. In version 4 this property is replaced with d.fx and d.fy, if they are set the node will stay at that position.

Related

Unable to refresh svg chart on Data Change

I have a heatmap designed on d3js. I have added two filters for sorting the data. When I'm changing the filters I see the updated data in the console and the chart refreshes. But after each refresh, the earlier visualized chart still remains.
I have tried .remove() and .exit from d3. These didn't seem to work.
Here's the link for my code in codesandbox: https://codesandbox.io/s/5x6qkjw6kp
Quick Answer
The way you have your code setup, you are calling the whole heatmap creation function every time a filter changes, so you're reading data, axes, everything again. Based on that, you could easily clear all elements on the chart and have them recreated from scratch, rather than using the true enter, exit, update pattern, by putting this line before you define your chart.
d3.select(".chart").selectAll("*").remove();
So your code will now look like
//Setting chart width and adjusting for margins
d3.select(".chart").selectAll("*").remove();
const chart = d3
.select(".chart")
.attr("width", width + margins.right + margins.left)
.attr("height", height + margins.top + margins.bottom)
.append("g")
.attr(
"transform",
"translate(" + margins.left + "," + margins.top + ")"
);
Enter Exit Update
This section has been heavily edited, but looking through the code, quite a lot of changes would have to be made to adapt it to make it use Enter/Exit/Update type processes. Think about putting the main creation steps at the start of the chart creation outside of the function, as these only need to run once at load (titles, axes, things like that). Clicking new elements would then not recreate the whole chart, but just alter the dataset used to create the rect objects.
This works by removing all elements which are children of the main chart group before the chart is recreated.
Hope that makes sense, let me know if anything is unclear and I'll tidy it up!

Transition on nodes' and links' positions in D3 v4 force layout

I am using D3 v4 to make a dynamic social network visualization and an example is here: https://jsfiddle.net/wand5r6L/1/.
There are two years of data in this example, and I want to update the nodes and links when 2004 comes to 2005. I want to make the positions of nodes and links to dynamically change as new nodes and links are added, but they just pop out at once regardless of the original position of old nodes and links.
I think I should add transition() to the tick() function but it does not work and causes more bugs.
Any suggestions? Thanks in advance.
This is the modifying a force layout block example from Mike Bostock:
https://bl.ocks.org/mbostock/0adcc447925ffae87975a3a81628a196
This is an updated jsfiddle I forked from the one you made. Mostly I specified a key function in the data links:
https://jsfiddle.net/eonny83k/1/
var node = g2
.attr("class", "nodes")
.selectAll("circle")
.data(nodeData, function(d) { return d.source + '-' + d.target });

How to define the node entering position in D3 js force layout

I am trying to implement a radial force layout in D3.js , I saw a similar example but i am stuck on how to initiate the node positions in the layout.
http://bl.ocks.org/vlandham/5087480
Thanks in Advance
Initialising a position is just done by setting the cx and cy positions. The most logical place is where the radius is currently being set i.e.
.attr("r", 10)
.attr("cx", 5) //added
.attr("cy", 5) //added
Of course, you can do something more exotic if you are using the bound data to initialise position.
This will only set the starting point though - the force layout will then take over and position elements. The advantage is that you can potentially reduce some of the initial node movement if you get it right.

d3 SVG Transitions Not Always Ending At Required Value

I have a d3 visualisation on a web page that shows a collection of plot points on a chart.
It's all very simple really with just two axis and sometimes maybe 30 points to plot. As I render these plots I perform a transition on the r attributes of the SVG circles. The code that does this is:
g.append("svg:circle")
.attr("class", "plot-circle")
.attr("cx", xCo)
.attr("cy", yCo)
.attr("r", 0)
.transition()
.delay(function() { return delayInput * 100; })
.duration(plotExplosionDuration)
.ease(Math.sqrt)
.attr("r", 6);
All that occurs is that the circles are initially set to r=0 which means they aren't rendered at all. Then I start a transition on the appended circle to take this radius up to 6.
The problem is that it appears on some machines these transitions don't stop at r=6 and some plots end up being much bigger than the value set after the transition.
I simply cannot duplicate this on my main development machine (PC), my iPad nor my MacBook Pro which leads me to think it might be performance or machine load causing this?
has anyone got any ideas on how to ensure the transition stops at the defined final r value?

D3 Focus+Context via Brushing not displaying scatterplot

I'm trying to replicate this Focus+Context via Brushing example. I'm including the same layout, but with a scatterplot instead of a line/area plot.
I started working off this example I found which combines the area plot and a scatterplot. However, when I scrap the area plot, I lose the zoom/focus capability.
My last step (thus far unsuccessful) is to make the brush (small focus bar on the bottom) actually respond to the main panel (make it adjust/zoom in when smaller time periods are selected in the brush). The brush adjusts the axis as it should, but I just haven't been able to make the brush actually adjust/zoom the points on the main scatterplot. I'm not trying plot anything in the brush - there will be a lot of points, so keeping the brush with a grey background and no points is fine.
here's my fiddle: http://jsfiddle.net/fuqzp580/3/
Sidenote: I can't quite get the jsfiddle to work with the way I'm using d3.csv, so I coded up a slightly altered version with dummy data in lieu of using d3.csv. However, I included the d3.csv code (commented out), just in case that could be a cause for my problem.
I'm new to d3 so any pointers or ideas welcome!
Here's an updated fiddle with the dots zooming on the points in the main panel: http://jsfiddle.net/henbox/3uwg92f8/1/
You were very close, I just made 3 small changes:
Firstly, uncommented the code you already had in function brushed() for selecting the dots
Secondly, defined mydots globally (since you were only doing it inside initialize() and it needs to be used beyond this scope). Added this on line 55:
var mydots = focus.append("g");
And last (and most importantly), I changed the definition for xMap from
xMap = function(d) { return x2(d.time); }
to
xMap = function(d) { return x(d.time); }
When brushing, it's the x scale that gets updated, not the x2

Categories

Resources