holoviz / panel

Panel: The powerful data exploration & web app framework for Python
https://panel.holoviz.org
BSD 3-Clause "New" or "Revised" License
4.77k stars 519 forks source link

Layout not resizing/ adjusting when exiting full screen #2617

Closed MarcSkovMadsen closed 1 year ago

MarcSkovMadsen commented 3 years ago

I'm on Panel 0.12.0 and experience the layout does not resize/ adjust when exiting full screen if I change my view during full screen. As I see it the problem is related to selected Panes.

See the video.

https://user-images.githubusercontent.com/42288570/128127683-db2c6d7a-fc0d-4d6d-992b-e6caceff10f6.mp4

Examples with problems:

Examples without problem

I will include the code (long) in the next post. I don't include a small example as I want this to work across plotting panes and not just for for example Altair.

MarcSkovMadsen commented 3 years ago

Code

import inspect
import textwrap

import param

import panel as pn

RAW_CSS = """
.bk-root *.bk-btn {
    font-size: 17px;
    font-weight: bold;
}
"""

pn.extension("vega", "deckgl", "echarts", "plotly", "vtk", sizing_mode="stretch_width")

class ComponentBase(param.Parameterized):
    component =  param.Parameter()
    reference = param.String("https://panel.holoviz.org/")
    extension = param.String("")

    def example(self, theme="default", accent_base_color="blue"):
        raise NotImplemented("")

    def code(self, accent_base_color="blue"):
        text = "import panel as pn"
        text += "\n\n"
        if self.extension:
            text += f'pn.extension("{self.extension}", sizing_mode="stretch_both")'
        else:
            text += 'pn.extension(sizing_mode="stretch_both")'
        text += "\n"
        text += f"""
color="{accent_base_color}"
template=pn.template.FastListTemplate(site="Awesome Panel", title="{self.name[0:-5]}", accent_base_color=color, header_background=color, header_accent_base_color="white",)
theme = 'dark' if template.theme==pn.template.DarkTheme else 'default'

"""
        text += textwrap.dedent(inspect.getsource(self.example)).replace("self, ","")

        text += f"""

component=example(theme=theme, accent_base_color=color)
template.main.append(component)
template.servable()"""
        return text

    def __str__(self):
        return type(self).__name__.upper()

class Altair(ComponentBase):
    component =  param.Parameter("pn.pane.Vega")
    reference = param.String("https://panel.holoviz.org/reference/panes/Vega.html#altair")
    extension = param.String("vega")

    def example(self, theme="default", accent_base_color="blue"):
        import altair as alt
        from vega_datasets import data

        if theme=="dark":
            alt.themes.enable("dark")
        else:
            alt.themes.enable("default")

        cars = data.cars()
        plot = alt.Chart(cars).mark_circle(size=60).encode(
            x='Horsepower',
            y='Miles_per_Gallon',
            color='Origin',
            tooltip=['Name', 'Origin', 'Horsepower', 'Miles_per_Gallon']
        ).properties(
            height="container",
            width="container",
        ).interactive()
        return pn.pane.Vega(plot, height=500, sizing_mode="stretch_both")

class Bokeh(ComponentBase):
    component =  param.Parameter(pn.pane.Bokeh)
    reference = param.String("https://panel.holoviz.org/")

    def example(self, theme="default", accent_base_color="blue"):
        import numpy as np
        from bokeh.plotting import figure
        from scipy.integrate import odeint

        sigma = 10
        rho = 28
        beta = 8.0/3
        theta = 3 * np.pi / 4

        def lorenz(xyz, t):
            x, y, z = xyz
            x_dot = sigma * (y - x)
            y_dot = x * rho - x * z - y
            z_dot = x * y - beta* z
            return [x_dot, y_dot, z_dot]

        initial = (-10, -7, 35)
        t = np.arange(0, 100, 0.006)

        solution = odeint(lorenz, initial, t)

        x = solution[:, 0]
        y = solution[:, 1]
        z = solution[:, 2]
        xprime = np.cos(theta) * x - np.sin(theta) * y

        colors = ["#C6DBEF", "#9ECAE1", "#6BAED6", "#4292C6", "#2171B5", "#08519C", "#08306B",]

        p = figure(title="Lorenz attractor example", tools=["pan,wheel_zoom,box_zoom,reset,hover"])

        p.multi_line(np.array_split(xprime, 7), np.array_split(z, 7),
                    line_color=colors, line_alpha=0.8, line_width=1.5)
        return pn.pane.Bokeh(p, height=500, sizing_mode="stretch_both")

class DeckGL(ComponentBase):
    component =  param.Parameter(pn.pane.DeckGL)
    reference = param.String("https://panel.holoviz.org/reference/panes/DeckGL.html")
    extension = param.String("deckgl")

    def example(self, theme="default", accent_base_color="#A01346"):
        MAPBOX_KEY = "pk.eyJ1IjoicGFuZWxvcmciLCJhIjoiY2s1enA3ejhyMWhmZjNobjM1NXhtbWRrMyJ9.B_frQsAVepGIe-HiOJeqvQ"

        if theme=="dark":
            deckgl_map_style = "mapbox://styles/mapbox/dark-v9"
        else:
            deckgl_map_style = "mapbox://styles/mapbox/light-v9"

        json_spec = {
            "initialViewState": {
                "bearing": -27.36,
                "latitude": 52.2323,
                "longitude": -1.415,
                "maxZoom": 15,
                "minZoom": 5,
                "pitch": 40.5,
                "zoom": 6
            },
            "layers": [{
                "@@type": "HexagonLayer",
                "autoHighlight": True,
                "coverage": 1,
                "data": "https://raw.githubusercontent.com/uber-common/deck.gl-data/master/examples/3d-heatmap/heatmap-data.csv",
                "elevationRange": [0, 3000],
                "elevationScale": 50,
                "extruded": True,
                "getPosition": "@@=[lng, lat]",
                "id": "8a553b25-ef3a-489c-bbe2-e102d18a3211",
                "pickable": True
            }],
            "mapStyle": deckgl_map_style,
            "views": [
                {"@@type": "MapView", "controller": True}
            ]
        }

        return pn.pane.DeckGL(json_spec, mapbox_api_key=MAPBOX_KEY, sizing_mode='stretch_both', height=500)

class ECharts(ComponentBase):
    component =  param.Parameter(pn.pane.ECharts)
    reference = param.String("https://panel.holoviz.org/reference/panes/ECharts.html#panes-gallery-echarts")
    extension = param.String("echarts")

    def example(self, theme="default", accent_base_color="#A01346"):
        echart = {
            "xAxis": {
                "data": ['2017-10-24', '2017-10-25', '2017-10-26', '2017-10-27']
            },
            "yAxis": {},
            "series": [{
                "type": 'k',
                "data": [
                    [20, 34, 10,38],
                    [40, 35, 30, 50],
                    [31, 38, 33, 44],
                    [38, 15, 5, 42],
                ]
            }],
            "responsive": True
        }
        return pn.pane.ECharts(echart, min_height=500, sizing_mode="stretch_both")

class HoloViews(ComponentBase):
    component =  param.Parameter(pn.pane.HoloViews)
    reference = param.String("https://panel.holoviz.org/reference/panes/HoloViews.html")

    def example(self, theme="default", accent_base_color="blue"):
        import holoviews as hv
        import numpy as np
        from holoviews import opts, streams
        from holoviews.plotting.links import DataLink

        hv.extension('bokeh')

        curve = hv.Curve(np.random.randn(10).cumsum()).opts(responsive=True, line_width=6, color=accent_base_color)
        if theme=="default":
            point_color="black"
        else:
            point_color="#E5E5E5"

        curve_stream = streams.CurveEdit(data=curve.columns(), source=curve, style={'color': point_color, 'size': 10})

        table = hv.Table(curve).opts(editable=True)
        DataLink(curve, table)

        plot=(curve + table).opts(
            opts.Table(editable=True),
        )

        return pn.pane.HoloViews(plot, height=500, sizing_mode="stretch_both")
class HVPlot(ComponentBase):
    component =  param.Parameter(pn.pane.HoloViews)
    reference = param.String("https://panel.holoviz.org/reference/panes/HoloViews.html")

    def example(self, theme="default", accent_base_color="blue"):
        import hvplot.pandas  # noqa
        from bokeh.sampledata.sprint import sprint as df

        plot = df.hvplot.violin(y='Time', by='Medal', c='Medal', ylabel='Sprint Time',
                        cmap=['gold', 'silver', 'brown'], legend=False,
                        responsive=True, padding=0.4)

        return pn.pane.HoloViews(plot, height=500, sizing_mode="stretch_both")

class IPyWidget(ComponentBase):
    component =  param.Parameter(pn.pane.IPyWidget)
    reference = param.String("https://panel.holoviz.org/")
    extension = param.String("ipywidgets")

    def example(self, theme="default", accent_base_color="blue"):
        # from ipyleaflet import Map, VideoOverlay

        # m = Map(center=(25, -115), zoom=4)

        # video = VideoOverlay(
        #     url="https://www.mapbox.com/bites/00188/patricia_nasa.webm",
        #     bounds=((13, -130), (32, -100))
        # )
        # m.add_layer(video)
        # return pn.pane.IPyWidget(m)
        return pn.pane.Alert("Currently not working. C.f. issue [#2593](https://github.com/holoviz/panel/issues/2593)", alert_type="info")
class Matplotlib(ComponentBase):
    component =  param.Parameter(pn.pane.Matplotlib)
    reference = param.String("https://panel.holoviz.org/reference/panes/Matplotlib.html#panes-gallery-matplotlib")

    def example(self, theme="default", accent_base_color="blue"):
        import matplotlib.pyplot as plt
        import numpy as np
        from matplotlib import cm
        from matplotlib.backends.backend_agg import \
            FigureCanvas  # not needed for mpl >= 3.1
        from matplotlib.figure import Figure

        plt.style.use("default")
        if theme=="dark":
            plt.style.use("dark_background")
        Y, X = np.mgrid[-3:3:100j, -3:3:100j]
        U = -1 - X**2 + Y
        V = 1 + X - Y**2
        speed = np.sqrt(U*U + V*V)

        fig0 = Figure(figsize=(12, 6))
        ax0 = fig0.subplots()
        FigureCanvas(fig0)  # not needed for mpl >= 3.1

        strm = ax0.streamplot(X, Y, U, V, color=U, linewidth=2, cmap=cm.autumn)
        fig0.colorbar(strm.lines)

        return pn.pane.Matplotlib(fig0, sizing_mode="stretch_both")

class Plotly(ComponentBase):
    component =  param.Parameter(pn.pane.Plotly)
    reference = param.String("https://panel.holoviz.org/reference/panes/Plotly.html#panes-gallery-plotly")
    extension = param.String("plotly")

    def example(self, theme="default", accent_base_color="blue"):
        import pandas as pd
        import plotly.express as px

        data = pd.DataFrame([
            ('Monday', 7), ('Tuesday', 4), ('Wednesday', 9), ('Thursday', 4),
            ('Friday', 4), ('Saturday', 4), ('Sunay', 4)], columns=['Day', 'Orders']
        )

        if theme=="dark":
            plotly_template="plotly_dark"
        else:
            plotly_template="plotly"

        fig = px.line(data, x="Day", y="Orders", template=plotly_template, color_discrete_sequence=(accent_base_color,))
        fig.update_traces(mode="lines+markers", marker=dict(size=10), line=dict(width=4))
        fig.layout.autosize = True

        return pn.pane.Plotly(fig, config={'responsive': True})

class Plotnine(ComponentBase):
    component =  param.Parameter(pn.pane.Matplotlib)
    reference = param.String("https://panel.holoviz.org/reference/panes/Matplotlib.html#panes-gallery-matplotlib")

    def example(self, theme="default", accent_base_color="blue"):
        import matplotlib.pyplot as plt
        from plotnine import (aes, element_rect, facet_wrap, geom_point,
                              ggplot, stat_smooth, themes)
        from plotnine.data import mtcars
        plt.style.use("default")
        if theme=="dark":
            plotnine_theme=themes.theme_dark() + themes.theme(plot_background=element_rect(fill='black', alpha=0))
        else:
            plotnine_theme=themes.theme_xkcd()

        plot=(
            (ggplot(mtcars, aes('wt', 'mpg', color='factor(gear)'))
            + geom_point()
            + stat_smooth(method='lm')
            + facet_wrap('~gear'))
            + plotnine_theme
            + themes.theme(figure_size=(16, 8))

        )
        return plot.draw()
class PyDeck(ComponentBase):
    component = param.Parameter(pn.pane.DeckGL)
    reference = param.String("https://panel.holoviz.org/reference/panes/DeckGL.html#pydeck")
    extension = param.String("deckgl")

    def example(self, theme="default", accent_base_color="blue"):
        import pydeck

        LAND_COVER = [[[-123.0, 49.196], [-123.0, 49.324], [-123.306, 49.324], [-123.306, 49.196]]]
        polygon = pydeck.Layer(
            'PolygonLayer',
            LAND_COVER,
            stroked=False,
            # processes the data as a flat longitude-latitude pair
            get_polygon='-',
            get_fill_color=[0, 0, 0, 20]
        )

        DATA_URL = "https://raw.githubusercontent.com/uber-common/deck.gl-data/master/examples/geojson/vancouver-blocks.json"
        geojson = pydeck.Layer(
            'GeoJsonLayer',
            DATA_URL,
            opacity=0.8,
            stroked=False,
            filled=True,
            extruded=True,
            wireframe=True,
            get_elevation='properties.valuePerSqm / 20',
            get_fill_color='[255, 255, properties.growth * 255]',
            get_line_color=[255, 255, 255],
            pickable=True
        )

        if theme=="dark":
            deckgl_map_style = "mapbox://styles/mapbox/dark-v9"
        else:
            deckgl_map_style = "mapbox://styles/mapbox/light-v9"
        MAPBOX_KEY = "pk.eyJ1IjoicGFuZWxvcmciLCJhIjoiY2s1enA3ejhyMWhmZjNobjM1NXhtbWRrMyJ9.B_frQsAVepGIe-HiOJeqvQ"
        INITIAL_VIEW_STATE = pydeck.ViewState(
            latitude=49.254,
            longitude=-123.13,
            zoom=11,
            max_zoom=16,
            pitch=45,
            bearing=0
        )

        r = pydeck.Deck(
            api_keys={'mapbox': MAPBOX_KEY},
            layers=[polygon, geojson],
            initial_view_state=INITIAL_VIEW_STATE,
            map_style=deckgl_map_style,
        )

        # Tooltip (you can get the id directly from the layer object)
        geojson_tooltip = {
            "html": """
            <b>Value per Square meter:</b> {properties.valuePerSqm}<br>
            <b>Growth:</b> {properties.growth}
            """,
            "style": {
                "backgroundColor": accent_base_color,
                "color": "white"
            }
        }
        tooltips = {geojson.id: geojson_tooltip}

        return pn.pane.DeckGL(r, tooltips=tooltips, height=600, sizing_mode="stretch_both")

class PyECharts(ComponentBase):
    component =  param.Parameter(pn.pane.ECharts)
    reference = param.String("https://panel.holoviz.org/reference/panes/ECharts.html#panes-gallery-echarts")
    extension = param.String("echarts")

    def example(self, theme="default", accent_base_color="blue"):
        from pyecharts.charts import Bar

        plot= (Bar()
            .add_xaxis(['Helicoptors', 'Planes', "Air Ballons"])
            .add_yaxis('Total In Flight', [50, 75, 25], color=accent_base_color)
        )

        # Workaround to make plot responsive
        import json
        plot=json.loads(plot.dump_options())
        plot["responsive"]=True

        return pn.pane.ECharts(plot, min_height=500, sizing_mode="stretch_both", theme=theme)

class PyVista(ComponentBase):
    component =  param.Parameter(pn.pane.VTK)
    reference = param.String("https://panel.holoviz.org/reference/panes/VTK.html#working-with-pyvista")
    extension = param.String("vtk")

    def example(self, theme="default", accent_base_color="blue"):
        import pyvista as pv

        plotter = pv.Plotter() # we define a pyvista plotter
        if theme=="dark":
            plotter.background_color = (0.13, 0.13, 0.13)
        else:
            plotter.background_color = (0.97,0.97,0.97)

        # we create a `VTK` panel around the render window
        pvcylinder = pv.Cylinder(resolution=8, direction=(0,1,0))
        cylinder_actor = plotter.add_mesh(pvcylinder, color=accent_base_color, smooth_shading=True)
        cylinder_actor.RotateX(30.0)
        cylinder_actor.RotateY(-45.0)
        sphere_actor = plotter.add_mesh(pv.Sphere(
            theta_resolution=8, phi_resolution=8,
            center=(0.5, 0.5, 0.5)),color=accent_base_color, smooth_shading=True
        )
        return pn.panel(plotter.ren_win, height=500, sizing_mode="stretch_both")

class Seaborn(ComponentBase):
    component =  param.Parameter(pn.pane.Matplotlib)
    reference = param.String("https://panel.holoviz.org/reference/panes/Matplotlib.html#panes-gallery-matplotlib")

    def example(self, theme="default", accent_base_color="blue"):
        import matplotlib.pyplot as plt
        import seaborn as sns

        penguins = sns.load_dataset("penguins")

        if theme=="dark":
            sns.set_style("darkgrid")
            plt.style.use("dark_background")
        else:
            plt.style.use("default")
            sns.set_style("whitegrid")

        plot = sns.displot(penguins, x="flipper_length_mm", color=accent_base_color)
        fig0 = plot.fig
        fig0.set_size_inches(16,8)

        # FigureCanvas(fig0)  # not needed for mpl >= 3.1
        return pn.pane.Matplotlib(fig0, sizing_mode="stretch_both")

class Vega(ComponentBase):
    component =  param.Parameter("pn.pane.Vega")
    reference = param.String("https://panel.holoviz.org/reference/panes/Vega.html#altair")
    extension = param.String("vega")

    def example(self, theme="default", accent_base_color="blue"):
        vegalite = {
            "$schema": "https://vega.github.io/schema/vega-lite/v3.json",
            "data": {"url": "https://raw.githubusercontent.com/vega/vega/master/docs/data/barley.json"},
            "mark": {"type": "bar", "tooltip": True},
            "width": "container",
            "height": "container",
            "encoding": {
                "x": {"aggregate": "sum", "field": "yield", "type": "quantitative"},
                "y": {"field": "variety", "type": "nominal"},
                "color": {"field": "site", "type": "nominal"}
            }
        }

        if theme=="dark":
            vegalite["config"] = {
                "background": '#333',
                "title": { "color": "#fff" },
                "style": {
                    'guide-label': {
                        "fill": "#fff"
                    },
                    'guide-title': {
                        "fill": "#fff"
                    }
                },
                "axis": {
                    "domainColor": "#fff",
                    "gridColor": "#888",
                    "tickColor": "#fff"
                }
            }
        return pn.panel(vegalite, height=500, sizing_mode="stretch_both")

class VTK(ComponentBase):
    component =  param.Parameter("pn.pane.VTK")
    reference = param.String("https://panel.holoviz.org/reference/panes/VTK.html")
    extension = param.String("vtk")

    def example(self, theme="default", accent_base_color="blue"):
        import vtk
        from vtk.util.colors import tomato

        # This creates a polygonal cylinder model with eight circumferential
        # facets.
        cylinder = vtk.vtkCylinderSource()
        cylinder.SetResolution(8)

        # The mapper is responsible for pushing the geometry into the graphics
        # library. It may also do color mapping, if scalars or other
        # attributes are defined.
        cylinderMapper = vtk.vtkPolyDataMapper()
        cylinderMapper.SetInputConnection(cylinder.GetOutputPort())

        # The actor is a grouping mechanism: besides the geometry (mapper), it
        # also has a property, transformation matrix, and/or texture map.
        # Here we set its color and rotate it -22.5 degrees.
        cylinderActor = vtk.vtkActor()
        cylinderActor.SetMapper(cylinderMapper)
        cylinderActor.GetProperty().SetColor(tomato)
        # We must set ScalarVisibilty to 0 to use tomato Color
        cylinderMapper.SetScalarVisibility(0)
        cylinderActor.RotateX(30.0)
        cylinderActor.RotateY(-45.0)

        # Create the graphics structure. The renderer renders into the render
        # window.
        ren = vtk.vtkRenderer()
        renWin = vtk.vtkRenderWindow()
        renWin.AddRenderer(ren)

        # Add the actors to the renderer, set the background and size
        ren.AddActor(cylinderActor)
        if theme=="dark":
            ren.SetBackground(0.13, 0.13, 0.13)
        else:
            ren.SetBackground(0.97,0.97,0.97)

        return pn.pane.VTK(renWin, height=500, sizing_mode="stretch_both")

TOOLS = {
    "ALTAIR": Altair(),
    "BOKEH": Bokeh(),
    "DECKGL": DeckGL(),
    "ECHARTS": ECharts(),
    "HOLOVIEWS": HoloViews(),
    "HVPLOT": HVPlot(),
    "MATPLOTLIB": Matplotlib(),
    "PLOTLY": Plotly(),
    "PLOTNINE": Plotnine(),
    "PYDECK": PyDeck(),
    "PYECHARTS": PyECharts(),
    "PYVISTA": PyVista(),
    "SEABORN": Seaborn(),
    "VEGA": Vega(),
    "VTK": VTK(),
}

description = """
# Works with the tools you know and love

### To use Pythons Viz with Panel just wrap the python object into a `pn.panel`, a *layout* like `pn.Column` or a specific *pane* like `pn.pane.Matplotlib`
"""

def show(component="Altair"):
    component = TOOLS[component]
    return component.example()

def reference(component="Altair"):
    component = TOOLS[component]
    return f"[Reference Guide]({ component.reference })"

def code(component="Altair"):
    component = TOOLS[component]
    value = component.code()

    return pn.widgets.Ace(
        value=value,
        language="python",
        min_height=400,
        sizing_mode="stretch_both",
        disabled=True,
    )

select = pn.widgets.RadioButtonGroup(
    options=list(TOOLS.keys()), button_type="success", margin=(10, 0, 25, 0)
)
try:
    pn.state.location.sync(select, {"value": "component"})
except:
    pass

show = pn.bind(show, component=select)
reference = pn.bind(reference, component=select)
code = pn.bind(code, component=select)
component = pn.Column(
    select,
    pn.Tabs(
        pn.panel(show, sizing_mode="stretch_both", name="Component", margin=(25, 5, 0, 5)),
        pn.panel(code, name="Code", sizing_mode="stretch_both"),
        sizing_mode="stretch_both",
    ),
    pn.panel(reference),
    sizing_mode="stretch_both",
)

template = pn.template.FastListTemplate(
    title="Test",
    main_max_width="95%",
    main=[description, component],
)
template.config.raw_css.append(RAW_CSS)
template.servable()
MarcSkovMadsen commented 3 years ago

If I could get some help for where to look I could try to test if that is the problem and find a solution. But I don't have the mental model of what could be causing this. And where I should start looking.

philippjfr commented 3 years ago

Have you tried dispatching a window resize event after exiting fullscreen? Maybe with a small delay.

MarcSkovMadsen commented 3 years ago

Yes. I have tried opening the console manually and dispatching a resize event. I really hoped/ believed it would work. But it did not.

MarcSkovMadsen commented 3 years ago

The problem for me is that I don't understand how/ that stretching in maximized mode works in the first place. It's rather cumbersome to get it working across pane types.

If you look at the code you will see I have to wrap every pane in a panel like

pn.panel(pn.pane.NAMEOFPANE(object, min_height=500, sizing_mode="stretch_both"), sizing_mode="stretch_both")

for stretching to work when maximized. The behaviour of panes is not uniform. Some work without pn.panel. Some specifically need min_height. Some also works with height. Some work without min_height/ height.

philippjfr commented 3 years ago

pn.panel(pn.pane.NAMEOFPANE(object, min_height=500, sizing_mode="stretch_both"), sizing_mode="stretch_both")

That seems rather unlikely to me since pn.panel is a no-op when you just pass it an existing pane. The first line of pn.panel is:

    if isinstance(obj, Viewable):
        return obj

Can you provide an example where that is actually the case?

MarcSkovMadsen commented 3 years ago

Sure. Only the fourth option of the below stretches on full screen.

image

https://user-images.githubusercontent.com/42288570/128188216-193718e1-07f3-4ed6-a3ab-de54813597c7.mp4

Code

import inspect
import textwrap

import panel as pn
import param

pn.extension("vega", sizing_mode="stretch_width")

def example(theme="default", accent_base_color="blue"):
    import altair as alt
    from vega_datasets import data

    if theme=="dark":
        alt.themes.enable("dark")
    else:
        alt.themes.enable("default")

    cars = data.cars()
    plot = alt.Chart(cars).mark_circle(size=60).encode(
        x='Horsepower',
        y='Miles_per_Gallon',
        color='Origin',
        tooltip=['Name', 'Origin', 'Horsepower', 'Miles_per_Gallon']
    ).properties(
        height="container",
        width="container",
    ).interactive()
    return pn.pane.Vega(plot, height=500, sizing_mode="stretch_both")

TOOLS = ["ALTAIR"]

def show(component="Altair"):
    return example()

select = pn.widgets.RadioButtonGroup(
    options=TOOLS, button_type="success", margin=(10, 0, 25, 0)
)
show_interactive = pn.bind(show, component=select)

template = pn.template.FastListTemplate(
    title="Test",
    main_max_width="95%",
    main=[
        show,
        pn.panel(show, sizing_mode="stretch_both"),
        show_interactive,
        pn.panel(show_interactive, sizing_mode="stretch_both"),],
)
template.servable()
philippjfr commented 3 years ago

All four look identical to me when I try it.

MarcSkovMadsen commented 3 years ago

Do they stretch or not?

philippjfr commented 3 years ago

They all stretch.

MarcSkovMadsen commented 3 years ago

But you can see in my video they don't right :-) Only option 4.

philippjfr commented 3 years ago

Ah, nvm, sorry. I was confused, but your example is nothing like you were claiming above, i.e. this:

pn.panel(pn.pane.NAMEOFPANE(object, min_height=500, sizing_mode="stretch_both"), sizing_mode="stretch_both")

is nothing like:

def example():
    return pn.pane.NAMEOFPANE(object, min_height=500, sizing_mode="stretch_both")

pn.panel(example, sizing_mode="stretch_both")
philippjfr commented 3 years ago

I do see what you're getting at though, you're saying dynamic functions should inherit the sizing options of the objects they are returning.

MarcSkovMadsen commented 3 years ago

hmm. I am not saying that. But now I understand that they don't :-)

philippjfr commented 3 years ago

That's indeed a pain point and I've tried addressing that in the past. The main problem we face here now is that I can't really change this behavior in a patch release, i.e. in 0.12.1, because it's a backward compatibility breaking change. Would like to fix that for 0.13 though.

MarcSkovMadsen commented 3 years ago

It's not a must have right now. But eventually full screen, maximize should just work for users. So 0.13 would be fine.

Just to be sure. If you run the example above you see the same behaviour as I do, i.e. first 3 panels not stretching while the 4th does?

philippjfr commented 3 years ago

Just to be sure. If you run the example above you see the same behaviour as I do, i.e. first 3 panels not stretching while the 4th does?

Yes, sorry for the confusion. Basically for full clarity here, if you supply a function to Panel it wraps that function in an Interactive or ParamFunction pane, which are both types of ReplacementPane. The ReplacementPane evaluates the function and then replaces the contents of a layout with the return value of the function (or in certain cases simply updates the existing pane). The layout issue arises because the layout the contents are wrapped in has its own layout options, which are distinct of the layout options of the return value of the function. What I would perhaps propose is that we:

1) Add an inherit_layout option to the ReplacementPane 2) In Panel 0.13 we consider if we want to enable this option by default

MarcSkovMadsen commented 3 years ago

Would the inherit_layout option be nescessary? I would claim its simpler (and 99.9% correct) to assume inherit_layout=True is what users want. And adding the complexity of implementation, maintenance, documentation and communication is not worth it?

MarcSkovMadsen commented 3 years ago

Just for the record. I've added a fifth panel. And that stretches nicely, which makes sense based on the above discussion.

image

philippjfr commented 3 years ago

I don't think we can make such a substantial change in behavior without providing a way to go back and this would also allow us to let people opt in to the new behavior before enabling it by default in 0.13.

MarcSkovMadsen commented 3 years ago

Ok. Makes sense.

MarcSkovMadsen commented 3 years ago

I still don't understand why the second panel does not stretch based on the discussion.

image

philippjfr commented 3 years ago

Seems like a bug in the interactive pane:

from panel.interact import interactive
print(interactive(show, sizing_mode="stretch_both").layout)
Column(sizing_mode='stretch_width')
    [0] Column(sizing_mode='stretch_width')
    [1] Row(sizing_mode='stretch_width')
        [0] Vega(Chart, height=500, sizing_mode='stretch_both')
MarcSkovMadsen commented 3 years ago

We discovered some good bugs here :-)

andhuang-CLGX commented 2 years ago

Is there a way to get full screen without using a template?

MarcSkovMadsen commented 2 years ago

Carve out the code for maximizing and create a custom component. For example based on ReactiveHTML.

philippjfr commented 1 year ago

@MarcSkovMadsen Could you try to make sense of the current state of this on main? I'm having a tough time keeping track of stuff here.

philippjfr commented 1 year ago

Appears to be fixed.