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
Refactor stream renaming and stream preprocessors #1224
Comments
I'm very happy with this proposal, thanks!
That does seem like a case for skipping with a warning, so that people can use a DynamicMap in one cell without causing problems if they try to pickle everything (with export).
How would this work? How would dtap be aware of anything that happened in the DynamicMap call? I thought a new stream would be created, a proxy for the old one, that does the renaming? |
@jbednar Thanks, I corrected what I meant below: tap = Tap()
dtap = DoubleTap()
DynamicMap(my_callback, streams=[tap, dtap.rename(x='dtap_x', y='dtap_y')])
# Generating an explicit event
dtap.update(dtap_x=0, dtap_y=0) Should be the |
Even so, the rename method will still return a new stream no? |
Unless you want to provide renaming as something all streams inherently know how to do, with a lookup table on every one, so that they know their arguments as well as all aliases available for their arguments. Not certain that's a good idea... |
Right.
Yeah, I think a new instance is a better approach. Edit: I've realized that maybe we do mean the same thing? Each stream instance will have a bit of state to remap its parameter names as necessary. Or do you mean some class attribute level approach? |
In which case the code becomes:
|
Ah, I see the issue now. Your code is right, but to be honest the recommended thing here is probably:
I need a better example of reusing streams... |
Ok, now that's a version that would work, assuming event() does what I'd assume it does. Sounds good! |
Are you sure that's the recommended approach, though? In your version, if someone does:
it's now an error (no such argument
then there's no error but nothing will happen, because DynamicMap knows nothing about |
That is now my question. @philippjfr Is there any reason to re-use streams at all except to save typing? In other words, I expect two streams instances of the same type with the same state (target, remapping etc) to behave as the same thing. Any reason the actual identity of the instance might matter? |
I don't think so, as long as they both point to the same source I think they will even be hooked up to the same bokeh Callback. |
Ok great, all these things are mostly equivalent though I agree my version leaves a useless handle around. Combining suggestions here is what I would probably use in the end: tap = Tap()
dtap = DoubleTap(rename=dict(x='dtap_x', y='dtap_y'))
dmap = DynamicMap(my_callback, streams=[tap, dtap])
# Generating an explicit event
dtap.update(dtap_x=0, dtap_y=0)
# Or
dmap.event(dtap_x=0, dtap_y=0) |
Actually, maybe this is an argument that Edit: I still prefer |
Seems like a really bad idea, in case you did use the stream somewhere else previously. |
Good point. And how do you feel about calling it |
Personally I think rename is clearer, but I suppose I could be persuaded. |
I think
@jbednar What do you prefer? |
I also think it is a better name for what it does. The docstring could be something like:
It also makes sense as a mathematical |
I'll let @jbednar decide. |
I think either one is accurate, since the underlying operation is arguably |
That matches my feelings about it. |
Ok, |
I think everything discussed in this issue has been addressed by the PR above. The Closing. |
Currently
Stream
classes have apreprocessors
argument that allow for renaming and other transformations of stream parameters. This was an initial concept we introduced, primarily because we realized that stream names might clash and wanted to introduce a mechanism that could resolve these clashes.Now we have more experience using the streams system, it no longer seems the appropriate level at which to introduce preprocessors, which we do know can be a useful concept in practice e.g we've found one example needing a preprocessor relating to datashader.
As the callback that generates elements lives on
DynamicMap
, this now seems to be the place to apply such transformations. The proposal here is two-fold: Streams should handle clashes only and preprocessors onDynamicMap
should handle transformations, once there are no name clashes.Resolving name clashes
Streams should now lose the
preprocessors
argument and gain arename
method instead:As this should be possible via the constructor, this should be equivalent to:
Note that I think
rename
should give you a new stream instance which is identical except for the renamed values in the streamscontents
property.As there can be no clashes between stream parameters on a single stream, so you only really need to use the
rename
in thestreams
argument to DynamicMap:or equivalently
This resolves the fact that both
Tap
andDoubleTap
havex
andy
stream parameters by default.Note that
DynamicMap
can check for clashes in the constructor - I suspect we do this already. I am also wondering ifmap
might be better as it is shorter thanrename
but that might be confusing as we havemap
methods elsewhere. Note thatremap
is also shorter thanrename
...Preprocessors
Now that stream parameters will be disambiguated, we can have a single preprocessor at the
DynamicMap
level that simply maps a dictionary of kwargs to a new dictionary of kwargs. We decided to have a single preprocessor instead of a list as:DynamicMaps
to pickle ( @philippjfr Isn't this a separate issue to address, shouldn't we safely skip DynamicMaps when pickling/unpickling instead of failing outright?)Note that because the preprocessor receives the renamed parameters at the
DynamicMap
level, it would be recommended that you apply rename inside thestreams
list so everything is declared together in one place (making things easier to reason about).There should be no issue applying the
rename
method in thestreams
list for re-used streams e.g:Call signatures
There is an issue about picking the appropriate call signatures in
DynamicMap
and we have explicitly decided that this is a separate issue from the concepts discussed in this issue.Edit: There are a few things that are more restricted under this proposal. Here is the docstring for the existing
Group
preprocessor at the streams level:As this was at the streams level, you would receive a single dictionary for each stream. With a preprocessor at the
DynamicMap
level, you would still need to rename the stream parameters then group.Just mentioning this for completeness as I don't think this is an important use-case (afaik we've never used
Group
).The text was updated successfully, but these errors were encountered: