D3 v4 graph simulation keeps dancing - force-layout

My graph contains a high number of links among a high number of nodes (300 nodes).
Since I upgrade D3 from v3 to v4 and adjusted to the new API and concepts, the graph keeps going in dancing mode.
Here is a brief screencast that shows the effect:
https://www.youtube.com/watch?v=DCkBMzs1wWI
I have tried to alternatively remove the forces below:
collide force
center force
change force
.. butt hey don't seem to be the culprit of this issue. The dancing seems to relate to the link force only.
This is how my simulation is defined:
// force definitions
this.forceCharge = d3.forceManyBody();
this.forceCenter = d3.forceCenter(1800,1200);
this.forceCollide = d3.forceCollide().radius(10);
this.forceLink = d3.forceLink().id(function(d) {return d.id;});
// simulation definition
this.simulation = d3.forceSimulation()
.force("charge", this.forceCharge)
.force("link", this.forceLink)
.force("center", this.forceCenter)
.force("collide", this.forceCollide)
.nodes(this.nodes)
.nodes(this.links)
.on("tick", this.tick)
.on("end", this.end);
It is to be said that the link strength and distance properties were modified to various settings without any help. I have tried with strength from 0.1 to 1 but that did not help either.
I have also noticed:
the simulation
The end event does not get triggered, meaning that the simulation keeps
going on for a very long time
I could call the simulation.stop() event. It does stop the dancing but I have to restart it with data changes and the dancing would start again
UPDATE:
removing the collision detection feature seems to calm down the dancing, but the resulting graph shows that most nodes overlap due tot the fact they have similar connections, creating a geometry that forces them to the same place

Related

OxyPlot performance issue on larg data in WPF on InvalidatePlot

I'm using OxyPlot in my wpf application as line recorder. It's like the LiveDemo example.
On a larg visible data set, I get some UI performance issues and may the whole application could freez. It seems to be PlotModel.InvalidatePlot which is called with to many points to often, but I didn't found a better way.
In deep:
Using OxyPlot 2.0.0
I code all in the PlotModel. The Xaml PlotView is only binding to the PlotModel.
I cyclical collect data in a thread an put them in a DataSource (List of List which are ItemSoure for the LineSeries)
I have a class which calculates cyclical in a thread the presentation for x and y axis and a bit more. After all this stuff, it calls PlotModel.InvalidatePlot.
If I
have more than 100 k points on the display (no matter if in multiple LineSeries or not)
and add 1 DataPoint per LineSeries every 500 ms
and call PlotModel.InvalidatePlot every 200 ms
not only the PlotView has performance issues, also the window is very slow in reaction, even if I call PlotModel.InvalidatePlot (false).
My goal
My goal would be that the Windo / Application is working normally. It should not hang up because of a line recorder. The best would be if it has no performance issues, but I'm skeptical.
What I have found or tested
OxyPlot has Performance guidelines. I'm using ItemsSource with DataPoints. I have also tried adding them directly to the LineSeris.Points, but then the Plot doesn’t refresh anyway (even with an ObservableCollection), so I have to call PlotModel.InvalidatePlot, what results in the same effect. I cannot bind to a defined LineSeries in Xaml because I don’t know how much Lines will be there. Maybe I missed something on adding the points directly?
I have also found a Github issue 1286 which is describing a related problem, but this workaround is slower in my tests.
I have also checked the time which is elapsed on the call of PlotModel.InvalidatePlot, but the count of points does not affect it.
I have checked the UI thread and it seems it have trouble to handle this large set of points
If I zoom in to the plot and display under 20 k Points it looks so
Question:
Is there a way to handle this better, except to call PlotModel.InvalidatePlot much less?
Restrictions:
I also must Update Axis and Annotations. So, I think I will not come around to call PlotModel.InvalidatePlot.
I have found that using the OxyPlot Windows Forms implementation and then displaying it using Windows Form integration in WPF gives much better performance.
e.g.
var plotView = new OxyPlot.WindowsForms.PlotView();
plotView.Model = Plot;
var host = new System.Windows.Forms.Integration.WindowsFormsHost();
host.Child = plotView;
PlotContainer = host;
Where 'Plot' is the PlotModel you call InvalidatePlot() on.
And then in your XAML:
<ContentControl Content="{Binding PlotContainer}"/>
Or however else you want to use your WindowsFormsHost.
I have a similar problem and found that you can use a Decimator in LineSeries. It is documented in the examples: LineSeriesExamples.cs
The usage is like this:
public static PlotModel WithXDecimator()
{
var model = new PlotModel { Title = "LineSeries with X Decimator" };
var s1 = CreateSeriesSuitableForDecimation();
s1.Decimator = Decimator.Decimate;
model.Series.Add(s1);
return model;
}
This may solve the problem on my side, and I hope it helps others too. Unfortunately it is not documented in the documentation
For the moment I ended up with calculating the time for calling InvalidatePlot for the next time. I calculate it with the method given in this answer, wich returns the number of visible points. This rededuce the performance issue, but dosent fix the block on the UI Thread on calling InvalidatePlot.

Esri Silverlight control Pan/Zoom from code

I have trouble getting Map behave properly when calling ZoomToResolution and PanTo
I need to be able to Zoom into specific coordinate and center map.
The only way I got it working is by removing animations:
this.MapControl.ZoomDuration = new TimeSpan(0);
this.MapControl.PanDuration = new TimeSpan(0);
Otherwise if I make call like this:
control.MapControl.ZoomToResolution(ZoomLevel);
control.MapControl.PanTo(MapPoint());
It does one or another (i.e. pan or zoom, but not both). If (after animation) I call this code second time (map already zoomed or panned to needed position/level) - it does second part.
Tried this:
control.MapControl.ZoomToResolution(ZoomLevel, MapPoint());
Same issue, internally it calls above commands
So, my only workaround right now is to set Zoom/Pan duration to 0. And it makes for bad UX when using mouse.
I also tried something like this:
this.MapControl.ZoomDuration = new TimeSpan(0);
this.MapControl.PanDuration = new TimeSpan(0);
control.MapControl.ZoomToResolution(ZoomLevel);
control.MapControl.PanTo(MapPoint());
this.MapControl.ZoomDuration = new TimeSpan(750);
this.MapControl.PanDuration = new TimeSpan(750);
Which seems to be working, but then mouse interaction becomes "crazy". Mouse scroll will make map jump and zoom to random places.
Is there known solution?
The problem is the second operation replaces the previous one. You would have to wait for one to complete before starting the next one. But that probably doesn't give the effect you want.
Instead zoom to an extent, and you'll get the desired behavior. If you don't have the extent but only center and resolution, you can create one using the following:
var zoomToExtent = new Envelope(point.X - resolution * MapControl.ActualWidth/2, point.Y, point.X + resolution * MapControl.ActualWidth/2, point.Y);
Btw it's a little confusing in your code that you call your resolution "ZoomLevel". I assume this is a map resolution, and not a level number right? The esri map control doesn't deal with service-specific levels, but is agnostic to the data's levels and uses a more generic "units per pixels" resolution value.

Following 3D Spiral Path

I would like to produce a realistic 3D demonstration of a ball rolling down a Conical Helix path. The reference that has helped me get close to a solution can be found here. [I am creating my solution in Actionscript 3, using Stage3D, but would be happy to have any suggested coding solutions in other languages, using other 3D frameworks, with which you may be more familiar.]
As I entered the title for my posting, the system pointed me to a wealth of "Questions that may already have your answer", and that was helpful, and I did check each of them out. Without wanting to hijack an existing thread, I should say that this oneincludes a good deal of very helpful commentary about the general subject, but does not get to the specific challenges I have been unable to resolve.
Using the cited reference, I am happy with this code snippet that traces the path I would like the ball to follow. [N.B. My reference, and most other math-based references, treat Z as being up-down; my usage, however, is the more usual 3D graphics of Y for up-down.]
This code is executed for each frame.
ft += 0.01; // Where ft is a global Number.
var n:Number = Math.pow (0.5, (0.15 * ft));
// Where s is a constant used to scale the overall path.
obj.moveTo (
(s * n * Math.cos (2.0 * ft)),
(s * n),
(s * n * Math.sin (2.0 * ft))
);
The ball follows a nice path, and owing to the lighting and other shader code, a very decent effect is viewed in the scene.
What is not good about my current implementation is that the ball does not appear to be rolling along that path as it moves from point to point. I am not using any physics engine, and am not seeking any solution dealing with collisions, but I would like the ball to correctly demonstrate what would be happening if the movement were due to the ball rolling down a track.
So, to make a little more clear the challenge, let's say that the ball is a billiard ball with the stripe and label for #15. In that case, the visual result should be that the number 15 should be turning head over heals, but, as you can probably surmise from the name of my obj.moveTo() function, that only results in changes in position of the 3D object, not its orientation.
That, finally, brings me to the specific question/request. I have been unable to discover what rotation changes must be synchronized with each positional change in order to correctly demonstrate the way the billiard ball would appear if it rolled from point 1 from point 2 along the path.
Part of the solution appears to be:
obj.setRotation ((Math.atan2 (Math.sin (ft), Math.cos (ft))), Vector3D.Y_AXIS);
but that is still not correct. I hope there is some well-known formula that I can add to my render code.

ios 6 MapKit annotation rotation

Our app has a rotating map view which aligns with the compass heading. We counter-rotate the annotations so that their callouts remain horizontal for reading. This works fine on iOS5 devices but is broken on iOS6 (problem seen with same binary as used on iOS5 device and with binary built with iOS6 SDK). The annotations initially rotate to the correct horizontal position and then a short time later revert to the un-corrected rotation. We cannot see any events that are causing this. This is the code snippet we are using in - (MKAnnotationView *)mapView:(MKMapView *)theMapView viewForAnnotation:(id )annotation
CATransform3D transformZ = CATransform3DIdentity;
transformZ = CATransform3DRotate(transformZ, _rotationZ, 0, 0, 1);
annotation.myView.layer.transform = transformZ;
Anyone else seen this and anyone got any suggestions on how to fix it on iOS6?
I had an identical problem so my workaround may work for you. I've also submitted a bug to Apple on it. For me, every time the map got panned by the user the Annotations would get "unrotated".
In my code I set the rotations using CGAffineTransformMakeRotation and I don't set it in viewForAnnotation but whenever the users location get's updated. So that is a bit different than you.
My workaround was to add an additional minor rotation at the bottom of my viewForAnnotation method.
if(is6orMore) {
[annView setTransform:CGAffineTransformMakeRotation(.001)]; //iOS6 BUG WORKAROUND !!!!!!!
}
So for you, I'm not sure if that works, since you are rotating differently and doing it in viewForAnnotation. But give it a try.
Took me forever to find and I just happened across this fix.

silverlight math performance question

Is there some reason that identical math operations would take significantly longer in one Silverlight app than in another?
For example, I have some code that takes a list of points and transforms them (scales and translates them) and populates another list of points. It's important that I keep the original points intact, hence the second list.
Here's the relevant code (scale is a double and origin is a point):
public Point transformPoint(Point point) {
// scale, then translate the x
point.X = (point.X - origin.X) * scale;
// scale, then translate the y
point.Y = (point.Y - origin.Y) * scale;
// return the point
return point;
}
Here's how I'm doing the loop and timing, in case it's important:
DateTime startTime = DateTime.Now;
foreach (Point point in rawPoints) transformedPoints.Add(transformPoint(point));
Debug.Print("ASPX milliseconds: {0}", (DateTime.Now - startTime).Milliseconds);
On a run of 14356 points (don't ask, it's modeled off a real world number in the desktop app), the breakdown is as follows:
Silverlight app #1: 46 ms
Silverlight app #2: 859 ms
The first app is an otherwise empty app that is doing the loop in the MainPage constructor. The second is doing the loop in a method in another class, and the method is called during an event handler in the GUI thread, I think. But should any of that matter, considering that identical operations are happening within the loop itself?
There maybe something huge I'm missing in how threading works or something, but this discrepancy doesn't make sense to me at all.
In addition to the other comments and answers I'm going to read between the lines a little.
In the first app you have pretty much this code in isolation running in the MainPage constructor. IWO you've create a fresh Silverlight app and slapped this code in it and thats it.
In the second app you have more actual real world stuff. At the very least you have this code running as the result of a button click on a rudimentory UI. Therein lies the clue.
Take a blank app and drop a button on it. Run it and click the button, what does the button do? There are animations attached to visual states of the button. This animation (or other animations or loops) are likely running in parrallel with your code when you click the button. Timers (whether you do it properly with StopWatch or not) record elapsed time, not just the time your thread takes. Hence when other threads are doing other things (like animations) your timing will be off.
My first suspicion would be that Silverlight App #2 triggers a garbage collection. Scaling ~15,000 points should be taking a millisecond, not nearly a second.
Try to reduce memory allocations in your code. Can transformedPoints be an array, rather than a dynamically grown data structure?
You can also look at the GC performance counters, but simply reducing the memory allocation may turn out to be simpler.
Could it be possible your code is not being inlined in the CLR by the app that is running slower?
I'm not sure how the CLR in SL handles inlining, but here is a link to some of the prerequisites for inlining in 3.5 SP1.
http://udooz.net/blog/2009/04/clr-improvements-in-net-35-sp1/

Resources