Hello, Markdown!
Use marimo’s “md
” function to embed rich text into your marimo apps. This function compiles Markdown into HTML that marimo can display.
For example, here’s the code that rendered the above title and paragraph:
mo.md(
'''
# Hello, Markdown!
Use marimo's "`md`" function to embed rich text into your marimo
apps. This function compiles your Markdown into HTML that marimo
can display.
'''
)
LaTeX
You can embed LaTeX in Markdown.
For example,
mo.md(r'$f : \mathbf{R} \to \mathbf{R}$')
renders \(f : \mathbf{R} \to \mathbf{R}\), while
mo.md(
r'''
\[
f: \mathbf{R} \to \mathbf{R}
\]
'''
)
renders the display math
[ f: . ]
Use r''
strings to remove the need to escape backslashes when writing LaTeX.
mo.accordion(%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%22Tip%3A%20%60r''%60%20strings%22%3A%20mo.md(%0A%20%20%20%20%20%20%20%20%20%20%20%20%22Use%20%60r''%60%20strings%20to%20remove%20the%20need%20to%20escape%20backslashes%22%0A%20%20%20%20%20%20%20%20%20%20%20%20%22%20when%20writing%20LaTeX.%22%0A%20%20%20%20%20%20%20%20)%0A%20%20%20%20%7D%0A)
Interpolating Python values
You can interpolate Python values into markdown using f-strings
and marimo’s as_html
function. This lets you create markdown whose contents depend on data that changes at runtime.
Here are some examples.
Plots
A matplotlib figure:
_x = np.linspace(start=0, stop=2*np.pi)
sine_plot = plt.plot(_x, np.sin(_x))
mo.md(f"{mo.as_html(sine_plot)}")
yields
def%20_sine_plot()%3A%0A%20%20%20%20if%20not%20numpy_installed%3A%0A%20%20%20%20%20%20%20%20return%20missing_numpy_msg%0A%20%20%20%20if%20not%20matplotlib_installed%3A%0A%20%20%20%20%20%20%20%20return%20missing_matplotlib_msg%0A%20%20%20%20_x%20%3D%20np.linspace(start%3D0%2C%20stop%3D2%20*%20np.pi)%0A%20%20%20%20plt.plot(_x%2C%20np.sin(_x))%0A%20%20%20%20return%20plt.gca()%0A%0A%0Amo.md(%0A%20%20%20%20f%22%22%22%0A%20%20%20%20%23%23%23%20Plots%0A%20%20%20%20A%20matplotlib%20figure%3A%0A%0A%20%20%20%20%60%60%60python3%0A%20%20%20%20_x%20%3D%20np.linspace(start%3D0%2C%20stop%3D2*np.pi)%0A%20%20%20%20sine_plot%20%3D%20plt.plot(_x%2C%20np.sin(_x))%0A%20%20%20%20mo.md(f%22%7B%7Bmo.as_html(sine_plot)%7D%7D%22)%0A%20%20%20%20%60%60%60%0A%20%20%20%20yields%0A%0A%20%20%20%20%7Bmo.as_html(_sine_plot())%7D%0A%20%20%20%20%22%22%22%0A)
UI elements
A marimo.ui
object:
leaves = mo.ui.slider(1, 16, label="🍃: ")
mo.md(f"{leaves}")
yields
leaves%20%3D%20mo.ui.slider(1%2C%2032%2C%20label%3D%22%F0%9F%8D%83%3A%20%22)%0A%0Amo.md(%0A%20%20%20%20f%22%22%22%0A%20%20%20%20%23%23%23%20UI%20elements%0A%0A%20%20%20%20A%20%60marimo.ui%60%20object%3A%0A%0A%20%20%20%20%60%60%60python3%0A%20%20%20%20leaves%20%3D%20mo.ui.slider(1%2C%2016%2C%20label%3D%22%F0%9F%8D%83%3A%20%22)%0A%20%20%20%20mo.md(f%22%7B%7Bleaves%7D%7D%22)%0A%20%20%20%20%60%60%60%0A%0A%20%20%20%20yields%0A%0A%20%20%20%20%7Bleaves%7D%0A%20%20%20%20%22%22%22%0A)
Your leaves: 🍃
mo.md(f%22Your%20leaves%3A%20%7B'%F0%9F%8D%83'%20*%20leaves.value%7D%22)
marimo objects know how to format themselves, so you can omit the
call to as_html
.
mo.accordion(%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%22Tip%3A%20UI%20elements%20can%20format%20themselves%22%3A%20%22%22%22%0A%20%20%20%20%20%20%20%20marimo%20objects%20know%20how%20to%20format%20themselves%2C%20so%20you%20can%20omit%20the%20%0A%20%20%20%20%20%20%20%20call%20to%20%60as_html%60.%0A%20%20%20%20%20%20%20%20%22%22%22%0A%20%20%20%20%7D%0A)
Other objects
Use mo.as_html
to convert objects to HTML. This function
generates rich HTML for many Python types, including:
- lists, dicts, and tuples,
pandas
dataframes and series,
seaborn
figures,
plotly
figures, and
altair
figures.
For example, here's a pandas dataframe:
| x | sin(x) |
---|
0 | 0.000000 | 0.000000e+00 |
---|
1 | 0.698132 | 6.427876e-01 |
---|
2 | 1.396263 | 9.848078e-01 |
---|
3 | 2.094395 | 8.660254e-01 |
---|
4 | 2.792527 | 3.420201e-01 |
---|
5 | 3.490659 | -3.420201e-01 |
---|
6 | 4.188790 | -8.660254e-01 |
---|
7 | 4.886922 | -9.848078e-01 |
---|
8 | 5.585054 | -6.427876e-01 |
---|
9 | 6.283185 | -2.449294e-16 |
---|
def%20make_dataframe()%3A%0A%20%20%20%20try%3A%0A%20%20%20%20%20%20%20%20import%20pandas%20as%20pd%0A%20%20%20%20except%20ModuleNotFoundError%3A%0A%20%20%20%20%20%20%20%20return%20mo.md(%22Oops!%20Looks%20like%20you%20don't%20have%20%60pandas%60%20installed.%22)%0A%0A%20%20%20%20if%20not%20numpy_installed%3A%0A%20%20%20%20%20%20%20%20return%20missing_numpy_msg%0A%0A%20%20%20%20x%20%3D%20np.linspace(0%2C%202%20*%20np.pi%2C%2010)%0A%20%20%20%20y%20%3D%20np.sin(x)%0A%20%20%20%20return%20pd.DataFrame(%7B%22x%22%3A%20x%2C%20%22sin(x)%22%3A%20y%7D)%0A%0A%0Amo.md(%0A%20%20%20%20f%22%22%22%0A%20%20%20%20%23%23%23%20Other%20objects%0A%0A%20%20%20%20Use%20%60mo.as_html%60%20to%20convert%20objects%20to%20HTML.%20This%20function%0A%20%20%20%20generates%20rich%20HTML%20for%20many%20Python%20types%2C%20including%3A%0A%0A%20%20%20%20-%20lists%2C%20dicts%2C%20and%20tuples%2C%0A%20%20%20%20-%20%60pandas%60%20dataframes%20and%20series%2C%0A%20%20%20%20-%20%60seaborn%60%20figures%2C%0A%20%20%20%20-%20%60plotly%60%20figures%2C%20and%0A%20%20%20%20-%20%60altair%60%20figures.%0A%0A%20%20%20%20For%20example%2C%20here's%20a%20pandas%20dataframe%3A%0A%0A%20%20%20%20%7Bmo.as_html(make_dataframe())%7D%0A%20%20%20%20%22%22%22%0A)
mo.as_html
is only needed when interpolating objects into
markdown; the last expression of a cell (its output) is
converted to HTML automatically.
mo.accordion(%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%22Tip%3A%20outputs%20are%20automatically%20converted%20to%20HTML%22%3A%20%22%22%22%0A%20%20%20%20%20%20%20%20%60mo.as_html%60%20is%20only%20needed%20when%20interpolating%20objects%20into%20%0A%20%20%20%20%20%20%20%20markdown%3B%20the%20last%20expression%20of%20a%20cell%20(its%20output)%20is%20%0A%20%20%20%20%20%20%20%20converted%20to%20HTML%20automatically.%0A%20%20%20%20%20%20%20%20%22%22%22%0A%20%20%20%20%7D%0A)
Putting it all together
Here’s a more interesting example that puts together everything we’ve learned: rendering markdown with LaTeX that depends on the values of Python objects.
amplitude%20%3D%20mo.ui.slider(1%2C%202%2C%20step%3D0.1%2C%20label%3D%22amplitude%3A%20%22)%0Aperiod%20%3D%20mo.ui.slider(%0A%20%20%20%20math.pi%20%2F%204%2C%0A%20%20%20%204%20*%20math.pi%2C%0A%20%20%20%20value%3D2%20*%20math.pi%2C%0A%20%20%20%20step%3Dmath.pi%20%2F%208%2C%0A%20%20%20%20label%3D%22period%3A%20%22%2C%0A)
import%20functools%0A%0A%0A%40functools.cache%0Adef%20plotsin(amplitude%2C%20period)%3A%0A%20%20%20%20if%20not%20numpy_installed%3A%0A%20%20%20%20%20%20%20%20return%20missing_numpy_msg%0A%20%20%20%20elif%20not%20matplotlib_installed%3A%0A%20%20%20%20%20%20%20%20return%20missing_matplotlib_msg%0A%20%20%20%20x%20%3D%20np.linspace(0%2C%202%20*%20np.pi%2C%20256)%0A%20%20%20%20plt.plot(x%2C%20amplitude%20*%20np.sin(2%20*%20np.pi%20%2F%20period%20*%20x))%0A%20%20%20%20plt.ylim(-2.2%2C%202.2)%0A%20%20%20%20return%20plt.gca()
A sin curve.
mo.md(%0A%20%20%20%20f%22%22%22%0A%0A%20%20%20%20%20%20**A%20sin%20curve.**%0A%0A%20%20%20%20%20%20-%20%7Bamplitude%7D%0A%20%20%20%20%20%20-%20%7Bperiod%7D%0A%20%20%20%20%20%20%22%22%22%0A)
You're viewing the graph of
||[
f(x) = 1.0\sin((2\pi/6.28)x),
||]with ||(x||) ranging from ||(0||) to ||(2\pi||).
mo.md(%0A%20%20%20%20rf%22%22%22%0A%0A%20%20%20%20You're%20viewing%20the%20graph%20of%0A%0A%20%20%20%20%5C%5B%0A%20%20%20%20f(x)%20%3D%20%7Bamplitude.value%7D%5Csin((2%5Cpi%2F%7Bperiod.value%3A0.2f%7D)x)%2C%0A%20%20%20%20%5C%5D%0A%0A%20%20%20%20with%20%24x%24%20ranging%20from%20%240%24%20to%20%242%5Cpi%24.%0A%20%20%20%20%7Bmo.as_html(plotsin(amplitude.value%2C%20period.value))%7D%0A%20%20%20%20%22%22%22%0A)
matplotlib_installed%20%3D%20False%0Anumpy_installed%20%3D%20False%0Amissing_numpy_msg%20%3D%20mo.md(%22Oops!%20Looks%20like%20you%20don't%20have%20%60numpy%60%20installed.%22)%0Amissing_matplotlib_msg%20%3D%20mo.md(%0A%20%20%20%20%22Oops!%20Looks%20like%20you%20don't%20have%20%60matplotlib%60%20installed.%22%0A)%0A%0Atry%3A%0A%20%20%20%20import%20matplotlib.pyplot%20as%20plt%0A%0A%20%20%20%20matplotlib_installed%20%3D%20True%0Aexcept%20ModuleNotFoundError%3A%0A%20%20%20%20pass%0A%0Atry%3A%0A%20%20%20%20import%20numpy%20as%20np%0A%0A%20%20%20%20numpy_installed%20%3D%20True%0Aexcept%20ModuleNotFoundError%3A%0A%20%20%20%20pass
import%20math%0A%0Aimport%20marimo%20as%20mo
Back to top