Yesterday Plotly release the new feature animation!!! So I was very eager to test this out, and with the current lack of documentations (temporary I suppose) I'm struggling quite a bit on how to use it.
I did have a peek into the code on GitHub, but ... not working.
I define my div element in the template:
<div id="plotDiv"> </div>
I wanted to have the plot responsive to resize events, thus I followed the example on the plotly website:
const d3 = Plotly.d3;
const gd3 = d3.select("#plotDiv")
.style({width: "95%", "margin-left": "2.5%"});
const gd = gd3.node();
Then generate the data (bits of angular magic and other things) but in the end it looks like this:
data = {x: [array_ot_dates], y: [array_of_not_so_random_values], type:'bar'};
According to the jsdocs for the animation function, you need to pass a frame:
let plotlyFrame = {data:data, layout:{}};
Try to call animation!!!
Plotly.animate(gd, plotlyFrame);
And there it goes Kaboum!
First error is: This element is not a Plotly plot: [object HTMLDivElement]
But when I try this:
Plotly.newPlot(gd, data, {});
I have my plot...
So I tried to "predefine" gd by calling Plotly.plot with empty data and then the animate function...
Plotly.plot(gd, [], {});
// make my data not empty
Plotly.animate(gd, plotlyFrame);
And then I get the following error:
plotly.js:116922 Uncaught (in promise) TypeError: Cannot read property '_module' of undefined(…)
Possibly the second could come from the fact I'm using angular and thus calling the function at one point 3 times in a close row.
Any advices? Ideas?
I'm the person who worked on the animation feature! First of all, you can find the documentation here.
Regarding your specific question, it looks like the answer is that you need to initialize the plot before you animate it (I'll add this to the documentation!). For example:
var frame = [{
data: {
y: [...new values...]
}
}]
Plotly.plot(gd, [{x: [...], y: [...]}]).then(function() {
Plotly.animate(gd, frame)
});
If some sort of user input is triggering the animation, the promise probably isn't necessary (since the input event will handle things and is pretty unlikely to get fired before Plotly.plot has had a chance to initialize).
Additionally, at the very least I believe you'll need to actually initialize the plot with the trace you wish to animate. I think you can probably get away with empty data, but you'll still need to at least have a trace defined, e.g. Plotly.plot(gd, [{x: [], y: []}]). I think the issue with your attempted fix is that [] for a list of traces is still empty as far as Plotly is concerned since that tells it nothing about the type of trace that exists. Also FYI, one thing the feature is not really designed to do is to draw the initial plot in a fancy manner. That could likely be accomplished, but it's not automatic given animate on an empty plot.
I hope that's enough to clarify issues! It was a pretty large feature, so we'd love feedback and to hear about successes/failures with it!
Related
Question:
I've been using the AutoDesk View and Data API, and I've been curious to know if it was possible to return geometric information about a selected element. Ideally, I want the position, size, angle, type of shape, etc., of a selected element so that I could compare, for instance, two lines. I don't mind how this information is represented, so long as two shapes could be compared.
Objective:
If there was a line, such that (psuedo-representation):
(x1=0,y1=0),(x2=10,y2=0), a 2d straight line of length 10;
and another line, such that:
(x1=20,y1=20),(x2=30,y2=20), another 2d straight line of length 10.
Then I would be able to say that these two lines are similar from this information and deduce their angle. There would obviously need to be some indication of the type of entity that is selected also. That's the desired outcome of my question.
What I've tried:
So far, I've found several useful functions within Viewer3d.js, but none seem to return any data about the geometric position of a single selected shape:
Viewing.Extension.SomeExtension = function (viewer, options)
{
...
var shapeRenderData = viewer.impl.getRenderProxy(viewer, dbId);
var shapeFragmentData = viewer.impl.getFragmentProxy(viewer, dbId);
}
I already understand how to include the onSelect event, and that is left out for clarity of the question.
Both of these return a JSON object with properties of fragId, scale, quaternion and position - although with exception of fragId, these properties have null values.
Extra:
I am basing the extension I've created off of this GitHub tutorial from the AutoDesk team:
https://github.com/Developer-Autodesk/tutorial-getting.started-view.and.data/blob/master/chapter-3.md#Step5
Please note the fifth step includes code for the onSelect event I'm discussing, should you wish to recreate the question to help me solve this.
I've wrote that blog post about geometry snapping and selection commands. I think it should provide some elements of answer to your question:
Geometry snapping and selection commands with View & Data API
This question builds on Lars Kotthoff's very helpful answer to the problem of transitioning with a D3 sunburst diagram that is based on different JSON data: d3 - sunburst - transition given updated data -- trying to animate, not snap
I've tried the final fiddle that Lars provided but when there is more than one transition, the animation still fails and we get snapping. The problem can be seen in this updated fiddle that contains a second transition.
From what I can tell, the x0 and dx0 values are not properly stored with the path object when calling the arcTweenUpdate function. When I check what the this object looks like inside arcTweenUpdate function, I get an [object SVGPathElement] at the beginning of the function when this.x0 and this.dx0 are read, and I get an [object Window] when the new values are written later. I'm relatively inexperienced with JS but that seemed like it could point to the problem.
Any help with addressing this and making the above fiddle work for multiple transitions (e.g. back and forth between the two JSONs) is highly appreciated. Thanks!
Well you've spotted a bug in my earlier answer :)
The problem is, as you say, that the saved values aren't updated properly. That's because this inside the callback doesn't refer to the path DOM element anymore. The fix is simple -- save a reference to this in the function at the level above and use that reference:
function arcTweenUpdate(a) {
var i = d3.interpolate({x: this.x0, dx: this.dx0}, a);
var that = this;
return function(t) {
var b = i(t);
that.x0 = b.x;
that.dx0 = b.dx;
return arc(b);
};
}
Complete demo here.
I want to move nodes in Sigma JS on click event. Say from position x 0.7 to position x -0.7.
Is it possible to move nodes in Sigma js, and if it is, kindly guide me to achieve that.
Yes, it is possible. I created a jsfiddle showing how to change node position, size, and color on mouse click here:
http://jsfiddle.net/kaliatech/P255K/
You can bind to custom "downnodes" events like this:
sigInst.bind('downnodes',onNodeDown);
The event callback contains an array of selected node ids. I don't know when it would be more than one when clicking. Perhaps when zoomed out in a complex graph.
One of the more subtle issues when using sigmajs, is that most methods, such as getNodes, return clones, not the instances themselves. This is to protect "private" data in the graph I think, especially data that can not be redrawn after initialization. To actually modify properties, you need to use the iterator methods. Even then, you are only given clones. The library updates the actual node instances using a list of predefined allowable properties. (See the checkNode function in graph.js).
After properties have been set, you then need to refresh/redraw the graph. While the "refresh" method would seem to be an obvious candidate, it did not work. I was able to get it to redraw using the draw method though. You will need to review the source code to understand the different parameters. Example:
function onNodeDown(evt) {
var sigmajs = evt.target;
var nodeId = evt.content[0];
sigmajs.iterNodes(function(n){
n.size = 10;
n.color = "#0000FF";
},[nodeId]);
sigmajs.draw(2, 2, 2, true);
};
For more advanced needs, the sigmajs website includes plugin examples showing other ways of getting mouse events and updating nodes dynamically. One is the advanced plugin example for a fisheye effect:
http://sigmajs.org/examples/a_plugin_example_advanced.html
Another is the example for accessing node attributes:
http://sigmajs.org/examples/more_node_info.html
The sigmajs documentation is weak, so you will need to review the source code to understand things.
There are plugins permitting to move isolated nodes from the graph.
Check
https://github.com/Linkurious/linkurious.js/blob/develop/examples/lasso.html
I'm trying to add an indicator to my vertical gauge but the format of the indicator is like a triangle, but I want it a large line.
This is JSFIDDLE example.
The code :
require(['dojo/parser', 'dojox/dgauges/components/default/VerticalLinearGauge','dojox/dgauges/RectangularRangeIndicator', 'dojo/domReady!'], function (parser, VerticalLinearGauge) {
parser.parse();
var ri = new dojox.dgauges.RectangularRangeIndicator();
ri.set("start",0 );
ri.set("value", 30);
ri.set("startThickness",100);
ri.set("endThickness",100);
gauge.getElement("scale").addIndicator("ri", ri, false);
});
This is a bug, it will be fixed in next releases (1.8.x and 1.9).
See https://github.com/dmandrioli/dgauges/issues/15
As a workaround, you can redefine the bad method like this:
myRangeIndicator._defaultVerticalShapeFunc =
function(indicator, group, scale, startX,
startY, endPosition, startThickness, endThickness,
fill, stroke){ ... }
See this workaround in action at http://jsfiddle.net/BFPuL/5/
I think that the properties are startThickness and endThickness (no "stroke" at the end). However, I still don't get one solid line when setting these properties to equal values like one would expect. It seems as though something odd (perhaps a bug) is happening with the way that the startThickness property is handled.
This problem has me interested, so I'll try to set aside some time later to dig into the source to see what the real issue is, but for now I can offer you a dirty workaround. The RectangularRangeIndicator is drawn using the dojox/gfx module, and the outline of the indicator drawn is controlled by the stroke property. So, if you want, you can do something like:
var ri = new dojox.dgauges.RectangularRangeIndicator();
ri.set("start",0 );
ri.set("value", 30);
ri.set("startThickness", 0);
ri.set("endThickness", 0);
ri.set("stroke", {color: "red", width: 2.5});
ri.set("paddingLeft", 7); // Default is 10, set this to whatever works for you.
This will appear to draw straight line (which is really the border of an extremely thin shape). Check out how it looks in a real example. Again, I understand that this is not the best solution since it is more of a dirty trick, but it is a way around what appears to be a bug in the code that renders a range indicator.
I'm using d3.js to make a simple line graph. I want to know if there's a way to create "holes" in the graph, that is, if the line can be interrupted or cut when there is no data available.
I'm looking into either delete the places I don't need from the domain, or setting the line weight to 0 in specific segments, but I can't find a way to do either of these.
Thanks for your help!
The D3 line generator has a built in function to do just this, line.defined. You can use this function to control where your line is defined and where it is not (like where you have missing data.) If you wanted to make your line undefined whenever the second value in the point array is a javascript NaN value, you could say:
line.defined(function(d) { return !isNaN(d[1]); });
Here is a good example of this in action.