Using plt.show with plots that depend on input values causes severe flickering
Describe the bug
Using plt.show() to show matplotlib plots works fine for static plots. However, it causes extreme flickering when the plot is redrawn every time an input value (e.g. slider value) changes:
https://github.com/user-attachments/assets/e0e729a8-c1cc-407f-8028-0c9fc56e4910
Environment
{
"marimo": "0.11.25",
"OS": "Windows",
"OS Version": "10",
"Processor": "Intel64 Family 6 Model 183 Stepping 1, GenuineIntel",
"Python Version": "3.12.6",
"Binaries": {
"Browser": "134.0.6998.117",
"Node": "v20.12.2"
},
"Dependencies": {
"click": "8.1.7",
"docutils": "0.21.2",
"itsdangerous": "2.2.0",
"jedi": "0.19.1",
"markdown": "3.7",
"narwhals": "1.31.0",
"packaging": "24.1",
"psutil": "6.0.0",
"pygments": "2.18.0",
"pymdown-extensions": "10.12",
"pyyaml": "6.0.2",
"ruff": "0.11.2",
"starlette": "0.45.3",
"tomlkit": "0.13.2",
"typing-extensions": "4.12.2",
"uvicorn": "0.34.0",
"websockets": "15.0"
},
"Optional Dependencies": {
"pandas": "2.2.3"
},
"Experimental Flags": {}
}
Code to reproduce
import marimo
__generated_with = "0.11.25"
app = marimo.App(width="medium")
@app.cell
def _():
import marimo as mo
return (mo,)
@app.cell
def _(mo):
v = mo.ui.slider(start=6.28, stop=62.8, step=0.1, show_value=True)
v
return (v,)
@app.cell
def _(v):
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(0, 1, 0.001)
y = np.sin(x * v.value)
plt.plot(x, y)
plt.show()
return np, plt, x, y
if __name__ == "__main__":
app.run()
You need to .gca() instead of .show(). The latter prints to the console output which gets cleared on each run (causing the flicker). The former is sent to the cell output and the recommended way to use matplotlib in marimo
I see. I understand why it works this way on a technical level, but as a user this seems like bad UX. No other environment functions like this and the docs even explicitly advertise that Marimo works like other environments:
Just import your plotting library of choice and use it as you normally would.
(from https://docs.marimo.io/guides/working_with_data/plotting/)
PS: I know the docs mention using plt.gca() instead of plt.show(), but that is an easy detail to miss when you are just skimming and the page starts with a clear claim that plotting libraries function the same as in any other environment.
Yea, we can look into debouncing the clearing of the console output to give new output a change to replace it without a flicker
Hmm, I'm also seing bad flickering with plt.gca() when using mo.mpl.interactive. The window jumps up and down while the div for the interactive plot appears and disappears.
import marimo
__generated_with = "0.11.25"
app = marimo.App(width="medium")
@app.cell
def _():
import marimo as mo
return (mo,)
@app.cell
def _(mo):
v = mo.ui.slider(start=6.28, stop=62.8, step=0.1, show_value=True)
v
return (v,)
@app.cell
def _(v):
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(0, 1, 0.001)
y = np.sin(x * v.value)
plt.plot(x, y)
mo.mpl.interactive(plt.gca())
return np, plt, x, y
if __name__ == "__main__":
app.run()
I found a fix for my issue which is way faster. I have matplotlib output SVGs and show them in HTML elements:
def show_svg():
import io
f = io.BytesIO()
plt.savefig(f, format = "svg")
svg_str = f.getvalue()
return mo.Html(svg_str.decode('utf-8'))
Then I added sliders and such to replace the interactive mode.
@marcelroed this is neat! StringIO works too, no need for decode.
This gives you access to all the extra styling; you will often need bbox_inches="tight":
savefig(fname, *, transparent=None, dpi='figure', format=None,
metadata=None, bbox_inches=None, pad_inches=0.1,
facecolor='auto', edgecolor='auto', backend=None,
**kwargs
)
Normally it takes ~100 ms to solve some ODEs and draw these plots. Then I leave the notebook alone and after a while marimo gets very very slow, 5-10 seconds to respond to slider change. VPN reconnection may or may not be involved. Restarting kernel helps.
@mscolnick any tips on diagnosis / prevention? Nothing helpful in browser console or marimo logs (have not tried debug).
@liquidcarbon im not sure i have any ideas without seeing code or playing around with it myself.