Skip to content

BUG: Figure breaks after animating a property of an array element #2228

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
jonmmease opened this issue Dec 29, 2017 · 4 comments · Fixed by #2324
Closed

BUG: Figure breaks after animating a property of an array element #2228

jonmmease opened this issue Dec 29, 2017 · 4 comments · Fixed by #2324
Assignees
Labels
bug something broken

Comments

@jonmmease
Copy link
Contributor

It seems that something goes wrong when using Plotly.animate to change a property of an array element. I hit this while working on a custom trace type, but it is reproducible on the Parallel Coordinate trace.

Note: I understand animated transitions are not supported for the Parallel Coordinates trace, but my expectation is that an animate command shouldn't cause an error and should behave like a relayout/restyle command.

Parallel Coordinate Example Pen: https://codepen.io/anon/pen/ZvKGxW

Summary:

  • Animating a change to line.color works fine
  • Restyling a change to dimensions[0].constraintrange works fine
  • Animating a change to dimensions[0].constraintrange breaks the plot (Nothing shows up afterward)

Example code for reference:

var trace = {
  type: 'parcoords',
  line: {
    color: 'blue'
  },
	
  dimensions: [{
    range: [1, 5],
    constraintrange: [1, 2],
    label: 'A',
    values: [1,4]
  }, {    
    range: [1,5],
    label: 'B',
    values: [3,1.5],
    tickvals: [1.5,3,4.5]
  }]
};

var data = [trace]

Plotly.plot('graphDiv', data).then(function() {
	// ## This animate command works as expected (line turns red) ##
	// Plotly.animate('graphDiv', 
	// 			{data: [{'line.color': 'red'}],
	// 			 traces: [0],
	// 			 layout: {}})
	
	// ## This restyle command works as expected (constraintrange extends to [1, 4]) ##
	// Plotly.restyle('graphDiv', {'dimensions[0].constraintrange': [[1, 4]]}, 0)
	
	// ## This animate command breaks things and the plot doesn't show up ##
	Plotly.animate('graphDiv', 
                                {data: [{'dimensions[0].constraintrange': [1, 4]}],
                                  traces: [0],
                                  layout: {}})
});
@etpinard etpinard added the bug something broken label Dec 29, 2017
@monfera
Copy link
Contributor

monfera commented Jan 18, 2018

Indeed the parcoords trace is currently not set to module.animatable.

@etpinard the animation function plots.js:prepareTransition invokes plots.supplyDefaults

plots.supplyDataDefaults(newData, newFullData, newLayout, newFullLayout);

where newData is

image

ie. its dimensions array has only one element, and its single property is constraintrange.

As I'm not too familiar with the animation internals and it's not going through the Plotly.restyle path, how should we move forward? I'm wondering if maybe parcoords / defaults.js should somehow retrieve the current state (ie. all dimensions, full with details with the change that is a constraintrange on a single dimension? (In this case we must also know which element of dimensions is getting updated.) An obstacle is that defaults.js has no awareness of the preexisting values. The structure of parcoords, especially the representation of dimensions is not like most other plots so maybe the change should be made more upstream, but I don't have a good handle on where. I can go further but maybe you have preferences for how to solve this.

@etpinard
Copy link
Contributor

The fix must be done inside the Plots.transitions helpers most likely in Plots.computeFrame. All trace types should work with Plotly.animate the fallback being an equivalent restyle, relayout or update call.

@monfera
Copy link
Contributor

monfera commented Jan 18, 2018

Thanks @etpinard! Currently Plots.computeFrame doesn't get called for this specific case, because it doesn't match the type:
image

image

Planning to add a branch there that'd handle dimensions and most likely, make that branch call Plots.computeFrame.

@monfera
Copy link
Contributor

monfera commented Jan 31, 2018

Circling back to this one, just jotting down where I am, also if someone has a firm idea on the best way for fixing it, please tell me.

During animation, the change src === {dimensions[0].constraintrange: [32000, 40000]} is merged into the preexisting data dest in plots.extendObjectWithContainers. As a result of this, all but index [0] of the preexisting dimensions get eliminated; dimension index [0] gets overwritten with src ie. its preexisting other properties are gone too. This is why the new render draws a blank.

In contrast, when calling the restlye function, it uses ultimately npSet, invoked in _restyle with the result that

  • all dimension elements remain in place
  • the item with index [0] also remains well-preserved, except the change represented by the restyle

I think this is the cause for the differing outcome between animation and restyling. As both of these spots are part of multi-hundred line code step sequences, and both are rather critical, I'd like to get input on how to proceed. My natural inclination would be to understand why animations don't use the same code bit for the "patching" as restyling, which might be written in the code and I missed it, or would need to ask; then, depending on the answer, either make animations call this gentler npSet merger or would run out of ideas, as making an explicit exception for dimensions would feel like a hack.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug something broken
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants