-
Notifications
You must be signed in to change notification settings - Fork 947
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
Add a get_interact_value() method to customize the value passed to interactive functions #725
Add a get_interact_value() method to customize the value passed to interactive functions #725
Conversation
Although this only works with widgets holding a |
Can you provide more details? I understand you eval proposal, but I'm having trouble understanding this alternative one. Is the intention that accompanying this suggestion, there'd be a "Delegate" widget or something, which on set .value a function would be triggered, of which the output would be get_value? |
This pull request obviously does not change anything for existing code, it just adds a hook. My idea was to allow something like
This is something that SageNB supports. It allows passing essentially arbitrary Python objects as arguments for interactive functions. But obviously, this pull request allows anything in |
I am not really sure about this in general. My view is that is you want to do something non-trivial with widgets, you declare and wire them explicitly. Interact' s goal to be completely auto-magic: based on introspection of default values, it creates a simple GUI automatically to interact with a function. Adding hooks exposes a complex inner machinery that is very likely to go south eventually. |
Nothing forces anybody to use those hooks. It's completely fine for me if |
Although it increases the API surface. If we change that something that breaks that one thing, it becomes an issue. |
Having a transformation function that intercepts values from the widgets before they are passed into the interact function is a nice generalization, I think. It allows a user to construct some more sophisticated controls easily (for example, if we had a grid control, we could easily make a numpy array control by taking the value of the grid and converting it to a numpy array). On the other hand, a transformation control like Jon hints at is more composable, and doesn't just apply to controls with a # in ipywidgets
class Transform(...):
def __init__(self, control, attribute, ...):
# observe the control's attribute
# on change, apply self.transform and set self.value
def transform(self, value):
return value
# in user code
class Eval(ipywidgets.transform):
def transform(self, value):
return eval(value)
@interact(x = Eval(ipywidgets.Text, 'value'))
def _(x):
print(x) Another nice thing about this approach is that it lets us use attributes other than |
This transform control is essentially a python dlink control with the endpoint being itself and the |
That is possible with my branch too, nobody says that Anyway, I don't care much how my use case is solved, I just want a solution. My solution is very simple, works right now and doesn't break anything in |
Another use-case for this branch or "transformations" in general is to change the type of slider values. I could use this branch to make a |
@jdemeyer perhaps the existing to_json/from_json transforms are enough for what you need: from ipywidgets import interact, Text
from traitlets import Any
def to_str(x, obj):
return str(x)
def from_str(x, obj):
return eval(x)
class Eval(Text):
value = Any().tag(sync=True, to_json=to_str, from_json=from_str)
@interact(x=Eval('1'))
def foo(x):
print(repr(x), type(x)) or for a custom IntSlider: import numpy as np
from ipywidgets import interact, IntSlider
from traitlets import Instance, validate
def to_int(x, obj):
return int(x)
def from_int(x, obj):
return np.int64(x)
class MyIntSlider(IntSlider):
value = Instance(np.int64).tag(sync=True, to_json=to_int, from_json=from_int)
@interact(x=MyIntSlider(np.int64(5)))
def foo(x):
print(repr(x), type(x)) The difference I see between existing |
I need to check, but it could be. |
Great! Let me know what you find, and hopefully we can get something working for you. |
Do you consider the JSON interface for the widgets part of your public API? |
yes, definitely. |
It's not well documented (at all?), and certainly an advanced usage, but it is a public API and needed for many custom widgets developed outside ipywidgets. |
If you assign a new to_json to a trait metadata it is going to change how I am not sure that I really understand the purpose of get_value though. On Aug 30, 2016 1:27 PM, "Min RK" notifications@github.com wrote: It's not well documented (at all?), and certainly an advanced usage, but it — Reply to this email directly, view it on GitHub |
it has to serialize to the same type for the widget to work, but it works just fine for existing widgets, including IntSlider and Text above. The goal is to allow changing the type of |
In term of use case, in addition to the function passed to |
One thing that I think would be worth considering is to formalize the So having a base |
Of course it can be part of the interactive function. But this is something that I do not want because it is cumbersome. For example, I may want to re-use existing functions which take certain arguments. And I want some common "standard" transformations, for example the |
I admit that this Is there a way to make the above work with |
to_json and from_json take two arguments, the second one being the |
I see. So basically the second argument is |
Hum I don't think so. At some point we made to_json a method of the Trait Type but never the HasTraits instance... We often have things like
|
I meant it's not actually a method but it can be used as if it was a method where
|
Just adding that |
I prefer the approach of Jon and Jason with the delegate widget over dynamically changing |
I personally don't care as long as it works. The |
But it does not make sense! If you modify |
Well, one thing which is bad with Min's proposal: whenever the Javascript value of a |
Good point. I wouldn't object in general to a |
@minrk the |
What do you think of this |
I have nothing against this but I also don't really see the point of introducing this extra class.
Part of the point of this pull request is that "widget holding a |
The reason is that not all widgets can be used for interact. For example
Why is it not the same thing? |
2312b33
to
f05f88c
Compare
This new version adds a |
I just thought about yet another use case for Then this |
👍 this will need a rebase! |
…teractive functions
f05f88c
to
74d6bc4
Compare
Sorry for that. It's done now. |
✨ 🎉 |
Cool, thanks! |
…This fixes it.
Let
W
be a widget. If that is used for an interactive (@interact
) function, the function receivesW.value
. I propose to allow to customize this by adding a methodW.get_value()
to return the value pased to the interactive function. By default, this is justW.value
but custom widgets could change this.This solves the same problem as #724 but perhaps with a cleaner API.
Context: this is to support analogous functionality from SageNB to help with OpenDreamKit/OpenDreamKit#94.