Auto-registration of callbacks and change in Callback API
Hi guys, I've been helping some people learn to use yt lately, and it is becoming apparent to me that the plotting API might need some work. I'm mostly okay with the way the PlotCollection stuff is handled (but see http://yt.enzotools.org/ticket/158 for more on that) but the callbacks specifically are not terribly intuitive. The current API is: p = pc.add_projection(...) p.add_callback(ContourCallback("Temperature")) Currently the Callback metaclass auto-registers each callback (http://yt.enzotools.org/browser/trunk/yt/raven/Callbacks.py#L38) so that they get imported automatically in yt.mods (http://yt.enzotools.org/browser/trunk/yt/mods.py#L55) but this can be done in a substantially more straightforward fashion. (However, the AMRData subclasses are also nearly auto-registering, which is something I intend to explore a bit more in the future.) I'd like to propose that each callback be given a static attribute _type_name -- i.e., "contour", "quiver" etc, and then this be used to access that particular callback type. I'm torn, however, on how this should be handled. There are three main ways I've considered for implementing this: == 1. Through a .modify(type_name, *args, **kwargs) command. You would then do: p.modify("contour", "Temperature") for instance, and it would add that callback. This has the downside that, while we could provide docstrings for all the possible callbacks, we would have to implement some introspection to do so. Not a huge deal, but somewhat annoying. 2. Through dictionary-style lookup, similar to DerivedQuantities: p.modify["contour"]("Temperature") this would allow us to have docstrings without any introspection. 3. Through the current style used for generating data objects from the hierarchy: p.contour("Temperature") This would also give us docstrings for free. == What do you think? The first appeals to me the strongest for aesthetic reasons, but the third appeals to me on the grounds of ease of use and understanding. Does anyone have any strong feelings? This would all be handled via an auto-registry situation, so the means of adding new callbacks would change, but only in that they would all require _type_name . Additionally, I see no reason to get rid of the current p.add_callback(...) method, which is more general that we're looking at here. -Matt
Matt,
I've been helping some people learn to use yt lately, and it is becoming apparent to me that the plotting API might need some work.
What do you think?
My first suggestion to you is to do what's easy and works. But if that's not what you're asking, three sounds like the way to go because if you're making this improvement for the users, go with what's easy for the users. _______________________________________________________ sskory@physics.ucsd.edu o__ Stephen Skory http://physics.ucsd.edu/~sskory/ _.>/ _Graduate Student ________________________________(_)_\(_)_______________
They're all the same difficulty; I'll count your vote toward three. :)
On Thu, Mar 19, 2009 at 12:19 PM, Stephen Skory
Matt,
I've been helping some people learn to use yt lately, and it is becoming apparent to me that the plotting API might need some work.
What do you think?
My first suggestion to you is to do what's easy and works. But if that's not what you're asking, three sounds like the way to go because if you're making this improvement for the users, go with what's easy for the users.
_______________________________________________________ sskory@physics.ucsd.edu o__ Stephen Skory http://physics.ucsd.edu/~sskory/ _.>/ _Graduate Student ________________________________(_)_\(_)_______________ _______________________________________________ Yt-dev mailing list Yt-dev@lists.spacepope.org http://lists.spacepope.org/listinfo.cgi/yt-dev-spacepope.org
I'd vote for two. If you have a dictionary of things, then I can do
p.modify.keys()
and figure out what options are available to me.
It's a bit more cumbersome of an interface than 3. I like 3 because
the interface is really easy, which I strongly approve of. But then I
have to go somewhere else to figure out what modifications are
available (contour, subgrids, Did you call that "Arrow Callback" or
"Quiver Callback?" and so on) and its not as obvious how to extend
that interface to user defined callbacks.
It would be nice if adding new callbacks and using extant ones was all
done in one place-- I see
p.modify["NewThingI'mAdding"] = dave_callbacks.PrintTheTimeInTheTitleOfThePlot()
as a potentially useful pattern that would fall right out of a
dictionary type method, but not as obvious with the other two. I use
my own callbacks all the time, so I would like to be able to use them
with whatever new interface comes up; and it would be nice for a new
user to not have to learn one system for calling pre-existing
callbacks, and another for adding one's own.
This is a good idea, I like this direction.
d.
On Thu, Mar 19, 2009 at 11:04 AM, Matthew Turk
Hi guys,
I've been helping some people learn to use yt lately, and it is becoming apparent to me that the plotting API might need some work. I'm mostly okay with the way the PlotCollection stuff is handled (but see http://yt.enzotools.org/ticket/158 for more on that) but the callbacks specifically are not terribly intuitive. The current API is:
p = pc.add_projection(...) p.add_callback(ContourCallback("Temperature"))
Currently the Callback metaclass auto-registers each callback (http://yt.enzotools.org/browser/trunk/yt/raven/Callbacks.py#L38) so that they get imported automatically in yt.mods (http://yt.enzotools.org/browser/trunk/yt/mods.py#L55) but this can be done in a substantially more straightforward fashion. (However, the AMRData subclasses are also nearly auto-registering, which is something I intend to explore a bit more in the future.)
I'd like to propose that each callback be given a static attribute _type_name -- i.e., "contour", "quiver" etc, and then this be used to access that particular callback type. I'm torn, however, on how this should be handled. There are three main ways I've considered for implementing this:
== 1. Through a .modify(type_name, *args, **kwargs) command. You would then do:
p.modify("contour", "Temperature")
for instance, and it would add that callback.
This has the downside that, while we could provide docstrings for all the possible callbacks, we would have to implement some introspection to do so. Not a huge deal, but somewhat annoying.
2. Through dictionary-style lookup, similar to DerivedQuantities:
p.modify["contour"]("Temperature")
this would allow us to have docstrings without any introspection.
3. Through the current style used for generating data objects from the hierarchy:
p.contour("Temperature")
This would also give us docstrings for free. ==
What do you think? The first appeals to me the strongest for aesthetic reasons, but the third appeals to me on the grounds of ease of use and understanding. Does anyone have any strong feelings? This would all be handled via an auto-registry situation, so the means of adding new callbacks would change, but only in that they would all require _type_name . Additionally, I see no reason to get rid of the current p.add_callback(...) method, which is more general that we're looking at here.
-Matt _______________________________________________ Yt-dev mailing list Yt-dev@lists.spacepope.org http://lists.spacepope.org/listinfo.cgi/yt-dev-spacepope.org
Under "for what it's worth"
One thing I stuck in uber (the "Dave's Lazy" object) was a callback
interface that took a list, and that list could be strings of pre
defined things ("GridLines","VelocityQuiver") or subclasses of
callbacks, and it would sort out if it was a subgrid class type, in
which case it would just deal with it, or if it was a pre-defined
string like "Grids" it would call the extant subgrid object, which
uber already knew about.
It also made it easy to add several callbacks to a plot at once.
So the use pattern would be like
sim = uber( args )
sim.callbacks = ["VelocityQuiver","GridLines", dave_callbacks.TimeInTitle() ]
sim.plot()
and it would make whatever plot you defined, and add all the callbacks
in the list at once.
That's probably not useful here, I think something a little more
sophisticated is in order, but that was my take to the same issue. It
does have the problem of not auto-listing.
d.
On Thu, Mar 19, 2009 at 1:57 PM, david collins
I'd vote for two. If you have a dictionary of things, then I can do p.modify.keys() and figure out what options are available to me.
It's a bit more cumbersome of an interface than 3. I like 3 because the interface is really easy, which I strongly approve of. But then I have to go somewhere else to figure out what modifications are available (contour, subgrids, Did you call that "Arrow Callback" or "Quiver Callback?" and so on) and its not as obvious how to extend that interface to user defined callbacks.
It would be nice if adding new callbacks and using extant ones was all done in one place-- I see
p.modify["NewThingI'mAdding"] = dave_callbacks.PrintTheTimeInTheTitleOfThePlot()
as a potentially useful pattern that would fall right out of a dictionary type method, but not as obvious with the other two. I use my own callbacks all the time, so I would like to be able to use them with whatever new interface comes up; and it would be nice for a new user to not have to learn one system for calling pre-existing callbacks, and another for adding one's own.
This is a good idea, I like this direction. d.
On Thu, Mar 19, 2009 at 11:04 AM, Matthew Turk
wrote: Hi guys,
I've been helping some people learn to use yt lately, and it is becoming apparent to me that the plotting API might need some work. I'm mostly okay with the way the PlotCollection stuff is handled (but see http://yt.enzotools.org/ticket/158 for more on that) but the callbacks specifically are not terribly intuitive. The current API is:
p = pc.add_projection(...) p.add_callback(ContourCallback("Temperature"))
Currently the Callback metaclass auto-registers each callback (http://yt.enzotools.org/browser/trunk/yt/raven/Callbacks.py#L38) so that they get imported automatically in yt.mods (http://yt.enzotools.org/browser/trunk/yt/mods.py#L55) but this can be done in a substantially more straightforward fashion. (However, the AMRData subclasses are also nearly auto-registering, which is something I intend to explore a bit more in the future.)
I'd like to propose that each callback be given a static attribute _type_name -- i.e., "contour", "quiver" etc, and then this be used to access that particular callback type. I'm torn, however, on how this should be handled. There are three main ways I've considered for implementing this:
== 1. Through a .modify(type_name, *args, **kwargs) command. You would then do:
p.modify("contour", "Temperature")
for instance, and it would add that callback.
This has the downside that, while we could provide docstrings for all the possible callbacks, we would have to implement some introspection to do so. Not a huge deal, but somewhat annoying.
2. Through dictionary-style lookup, similar to DerivedQuantities:
p.modify["contour"]("Temperature")
this would allow us to have docstrings without any introspection.
3. Through the current style used for generating data objects from the hierarchy:
p.contour("Temperature")
This would also give us docstrings for free. ==
What do you think? The first appeals to me the strongest for aesthetic reasons, but the third appeals to me on the grounds of ease of use and understanding. Does anyone have any strong feelings? This would all be handled via an auto-registry situation, so the means of adding new callbacks would change, but only in that they would all require _type_name . Additionally, I see no reason to get rid of the current p.add_callback(...) method, which is more general that we're looking at here.
-Matt _______________________________________________ Yt-dev mailing list Yt-dev@lists.spacepope.org http://lists.spacepope.org/listinfo.cgi/yt-dev-spacepope.org
Hi Dave and others,
I've gone with Dave's persuasive suggestion to put them in a dict. To
do so, and retain the current structure of the callbacks (which is
really kind of easy to use, I thought) I used a wrapper function and a
closure, which I think works out alright.
http://bitbucket.org/MatthewTurk/yt/changeset/17f300ab8101/
Here's a sample script:
==
from yt.mods import *
pf = EnzoStaticOutput("RD0005-mine/RedshiftOutput0005")
pc = PlotCollection(pf, center = [0.5]*3)
p = pc.add_projection("Density", 0, weight_field="Density")
p.modify["contour"]("Temperature", take_log = True)
p = pc.add_projection("Density", 1, weight_field="Density")
p.modify["particles"](1, 1.0)
==
This, I think, is much nicer. The help() for each works, too, and you
don't have to add_callback(...) anymore; this should also help with
adding the callbacks to the next-gen GUI. I've also added (in a later
changeset) helpful velocity callback ("velocity" in .modify[]) that
accepts only the skip count and then gets the field information
itself; this should have been put in a long time ago. It tries to
figure out which quiver type to use, too, so it should work on cutting
planes out of the box.
The old plot callback interface remains, and will likely remain in
yt.mods until 1.5 is out the door. If no one objects, I'll bring
these changes into trunk. Also, the particle callback needs work.
I'll take a look at it later; it's awful right now, and uses too much
memory and loads too much data and and and and.
Dave, I like your idea you have presented about the list of callbacks.
We should investigate this when you start bringing in components of
uber.
-Matt
On Thu, Mar 19, 2009 at 2:09 PM, david collins
Under "for what it's worth"
One thing I stuck in uber (the "Dave's Lazy" object) was a callback interface that took a list, and that list could be strings of pre defined things ("GridLines","VelocityQuiver") or subclasses of callbacks, and it would sort out if it was a subgrid class type, in which case it would just deal with it, or if it was a pre-defined string like "Grids" it would call the extant subgrid object, which uber already knew about. It also made it easy to add several callbacks to a plot at once.
So the use pattern would be like sim = uber( args ) sim.callbacks = ["VelocityQuiver","GridLines", dave_callbacks.TimeInTitle() ] sim.plot()
and it would make whatever plot you defined, and add all the callbacks in the list at once.
That's probably not useful here, I think something a little more sophisticated is in order, but that was my take to the same issue. It does have the problem of not auto-listing.
d.
On Thu, Mar 19, 2009 at 1:57 PM, david collins
wrote: I'd vote for two. If you have a dictionary of things, then I can do p.modify.keys() and figure out what options are available to me.
It's a bit more cumbersome of an interface than 3. I like 3 because the interface is really easy, which I strongly approve of. But then I have to go somewhere else to figure out what modifications are available (contour, subgrids, Did you call that "Arrow Callback" or "Quiver Callback?" and so on) and its not as obvious how to extend that interface to user defined callbacks.
It would be nice if adding new callbacks and using extant ones was all done in one place-- I see
p.modify["NewThingI'mAdding"] = dave_callbacks.PrintTheTimeInTheTitleOfThePlot()
as a potentially useful pattern that would fall right out of a dictionary type method, but not as obvious with the other two. I use my own callbacks all the time, so I would like to be able to use them with whatever new interface comes up; and it would be nice for a new user to not have to learn one system for calling pre-existing callbacks, and another for adding one's own.
This is a good idea, I like this direction. d.
On Thu, Mar 19, 2009 at 11:04 AM, Matthew Turk
wrote: Hi guys,
I've been helping some people learn to use yt lately, and it is becoming apparent to me that the plotting API might need some work. I'm mostly okay with the way the PlotCollection stuff is handled (but see http://yt.enzotools.org/ticket/158 for more on that) but the callbacks specifically are not terribly intuitive. The current API is:
p = pc.add_projection(...) p.add_callback(ContourCallback("Temperature"))
Currently the Callback metaclass auto-registers each callback (http://yt.enzotools.org/browser/trunk/yt/raven/Callbacks.py#L38) so that they get imported automatically in yt.mods (http://yt.enzotools.org/browser/trunk/yt/mods.py#L55) but this can be done in a substantially more straightforward fashion. (However, the AMRData subclasses are also nearly auto-registering, which is something I intend to explore a bit more in the future.)
I'd like to propose that each callback be given a static attribute _type_name -- i.e., "contour", "quiver" etc, and then this be used to access that particular callback type. I'm torn, however, on how this should be handled. There are three main ways I've considered for implementing this:
== 1. Through a .modify(type_name, *args, **kwargs) command. You would then do:
p.modify("contour", "Temperature")
for instance, and it would add that callback.
This has the downside that, while we could provide docstrings for all the possible callbacks, we would have to implement some introspection to do so. Not a huge deal, but somewhat annoying.
2. Through dictionary-style lookup, similar to DerivedQuantities:
p.modify["contour"]("Temperature")
this would allow us to have docstrings without any introspection.
3. Through the current style used for generating data objects from the hierarchy:
p.contour("Temperature")
This would also give us docstrings for free. ==
What do you think? The first appeals to me the strongest for aesthetic reasons, but the third appeals to me on the grounds of ease of use and understanding. Does anyone have any strong feelings? This would all be handled via an auto-registry situation, so the means of adding new callbacks would change, but only in that they would all require _type_name . Additionally, I see no reason to get rid of the current p.add_callback(...) method, which is more general that we're looking at here.
-Matt _______________________________________________ Yt-dev mailing list Yt-dev@lists.spacepope.org http://lists.spacepope.org/listinfo.cgi/yt-dev-spacepope.org
_______________________________________________ Yt-dev mailing list Yt-dev@lists.spacepope.org http://lists.spacepope.org/listinfo.cgi/yt-dev-spacepope.org
participants (3)
-
david collins
-
Matthew Turk
-
Stephen Skory