What is the `e` parameter passed to the d3.js force tick callback function? - d3.js

below is a normal example of tick function:
function tick(e) {
nodes
.each(cluster(10 * e.alpha * e.alpha));
}
who can tell me the definition of "e"? What properties does it have?
I can't find any description of "e", and what's the meaning of e.alpha. Yes, I used google but with no results.
Thanks for the help you gave below.
I'm copying some code, which use
var force = d3.layout.force()
.nodes(nodes)
.size([width, height])
.charge(-70)
.gravity(0.1)
.on("tick", tick)
.start();
so it's just the case you guess. I'm new to d3, a skim of force.layout API didn't give me any clue. Thanks for your precious time!

Without the full context of your "normal" function, this is a bit of a guess, but here goes:
tick is used in many contexts within d3. The inlcusion of alpha suggests that this is a force layout tick function, which is called by the force layout object on a tick event, in which case e would be the tick event object.
There is not a lot of documentation about the tick event, as most examples don't use it. If you inspect the source code, you will see
// A rudimentary force layout using Gauss-Seidel.
d3.layout.force = function() { //line 11
var force = {},
event = d3.dispatch("start", "tick", "end");
/* ... */
force.tick = function() { //line 58
// simulated annealing, basically
if ((alpha *= .99) < .005) {
event.end({type: "end", alpha: alpha = 0});
return true;
}
/* code to implement default force layout adjustments */
event.tick({type: "tick", alpha: alpha}); //line 128
};
/* ... */
return d3.rebind(force, event, "on"); //line 305
};
In other words, the tick event is one of three types of custom event created within the d3 source code using the d3.dispatch process. The tick event in particular is dispatched at the end of the internal tick function, and only contains one custom property: the current alpha parameter within the force layout. In order that these events actually go anywhere, the on method of the event dispatcher object is rebound on to the force layout object, so that the user can register listener functions for the custom events.
If all that is way too much d3 internals for you, just focus on these details:
e is a custom event object passed to your tick function every time it is called
e.alpha is the force layout's current alpha value, which by default starts at 0.1 and gets reduced (according to the friction parameter) at each tick until it drops below 0.005 and the layout freezes:
Internally, the layout uses a cooling parameter alpha which controls the layout temperature: as the physical simulation converges on a stable layout, the temperature drops, causing nodes to move more slowly. Eventually, alpha drops below a threshold and the simulation stops completely, freeing the CPU and avoiding battery drain. (From the API wiki for force.start)

Related

amCharts 4 - How to Access Currently-Hovered Series Data/Color in XYChart in JavaScript

I'm trying to access the currently-hovered series data and color via JavaScript. The data is available to the legend and tooltip, but I'm not sure how to directly access it.
It's possible to place the legend in an external container, but their code creates a lot of additional containers/wrappers which makes formatting difficult. This Github question addresses it, but no answer was provided.
Perhaps events could be used to detect changes in the legend text or tspan elements and then grab the new text, but I'm not sure how to do this (using amCharts events) and how efficient it would be (especially with multiple series and/or charts with synced cursors).
Another idea was to get the data based on cursor position, but this seems inefficient (cursorpositionchanged fires too often - on mouse/cursor movement even when the series data hasn't changed). Maybe it could be done more efficiently based on change in dateAxis value? For example, using the positionchanged event listener:
chart.cursor.lineX.events.on('positionchanged', function() {
// get series data and do something with it
});
At least when using chart.cursor.xAxis = dateAxis, the positionchanged event only seems to fire when the cursor jumps to a new value. So it would be more efficient than an event that fired on mouse/cursor movement.
Any suggestions would be appreciated.
UPDATE
By currently-hovered, I am referring to the series data and color accessible via the tooltip (for example) with the mouse over the chart.
Examples: CandlestickSeries and LineSeries
One method you can try is to set an adapter for tooltipText on the object of concern. Since this may run multiple times especially via a chart cursor, perhaps keep track of changes to the tooltip via monitoring the unique value, e.g. in the samples provided that would be the date field. The data you're looking for can be found in the adapter's target.tooltipDataItem. The color, if on the series, will be target.tooltipDataItem.component.fill (in the case of the line series example, the target is the line series and has no change of color, so you can just use target.fill), otherwise e.g. in the case of CandleStick series the color would be on the candle stick, or column, i.e. via target.tooltipDataItem.column.fill.
Sample adapter for LineSeries:
var tooltipDate;
series.adapter.add("tooltipText", function(text, target) {
// data via target.tooltipDataItem.dataContext
console.log('text adapter; color: ', target.tooltipDataItem.component.fill.hex);
if (tooltipDate !== target.tooltipDataItem.dataContext.date) {
console.log('new tooltip date, do something');
tooltipDate = target.tooltipDataItem.dataContext.date;
}
// note: in this case: component === target
return text;
});
Demo:
https://codepen.io/team/amcharts/pen/9f621f6a0e5d0441fe55b99a25094e2b
Sample Candlestick series adapter:
var tooltipDate;
series.adapter.add("tooltipText", function(text, target) {
// data via target.tooltipDataItem.dataContext
console.log('text adapter; color: ', target.tooltipDataItem.column.fill.hex);
if (tooltipDate !== target.tooltipDataItem.dataContext.date) {
console.log('new tooltip date, do something');
tooltipDate = target.tooltipDataItem.dataContext.date;
}
return text;
});
Demo:
https://codepen.io/team/amcharts/pen/80343b59241b72cf8246c266d70281a7
Let us know if this is making sense, and if the adapter route is a good point in time to capture changes, data, color, as well as if it's efficient enough a manner to go about this.

d3.js tween factory return function applied to non-interpolable property values

This question builds on the (correct) answer provided to this. I simply haven't been able to get any further..
With the help of an interpolator function, d3.js's tween allows smooth graphical transition between existing and new (ie to be set) DOM element values. At the simplest level, for a given animation we have a target element, an start state, an end state, a transition, a tween function and an interpolator.
Now, say I want every so often to programmatically update the contents of an input (text field) element. The value to be entered is non-interpolable (either the text is submitted, or it is not. There is no in-between state). In providing a closure (allowing for text retrieval at the scheduled transition time), tween would seem to be a good vehicle for the updates. Either I replace the interpolator with a fixed value, ensure the start and end values are identical, or find some other way of forcing it to fire at t=1. That's the theory..
To this end, in my case each property (not value) is modified in it's own update call, into which are passed transition, element index and parent element selection.
First cut:
an outer, 'governing' transition with delay values staggered using a multiple of the current element's index
playback_transition = d3.transition()
.delay(function(d, i, j) {
return (time_interval * i);
})
.duration(function() {
return 1; // the minimum
});
within a call to playback_transition.each() pass the transition as a parameter to a dependent animation by means of an update() interface
within this dependent animation, apply the transition and tween to the current element(s):
input // a UI dialog element
.transition()
.tween(i.toString(), setChordname( waveplot.chordname ));
Where:
function setChordname(newValue) {
return function() {
var i = newValue; // a string
return function(t) {
this.value = i;
inputChanged.call(this);
};
};
};
and
function inputChanged() {
if (!this.value) return;
try {
var chord = chordify.chordObjFromChordName(this.value);
purge(); // rid display of superceded elements
plotChord(chord, options); // calculate & draw chord using new input property
} catch (e) {
console.log(e.toString());
}
}
PROBLEM
While setChordname always fires (each chord is in turn correctly found and it's value stored), of the scheduled returned functions, only the first fires and results in display of the associated waveform. For all subsequent return function occurrences, it is as if they had never been scheduled.
From the display:
direct user update to the input field still works fine
only the first of setChordname's return functions fire, but, for this initial chord, carries right through, correctly displaying the cluster of associated chord and note waves.
From this, we can say that the problem has nothing to do with the integrity of the waveplotting functions.
From the console
transitions are accumulating correctly.
chord supply is all good
associated (ie initial) tween fires at t=1. (specifically, tween appears to accept omission of an interpolator function).
looking at the output of transition.toSource(), though the associated outer index increases by single figure leaps, tween itself is always paired with an empty pair of curly brackets.
transition = [[{__transition__:{8:{tween:{}, time:1407355314749, eas..
For the moment, apart from this and the initial execution, the tween factory return function behaviour is a mystery.
From Experiment
Neither of the following have any impact:
Extending the period before the initial transition takes effect
Extending (by a multiple) each staggered transition delay
Furthermore
the same transition configuration used in a different scenario works fine.
These seem to eliminate timing issues as a possible cause, leaving the focus more on the integrity of the tween setup, or conditions surrounding waveplot append/remove.
Afraid it might be interfering with input property text submission via the tween, I also tried disabling a parallel event listener (listening for 'change' events, triggering a call to inputChanged()). Apart from no longer being able to enter own chordnames by hand, no impact.
In addition to 'change', I tried out a variety of event.types ('submit', 'input', 'click' etc). No improvement.
The single most important clue is (to my mind) that only the first setChordname() return function is executed. This suggests that some fundamental rule of tween usage is being breached. The most likely candidate seems to be that the return value of tween **must* be an interpolator.
3 related questions, glad of answers to any:
Anything blatently wrong in this approach?
For a shared transition scenario such as this, do you see a better approach to transitioning a non-interpolable (and normally user-supplied) input property than using tween ?
Provided they are staggered in time, multiple transitions may be scheduled on the same element - but what about multiple tweens? Here, as the staggered transition/tween combos are operating on only one element, they seem likely to be passed identical data (d) and index(i) in every call. Impact?
I'm now able to answer my own question. Don't be put off by the initial couple of paragraphs: there are a couple of valuable lessons further down..
Ok, there were one or two trivial DOM-to-d3 reworking issues in my adoption of the original code. Moreover, an extra returned function construct managed to find it's way into this:
Was:
function setChordname(newValue) {
return function() { <--- Nasty..
var i = newValue;
return function(t) {
this.value = i;
inputChanged.call(this);
};
};
};
Should have been:
function setChordname(newValue) {
var i = newValue;
return function(t) {
this.value = i;
inputChanged.call(this);
};
};
The fundamental problem, however, was that the transition -passed in as a parameter to an update() function- seems in this case to have been blocked or ignored.
Originally (as documented in the question) defined as:
input // a UI dialog element
.transition()
.tween(i.toString(), setChordname( waveplot.chordname ));
..but should have been defined as:
transition
.select("#chordinput") // id attribute of the input element
.tween(i.toString(), setChordname( waveplot.chordname ));
My guess is that the first version tries to create a new transition (with no delay or duration defined), whereas the second uses the transition passed in through the update() interface.
Strange is that:
what worked for another dependent animation did not for this.
the staggered delays and their associated durations were nevertheless accepted by the original version, allowing me to be misled by console logs..
Just to round this topic off, I can point out the the following (event-based) approach seems to work just as well as the tween variant with non-interpolable values documented above. I can switch freely between the two with no apparent difference in the resulting animations:
transition
.select("#chordinput") // id attribute of the input element
.each("start", setChordname( waveplot.chordname ));
Thug

How to create slow simultaneous transitions of multiple attributes in force directed graphs?

In a previous post called "D3: How to create slow transition of Circles for nodes in Force Directed Graphs FDG?", I got a great answer for how to transition a single element (e.g. the radius for "just circles") in D3.
My followup question is now about how to transition "multiple D3 attributes" at the same time...
As a reminder, I'm using D3 generated Radio Buttons to toggle the size of Nodes in a FDG Layout (on mouse click) from a default size to a scaled magnitude. You can find the Radio Buttons in the upper left hand of the Node Cluster Diagram (http://nounz.if4it.com/Nouns/Applications/A__Application_1.NodeCluster.html)
The code that toggles the node circles between a default number and a scaled magnitude (now using transitions) looks as follows...
var densityControlClick = function() {
var thisObject = d3.select(this);
var typeValue = thisObject.attr("density_type");
var oppositeTypeValue = (function() {
if(typeValue=="On") {
return "Off";
} else {
return "On";
}
})();
var densityBulletSelector = "." + "densityControlBullet-" + typeValue;
var selectedBullet = d3.selectAll(densityBulletSelector);
selectedBullet.style("fill", "Black")
var oppositeDensityBulletSelector = "." + "densityControlBullet-" + oppositeTypeValue;
var selectedOppositeBullet = d3.selectAll(oppositeDensityBulletSelector);
selectedOppositeBullet.style("fill", "White")
if(typeValue=="On") {
var selectedNodeCircles = d3.selectAll("#NODE");
selectedNodeCircles.transition().duration(500).attr("r", function(d){ return rRange(d.rSize); });
}
else {
var selectedNodeCircles = d3.selectAll("#NODE"); selectedNodeCircles.transition().duration(500).attr("r", function(d) { if (d.id==focalNodeID) { return centerNodeSize; } else { return defaultNodeSize; } } );
}
}
Everything works great and you can see the slower node transitions when you select the radio buttons. However, I'd now like to learn how to transition multiple elements, such as the the radius and the edge lengths simultaneously, along with the theory behind doing so, in order to show off D3's dynamic nature.
My question is: Given that I already can successfully transition the radius of circles, how would I also transition other elements like the edge lengths based on attributes like "alpha", "friction", etc., and... what's the theory behind transitioning multiple elements (in other words, what does the code mean, in English)? The D3 API doesn't appear to clearly get into the theory behind transitioning multiple attributes, simultaneously.
So transitioning multiple attributes is the simple part of this question. Just like a regular selection you can set multiple attributes at a time on your transition:
selectedNodeCircles.transition().duration(500)
.attr("r", function(d){ return rRange(d.rSize); })
.attr("stroke", 'red');
This will transition your radius and your line colour. The transition is a property of the DOM element (in this case the circle) and it will transition as many DOM attributes as you like. The thing to remember is that there is only only one transition object on each DOM element. So if you create another you will overwrite the old one.
// This will NOT work
circles.transition().duration(1000).attr('r', 50);
// The radius transition will be overridden by the fill
// transition and so will not complete
circles.transition().duration(1000).attr('fill', 'red');
This can actually be quite useful because you don't have to worry about interrupting animations that are in progress and figure out how far along they are and then starting a new animation - this will generally be handled automatically.
In your case you want to transition edge lengths in your graph. These are determined by the positional attributes of the nodes. Judging by your finished product, these attributes are already being animated because you are updating the DOM on every iteration of the layout algorithm (not through transitions) probably in the tick() callback.
So you could use transitions inside your tick callback, which might look odd and may be a hassle to keep in synch with the radius transitions (you will have to set both attributes in the transition). But it might be just what you need.
Alternatively, if you can wait, don't update the DOM in the tick callback. Let the layout complete - it runs a lot faster when it is not rendering on each tick - and once it is complete you can animate the radius and x and y attributes to their final positions. Of course this means you'll want good starting positions.

change initial zoom in D3.js node graph

I try to change the default scale of the NodeGraph here so it fits in the screen on first load. It is written with D3.js. Is there an initial variable, that defines the zoom?
You can set a suitable transform on the top-level g element, e.g. g.attr("transform", "scale(0.8)").
I managed to change the initial gravity, which makes the zoom not needed anymore:
// Gravity at pageload:
initial_gravity=0.07; // to apply a change here, enter `make` in you terminal
var force = d3.layout.force()
.charge( function (d) {
if (d.flags.client)
return -30 * chargeScale
return -100 * chargeScale
})
.gravity(initial_gravity)
....
afterwards you need to call make at the console to apply the changes

Example on how to control tweens using Ticker in CreateJS

I'm working with CreateJS and wondered if anyone here has examples of controlling tweens using the Ticker object. I'm trying to get a sprite to follow a path defined by waypoints but i don't want to control each tween (in between waypoints) by time. I want to have smooth movement between each waypoint controlled by the Ticker object. I tried this code which doesn't seem to work at all.
var index = 0;
function move(){
index++;
if (index < path.length) {
createjs.Tween.get(person)
.to({x:gridSize * path[index][0] - pathOffset,y:gridSize * path[index][1] - pathOffset})
.call(move);
}
}
move();
createjs.Ticker.setFPS(30);
createjs.Ticker.addEventListener("tick", function(event){
createjs.Tween.tick(1);
stage.update();
});
This code seems to only jump between waypoints and not tween at all. Any ideas what i may be doing wrong or any code/tutorials which might help?
You need to add a duration(in milliseconds) to your tween, otherwise it would default to 0, this will cause the "jump", e.g.: 500 for half a second
instead of: .to({x:..., y:...})
use: .to({x:..., y:...},500)
And a second thing: You don't NEED to call createjs.Tween.tick(1); this is usually called automatically by the Tween-class.
Here is some help and some small examples: http://www.createjs.com/Docs/TweenJS/classes/Tween.html
Advanced Examples:
https://github.com/CreateJS/TweenJS/tree/master/examples

Resources