I can animate six circles, and I can animate a line. When I try to animate both, I cannot figure out what init() and animate() should return. For six circles I "return tuple(pins)" and for the line I "return line,". Each pin is a "class 'matplotlib.patches.Circle'" and the line is "class 'matplotlib.lines.Line2D'."
When I try to animate both the circles and the line, I have tried many different return statements without success. Here are the some of the results:
return line, tuple(pins) GIVES 'tuple' object has no attribute 'set_animated'
return tuple(pins) + (line) GIVES can only concatenate tuple (not "Line2D") to tuple
return tuple(pins) + tuple(line) GIVES 'Line2D' object is not iterable
Note that you only need to return something from the animating function if you use blitting.
From the documentation:
If blit == True, func must return an iterable of all artists that were modified or created. This information is used by the blitting algorithm to determine which parts of the figure have to be updated. The return value is unused if blit == False and may be omitted in that case.
So just ommiting the return altogether may be the easiest option.
If you need/want to use blitting, you need to return an iterable of artists. This can e.g. be a tuple or a list. Unfortunately, it's not clear what pins is from the question.
Supposing pins is a list,
return pins + [line]
or if you want to make it a list,
return list(pins) + [line]
Supposing pins is a tuple,
return pins + (line,)
or if you want to make it a tuple,
return tuple(pins) + (line,)
Related
My dilemma is this:
I have a spaceship positioned somewhere in space between stars and planets. The camera is added as a child of the spaceshipNode and you always look at the back of the spaceship (raised a few units above).
I use CoreMotion to rotate the spaceship like this:
func startMonitoringMotion() {
self.motionManager?.startDeviceMotionUpdates(to: OperationQueue.main, withHandler: { (data, error) in
guard let data = data else { return }
let attitude: CMAttitude = data.attitude
self.ship.eulerAngles = SCNVector3Make(Float(attitude.roll - M_PI_2), Float(attitude.yaw), Float(attitude.pitch))
})
}
and the rotation works as expected.
Now I want to move the spaceship in the direction it is facing but I have no clue how to do it. I have tried different approaches but I have failed miserably.
I have searched this forum countless times for several days but with no luck.
I hope someone can point me (and my spaceship) in the right direction.
Thank you in advance.
I've found that the easiest way to do this is to grab the third row of the node's worldTransform property, which corresponds to its z-forward axis.
func getZForward(node: SCNNode) -> SCNVector3 {
return SCNVector3(node.worldTransform.m31, node.worldTransform.m32, node.worldTransform.m33)
}
ship.position += getZForward(ship) * speed // nb scalar multiply requires overload of * func
// if node has a physics body, you might need to use the presentationNode, eg:
// getZForward(ship.presentationNode)
// though you probably don't want to be directly modifying the position of a node with a physics body
See the discussion here Getting direction that SCNNode is facing
iOS 11 update
iOS 11 adds handy convenience functions for getting the orientation of a node. In this case the worldForward property is the one you want. Also, all of the properties on SCNNode that return SCNVector and matrix types now have versions that return simd types. Because simd already has overloads for the arithmetic operators, you no longer need to add sets of arithmetic overrides for the SCNVector and SCNMatrix types.
So we can get rid of out getZForward method above, and just have the line:
ship.simdPosition += ship.simdWorldFront * speed
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
I have a composite graph of two line charts. For one of them i'm attempting to apply a custom color range based on the value of each point on the line:
.colors(['rgb(215,48,39)','rgb(244,109,67)','rgb(253,174,97)','rgb(254,224,144)'])
.colorDomain ([0,3])
.colorAccessor (d,i) ->
if d.points[i].data.value.avg > 50
return 0
else
return 3
The problem is I keep getting only one color for the entire graph... Not to mention d returns as an object of all the points instead of a single point... (maybe a hint of the problem?)
Am i doing something wrong here and/or is there an easier way to do this?
You didn't get an answer so I'll try to look into it with you.
First, I created a fiddle at http://jsfiddle.net/djmartin_umich/4ZwaG/.
.colors( ['rgb(215,48,39)', 'rgb(244,109,67)', 'rgb(253,174,97)', 'rgb(254,224,144)' ] )
.colorDomain ([0,3])
.colorAccessor(function(d, i){
if(d[i] && d[i].data.value > 150)
return 3;
else if(d.data.value > 150)
return 2;
else return 1;
});
I had to play around with the color accessor to get it to stop throwing errors. The method was called twice with an array of elements and twice for each element in the array (24 times total).
Once I got it compiling I inspected the chart and saw this:
The chart has a path element that defines the line and a bunch of circles that define the points on the line. The points are part of the tool-tip that display when you hover over the different points on the line.
The path seems to be colored by the value returned when the array of values was passed in and the hover-points on the line are each colored by the value returned for that element.
So the path of the line is given a single color. It sounds like your expectation is for different portions of the line to be colored differently based on their y-value, but this is not how the line is rendered.
The article at http://www.d3noob.org/2013/01/applying-colour-gradient-to-graph-line.html describes how you can use gradients to achieve the effect you desire. I believe the author is "hard-coding" the start and stop points for each gradient, so it won't get you all the way to your answer but it should help you get started.
I hope this helps!
-DJ
I am trying to create an animated line graph where the line draws out its path from left to right, as in the first scene of this example. I have been closely following the code for mbostock's example, but still am having a couple issues.
When I try to run my code, I get an error saying "'d' is undefined", in the attr method inside the draw function shown below:
var line = d3.svg.line()
.interpolate('linear')
.x(function(d,i) {return x(i);})
.y(function(d,i) {return y(d['measures'][i]);});
chart.append('path')
.attr('class','line')
.data(array);
function draw(k) {
chart.select('.line')
.attr('d',function(d) { return line(d.measures.slice(0,k+1));});
}
var k=1, n = array.measures.length;
d3.timer( function() {
draw(k);
if((k+=2) >= n-1) {
draw(n-1);
//next transitions
return true;
}
This leads me to believe that my data has not been correctly bound to the path. However, I can't seem to understand why it would not be binding correctly
Any help would be much appreciated!
The example you picked as a starting point is binding the data for each ticker symbol to a <g> element, and then within each of those it's creating lines, etc. based on child data of that ticker. The .selectAll and .data methods are used when you're binding a list of data to a list of DOM nodes (e.g. <circle>, <rect>, <g>). But <path> is just a single DOM node with a long string of path data for rendering the line. You call the line function once to give you that string.
So for your purpose, if you just have one line that you're trying to animate, you just call your line function directly in order to create the path string to set on that node. There is no existing data bound to the node that you're trying to reuse. In your draw function:
.attr("d", line(array.measures.slice(0,k+1)))
Your line function itself needs slight adjustment too, assuming that array.measures contains a simple array of numbers:
var line = d3.svg.line()
.interpolate('linear')
.x(function(d,i) {return x(i);})
.y(function(d,i) {return y(d);});
BUT, having said all that, I think you would be better served by starting from a simpler example such as http://bl.ocks.org/duopixel/4063326 or one of the other approaches listed in this question or this question. It's hard to separate just the animated line portion of your original example from the rest of the cool stuff it's doing.
I am trying to use d3 to animate text using an svg text with d3 transitions. I have it working as desired for a single string.
I want to iterate through strings from an array of json objects.
I can do this as well.
All the painting and transitions work great. Problem is, they all happen at once, and appear piled up on each other, and all animate all at once.
I have tried putting them in a setTimeout() to get them to appear sequentially.
Still does not work.
for ( i in haikuStr ) {
if( i !=0 ){
//Make it wait if an appropriate time it is not the first one
setTimeout( function() {
showText();
}, 11000 * i );
} else {
//if i=0, don't make folks wait
showText();
}
}
The showText() function is the full create container -> finish transitions.
I use 11000 * i to ensure that >2 iterations have 11 additional seconds per i.
I have spent quite a bit of time reading and trying to figure out how to get the loop to pause before cycling through to paint the next line.
Any thoughts or ideas would be appreciated.
The un-timed example is here, if you wish to see the text jumble up:
http://www.mysalmagundi.com/js/svg-d3-no-timing.html
Have you read Thinking with Joins? Or some of the other introductory D3 tutorials, such as those by Scott Murray? Or Three Little Circles, or Working with Selections? I ask because your showText function is misusing data joins; it creates text elements for every element in the global haikuStr array:
var text = haikuContainer.selectAll("text")
.data(haikuStr)
.html(String)
.enter().append("text");
And all your text elements are overlapping because you set them to have the same y-attribute:
var thisHaiku = text
.attr("x", -800)
.attr("y", 120)
(Also, that selection.html call is a no-op because the update selection is guaranteed to be empty, since you just created haikuContainer it is guaranteed to not have any descendant text elements. And thisHaiku is the same value as the var text, because when method chaining selection.attr and similar methods return the current selection; so there’s no reason to create a separate var. Also, you shouldn’t use a for-in loop to iterate over arrays.)
If you wait 11 seconds, you’ll see the second SVG appear, but because of your data join as described above, it has the same overlapping text content.
If you just want to show a single piece of text, then pass that string to your showText function (e.g., showText("hello")). Then, since you’re just creating individual elements, just selection.append them rather than using a data-join. You only need the data-join when you’re creating (or updating or removing) a variable number of elements based on data; in this case it looks like you’re trying to just create a single element.