Layout of Layout

Let’s say I have a 2x3 grid layout of Overlay plots. On top of that I want to add a top and right panel “legend” plots. There are 2 things getting in the way:

  • The layouts are flattened out if we + operate on them (not sure if there is an equivalent of .append)
  • Because of the former, we can’t manipulate the options of the inner Layout, e.g. sublabel_* to only affect it

The current thought it to use panel.Column, but this does not interact quite well, e.g. I encounter:

AttributeError: 'Column' object has no attribute 'traverse'

when running renderer.get_plot()

Not sure I follow.

Can you share a minimal code example?

main_layout = holoviews.Layout()
for run in plot_runs:
    plot_data = data.sel(run=run)
    overlay = holoviews.Overlay()
    # Complicating the example a bit to give more realistic example of colorbar usage
    for t in data["t"]:
        line_data = plot_data.sel(t=t)
        ovelay *= line_data.hvplot(kind=line)
    main_layout += overlay
# Let's say I want this to be a 2x3 format
main_layout.cols(2)
main_layout.opts(
    holoviews.opts.Curve(color=holoviews.Palette("Viridis")),
)
colorbar = draw_my_colorbar("Viridis")
# Note the broken part is here, because main_layout is being flattned out instead of keeping it as a list
super_layout = holoviews.Layout([colorbar, main_layout])
# Here I want `colorbar` to be on top of `main_layout`
super_layout.cols(1)

Maybe pn.Column(colorbar, main_layout)

But ideally if you can share a reproducible example that I can copy/paste to test.

(I don’t know how to format jupyter cells so I just split them up)

import holoviews
import panel

holoviews.extension("bokeh")

renderer = holoviews.renderer("bokeh").instance(

# For simplicity, let's just copy the plots
curve = holoviews.Curve([0, 1, 2])
main_layout = holoviews.Layout()
for _ in range(6):
    main_layout += curve
# Let's say I want this to be a 2x3 format
main_layout.cols(2)
# Placeholder for colorbar or whatever other legend plot
curve2 = holoviews.Curve([1, 2, 3])
## This doesn't work
# Note the broken part is here, because main_layout is being flattned out instead of keeping it as a list
super_layout = holoviews.Layout([curve2, main_layout])
super_layout.cols(1)

super_layout
## This works for displaying
super_layout = panel.Column(
    curve2,
    main_layout
)

super_layout
# But it breaks down when I try to use renderers, e.g. `get_plot()` or `save()`
renderer.get_plot(super_layout)

Don’t use holoviews method on panel, but can use panel to holoviews.

super_layout.save("...") or pn.save(super_layout, ...)

The issue there is that it creates a .html, but I want it as a single svg file, e.g.:

renderer = holoviews.renderer("matplotlib").instance(
                fig="svg",
                dpi=900,
            )

At the moment, there’s no direct support with Panel so you have to raise an issue.

You can, however, (potentially) use bokeh’s save_svg, or a modified version of it

If that doesn’t work you probably have to implement it using playwright/selenium

Should Panel even have such a feature though? The issue here seems to be completely within holoviews composition. Wouldn’t it be better to expand holoviews.Layout to accept Layout of Layout, i.e.:

  • Fix the Layout constructor to not expand any Layout objects
  • Figure out the composition interface, maybe + with Overlay behaves the same, but if it’s a Layout, make it behave like a list operation, i.e. + expands to Layout(self, *other) (current behavior), .append to add a list as an element, i.e. Layout(self, other)
  • Scope the Layout options to each individual layer (not sure if this is already built-in?)

The core issue is, iiuc with ViewableTree as there should be one layer on top of it like LayoutTree that can have branches of similar LayoutTree elements or leafs of ViewableTree (similar to the structure of ViewableTree vs ViewableElement)

For my immediate usecase I can coast along with using inkspace to relable the plots and such and luckily I have a 1x3 layout.

I think it could. Panel is great for laying things out properly.

Sounds like a major internal refactor, but I could be wrong; I haven’t looked too deep into HoloViews internals.