-
-
Notifications
You must be signed in to change notification settings - Fork 112
Proper trace type initialization in TraceSelector component #196
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
Conversation
0e2cc1a
to
5cc424c
Compare
ok, so I removed mode: 'markers' from examples/simple/App.js in the initial figure, as well as in PlotlyEditor.js' EDITOR_ACTIONS.ADD_TRACE. Instead, on componentWillMount, will initialize the right value in the TraceSelector dropdown because I am calling updatePlot with the right Plotly.js initialization attributes. I am not calling it on componentWillReceive props because this.setLocals calls it, internally. I've changed the plotlyTraceToCustomTrace function to take gd.data instead of gd._fullData, in that way I'm only going to evaluate to a line trace if trace.mode exists in gd. @bpostlethwaite, is this good? |
package.json
Outdated
@@ -13,27 +13,19 @@ | |||
"url": "https://github.com/plotly/react-plotly.js-editor/issues" | |||
}, | |||
"scripts": { | |||
"make:combined-translation-keys": |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does your prettifier act on json as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, it shouldn't? It was from the start..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmmm I haven't configured prettier to handle JSON in this lib. Not sure which rule sets it would be applying. I was imagining only targeting stuff in src
. It wouldn't be a bad thing to prettify the json
but we don't have CI tests to test this so our styling could end up fighting without an arbiter.
componentWillMount() { | ||
const {container} = this.props; | ||
const value = plotlyTraceToCustomTrace(container); | ||
this.updatePlot(value); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we only want to do this if the mode isn't set though right? Also you are setting a custom trace type in user data which will break soon as they take their plot out of the editor app
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
don't we want to aggressively set this in componentWillReceiveProps? What if the user at some random future time supplies {x: [1], y: [1]}
in the gd.data?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm calling updatePlot every time TraceSelector mounts, to make sure, that in any situation, the proper defaults are sent to plotly.js.
So, in the case that a user starts out with x: [], y: [], type: 'scatter', before TraceSelector mounts, updatePlot will be called with {x: [], y: [], type: 'scatter', mode: 'markers'}, that way, on the next call to updatePlot, if the user provides new props of x: [1], y: [1], mode will already have been set to 'markers'
This is the reason I don't need to call this in componentWillReceiveProps, is this ok?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is usually better practice to only send an update if you have to send an update but it probably won't be that costly so most likely won't make much of a difference.
If you only call the function on component mount how will we aggressively repair a trace {x: [1], y: [1]}
that comes into being on gd.data when this component is already mounted? If it is already mounted it won't send another update and this new trace will not be modified.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is usually better practice to only send an update if you have to send
I DO have an update to send, I want to send the mode update, so that regardless of whether I have an empty state or a full one, the mode is set in gd.data.
So when x: [], y: [] changes to x:[1], y: [1] nothing additional needs to happen in componentWillReceiveProps because componentDidMount already set the mode in gd.data, and its gd.data that I use for trace recognition.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll slack you. I don't think I am communicating this effectively
Actually, there's a situation unaccounted for here: when the user actually wants mode: 'lines+markers' and they didn't think to set mode in gd.data because it's the plotly.js default, they didn't think they needed to. So now, if we're using the editor in streambed, how am I supposed to differentiate between having to change mode on figure initialization, and not changing anything because the loaded figure actually wanted a trace with mode: 'lines+markers' In streambed we initialize our figure explicitly with the mode we want, we should do so here too. As for the empty state So I propose to change back to explicit mode setting in figure initialization, and that along with checking gd.data when recognizing trace types, should prevent us from mixing up trace types. streambed initialization: https://github.com/plotly/streambed/blob/2d9bd322e177c2eb3f4206ea95b86984247be4cd/shelly/webapp/static/webapp/src/workspace/reducers/partialStateWorkspace.js#L399 |
Good catch @VeraZab - I think this is what you're saying, but just to be sure, it seems like there are two distinct cases based on how we arrive at the figure:
|
yup @alexcjohnson correct, that is what I'm saying. I'll make the changes now. |
7eb3e19
to
f59614c
Compare
so, just so that we're sure that everything's updating correctly, I've tried adding a call to updatePlot just like in componentWillMount, but when I try to do so, I'm caught in an infinite loop, the apps don't render. I think that it may have to do with the lifecycle of react-select, but honestly, I'm a little mixed up at this point, this call to componentWillReceiveProps doesn't seem to be needed. I see that the TraceSelector component rerenders even when DataSelector components are changed, so I can see that rerendering works correctly, even if I'm not exactly sure how this is happening. so I've pushed up what I've got so far, which seems to be working, if @bpostlethwaite you see a situation that this fix doesn't cover, could you give me an example, so that I can fix something more concrete. I would have added a call to updatePlot in componentWillReceiveProps, but it's breaking the app. |
what were the conditions you were you calling |
if you don't put a conditional around it then it will fire, the app will rerender, and it will fire again and yeh infinite loop. But if you have something like
Then shouldn't it reach a stable state on second time around? Ie this conditional will fail and we won't send a new update. |
Then again there is this chilling warning on this pattern https://hackernoon.com/evil-things-you-do-with-redux-dispatch-in-updating-lifecycle-methods-ad116de882d4 |
How else could we do this... We do this to some effect in webapp.
type patterns. |
🙈 forgot about the conditional in componentWillReceiveProps.. |
Does this PR make the default line or scatter? Seems to be line, but in the webapp we pick scatter no? |
mode has to be explicitly set to 'markers', because now we're covering the situation of a plot loaded through api, where the user might have intended to have mode: 'lines+makers' |
What if plotly defaults to |
42a2c98
to
3a58812
Compare
@@ -38,7 +38,7 @@ describe('DataSelector', () => { | |||
const onUpdateTraces = jest.fn(); | |||
const wrapper = render({onUpdateTraces}).find(DropdownWidget); | |||
wrapper.prop('onChange')('y1'); | |||
expect(onUpdateTraces.mock.calls[0][0]).toEqual({ | |||
expect(onUpdateTraces.mock.calls[2][0]).toEqual({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could clear the mock after the render right before calling onChange
. That way we are impervious to these changes in indexes.
So here where this stands now. This is important when the user switches from one trace to another. Also, Ben pointed out yesterday that I should be using the plotly.js logic to determine trace.mode, which isn't always 'lines+markers': https://github.com/plotly/plotly.js/blob/master/src/traces/scatter/defaults.js#L32 I'm reworking this so that mode isn't aggressively set. |
33f4495
to
f793f7a
Compare
Sorry for all the noise in this pr. So, this pr responds to these requirements:
@bpostlethwaite @alexcjohnson would you review please. |
setTraceDefaults(container, fullContainer, updateContainer) { | ||
if ( | ||
(container.type === 'scatter' && !container.mode) || | ||
(!container.type && fullContainer.type === 'scatter') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
doesn't look quite right to me... so if container.type
is missing, we'll set mode
even if there already is one?
And if container.type
is missing, isn't fullContainer.type
always going to be 'scatter'
?
I would have thought just !container.mode && (container.type === 'scatter' || !container.type)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
!container.mode && (container.type === 'scatter' || !container.type)
you're right, changing this
) { | ||
updateContainer({ | ||
type: 'scatter', | ||
mode: fullContainer.mode || 'markers', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't have a real strong opinion here, but I probably would have gone for 'lines+markers'
as that's the "<20 points" default and we get here only (I think?) when there are no points.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I put markers, because it's the editor default..
We're using plotly.js defaults wherever we can with fullContainer.mode
, but when we're at our first trace that is empty and didn't have any data put in yet, we put in the editor default of 'markers'
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes looks good to me! 💃 We can tweak the defaults a little if we have to before we hit v1.0.
src/lib/customTraceType.js
Outdated
['tozeroy', 'tozerox', 'tonexty', 'tonextx', 'toself', 'tonext'].includes( | ||
trace.fill | ||
) | ||
) { | ||
return 'area'; | ||
} else if ( | ||
trace.type === 'scatter' && | ||
trace.mode && | ||
(trace.mode === 'lines' || trace.mode === 'lines+markers') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
are && trace.fill
and && trace.mode
actually necessary here? falsey values will fail the following clauses anyway.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah..you're right, removing
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks great! 💃 (though you'll probably need another after rebasing...)
6dce0ce
to
9398c33
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💃
thanks!! |
No description provided.