# What's a better pattern for displaying expensive to compute elements

**URL:** <https://discourse.holoviz.org/t/whats-a-better-pattern-for-displaying-expensive-to-compute-elements/7341>\
**Category:** Panel\
**Tags:** param, panel\
**Created:** [June 15, 2024, 4:19pm UTC](https://discourse.holoviz.org/t/whats-a-better-pattern-for-displaying-expensive-to-compute-elements/7341 "2024-06-15T16:19:01Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![GabrielM](https://discourse.holoviz.org/letter_avatar_proxy/v4/letter/g/f19dbf/32.png) [@GabrielM](https://discourse.holoviz.org/u/GabrielM)\
**Post date:** [June 15, 2024, 4:19pm UTC](https://discourse.holoviz.org/t/whats-a-better-pattern-for-displaying-expensive-to-compute-elements/7341/1 "2024-06-15T16:19:01Z")

</div>

I noticed a common pattern in my panel code:

```auto
from time import sleep

import numpy as np
import panel as pn
from matplotlib.figure import Figure

pn.extension(sizing_mode="stretch_width")

button = pn.widgets.Button(name="Click me")
select = pn.widgets.Select(name="Select")
layout = pn.Column()

def expensive_computation(s):
    sleep(1)
    print("expensive!")
    return pn.Column(pn.pane.Str(f"Selected: {s}"))

def expensive_2_step(s):
    layout.objects = [expensive_computation(s)]

pn.bind(expensive_2_step, select, watch=True)
select.options = ["a", "b", "c"]

def display(event):
    fig = Figure()
    ax = fig.add_subplot(111)
    ax.plot(np.random.rand(10))
    return pn.Column(select, pn.bind(lambda _: layout, select), fig)

pn.serve(
    pn.Column(
        button,
        pn.bind(display, button),
    )
)
    button,
        pn.bind(display, button),
    )
)

```

breakdown: clicking the button will refresh the whole layout

if you replace `pn.bind(lambda _: layout, select), fig)` with `pn.bind(expensive_computation, select), fig)` it will indeed perform the calculation on every redraw.

Is there a better pattern that still involves only panel components? Could panel do something in the future to implement this boilerplate for us in the background?

---

<div class="post-metadata">

**Author:** ![dleybel](https://discourse.holoviz.org/user_avatar/discourse.holoviz.org/dleybel/32/6147_2.png) [@dleybel](https://discourse.holoviz.org/u/dleybel)\
**Post date:** [June 20, 2024, 9:10pm UTC](https://discourse.holoviz.org/t/whats-a-better-pattern-for-displaying-expensive-to-compute-elements/7341/2 "2024-06-20T21:10:27Z")

</div>

Would caching suffice for your use case?  
[https://panel.holoviz.org/how\_to/caching/memoization.html](https://panel.holoviz.org/how_to/caching/memoization.html)

---

<div class="post-metadata">

**Author:** ![GabrielM](https://discourse.holoviz.org/letter_avatar_proxy/v4/letter/g/f19dbf/32.png) [@GabrielM](https://discourse.holoviz.org/u/GabrielM)\
**Post date:** [June 21, 2024, 8:08pm UTC](https://discourse.holoviz.org/t/whats-a-better-pattern-for-displaying-expensive-to-compute-elements/7341/3 "2024-06-21T20:08:13Z")

</div>

pn.cache is supposed to cache data. Simply adding pn.cache to

```auto
expensive_2_step

```

will break the example

---

<div class="post-metadata">

**Author:** ![dleybel](https://discourse.holoviz.org/user_avatar/discourse.holoviz.org/dleybel/32/6147_2.png) [@dleybel](https://discourse.holoviz.org/u/dleybel)\
**Post date:** [June 21, 2024, 8:48pm UTC](https://discourse.holoviz.org/t/whats-a-better-pattern-for-displaying-expensive-to-compute-elements/7341/4 "2024-06-21T20:48:50Z")

</div>

Try this pattern – I’m using `append` to build up the Column:

```python
from time import sleep

import numpy as np
import panel as pn

pn.extension(sizing_mode="stretch_width")

button = pn.widgets.Button(name="Click me")
select = pn.widgets.Select(name="Select", options=['a', 'b', 'c'])
layout = pn.Column()

def expensive_computation(s):
    sleep(1)
    print("expensive!")
    layout.append(pn.pane.Str(f"Selected: {s}"))
    return layout

pn.serve(pn.Column(button, select, pn.bind(expensive_computation, s=select)))

```

---

<div class="post-metadata">

**Author:** ![GabrielM](https://discourse.holoviz.org/letter_avatar_proxy/v4/letter/g/f19dbf/32.png) [@GabrielM](https://discourse.holoviz.org/u/GabrielM)\
**Post date:** [June 22, 2024, 9:13am UTC](https://discourse.holoviz.org/t/whats-a-better-pattern-for-displaying-expensive-to-compute-elements/7341/5 "2024-06-22T09:13:16Z")

</div>

I don’t exactly understand how this solves the issue. The original example replaces the objects of the layout instead of appending (which is wanted). Could you replicate the button’s functionality also in this example? The goal would be to be able to click the button and not re-trigger the expensive computation unnecesarily

---

<div class="post-metadata">

**Author:** ![GabrielM](https://discourse.holoviz.org/letter_avatar_proxy/v4/letter/g/f19dbf/32.png) [@GabrielM](https://discourse.holoviz.org/u/GabrielM)\
**Post date:** [June 22, 2024, 9:19am UTC](https://discourse.holoviz.org/t/whats-a-better-pattern-for-displaying-expensive-to-compute-elements/7341/6 "2024-06-22T09:19:34Z")

</div>

to clarify:

what I want is to have the behavior of the original code posted in this thread, with the simplicity of writing:

```auto
from time import sleep

import numpy as np
import panel as pn
from matplotlib.figure import Figure

pn.extension(sizing_mode="stretch_width")

button = pn.widgets.Button(name="Click me")
select = pn.widgets.Select(name="Select", options=["a", "b", "c"])
layout = pn.Column()

def expensive_computation(s):
    sleep(1)
    print("expensive!")
    return pn.Column(pn.pane.Str(f"Selected: {s}"))

def display(event):
    fig = Figure()
    ax = fig.add_subplot(111)
    ax.plot(np.random.rand(10))
    return pn.Column(select, pn.bind(expensive_computation, select), fig)

pn.serve(
    pn.Column(
        button,
        pn.bind(display, button),
    )
)

```
