Panel has been very useful for me in my work already, making it easy to compose displayable items into an overall app or dashboard arrangement. However, the ability to decompose and recompose these objects has some obvious limits that I have found very frustrating. These limitations make it very hard to follow a code-development process of getting something working and adapting it into whatever final form I want, without having to go backwards and start over. To me, the compositional nature of Panel is the whole point of the library, and so I want to work to eliminate any of these limitations on composition, decomposition, and recomposition.
For instance, in my trivial clifford interact example, I can call pn.interact(clifford_plot, n=(1,20000000), colormap=ps)
to get an app like:
It's great that I can do that in one line, and often that's all I'll need. But let's say I want to go ahead and publish that as a dashboard -- now I want to swap the order to be left to right, add some instructions, and so on. If I look at what's displayed, I see a composite object of two items (a box of widgets, and a plot), and that's what I want to be able to work with now that I have them. (I may even want to pull some of the widgets out individually, move some up to the top, some to the right, throw away others, etc., but that issue can be discussed later even though it's probably covered under the same principles listed here.)
When I look, I see that the object returned in that call is <interactive interactive00116>
, which is opaque but turns out to be a type of Pane. Unlike Layouts, Panes are not inherently a container or compositional object, yet this one and several others (yt and HoloViews, at least) return something that looks like it would be a container, either with multiple plots or with a plot and some widgets. If I study the code for the implementation of this particular pane, I can find that it has a layout
attribute with the two items on it (widgets and plot) that I can see, and it turns out that I can indeed pull out those items and build a new layout:
i=pp.interact(clifford_plot, a=(-2,2), b=(-2,2), c=(-2,2), d=(-2,2),
n=(1,20000000), colormap=ps, panel_layout=pp.Row)
logo = "https://tinyurl.com/y9c2zn65/logo_stacked_s.png"
text = """Try out the widgets!"""
i.layout[0] = pp.Column(logo, text, i.layout[0])
i.servable()
It's great that that works, but discovering that took some great leaps of faith and violated my intuitions about how things should work. I was expecting the object returned to be explicitly compositional already, so that I could simply decompose it and recompose it as I like, without having to figure out the special layout
object inside it. Otherwise, how would I know if recomposing it that way is ok, or if the interact object had some special properties at the combined level that will now no longer work? Both of those issues (the lack of discoverability and the lack of knowing what might be lost when unpacking) strongly discourage such unpacking, and thus limit my ability as a user to exploit the object that I created. Those forces would push me to avoid interact
and instead build up my object compositionally, so that I can have control over how it is recomposed, making me abandon the convenience of interact
-- I'd treat interact
as a dead end rather than as a quick start.
What I would like is for Panel to be explicitly compositional wherever it appears to be compositional. For this to work, magic convenience functions like interact()
would need to constrain their magic (wherever possible) to the construction, not the operation, of a composite object, and then return something that is clearly and explicitly a composite. Here, I think what's returned should just be a container of the two items I can see (widgets and plots), ready for me to do whatever I like with it. That's the only way I can see that a Panel user will be able to naturally and easily go on a trajectory from seeing some initial thing to arranging precisely the dashboard they want to have. The same issue applies to the HoloViews pane and any other pane that returns objects that a user might want to rearrange or control (multiple plots, plots with widgets, multiple widgets, etc.) -- if it's something the user could want to rearrange and recompose, then it should be explicitly a container object of reusable objects from the start, not a pane that inside includes some container but also adds some magic (if possible!).