Hello, Markdown!
Use marimo’s “md” function to write markdown. 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.
'''
)
Tip: toggling between the Markdown and Python editor
Although markdown is written with mo.md, marimo provides a markdown editor that hides this boilerplate from you.
Toggle between the Markdown and Python editors by clicking the blue icon in the top-right of the editor, entering Ctrl/Cmd+Shift+M, or using the “cell actions menu”. You can also hide the markdown editor through the cell actions menu.
Tip: To interpolate Python values into markdown strings, you’ll need to use mo.md(f"...") directly; the markdown view does not support f-strings. ## 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)
marimo actually uses KaTeX, a math typesetting library for the
web which supports a subset of LaTeX. For a list of
(un)supported commands, visit
https://katex.org/docs/support_table
mo.accordion(%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%22Note%3A%20KaTeX%22%3A%20mo.md(%0A%20%20%20%20%20%20%20%20%20%20%20%20%22%22%22%0A%20%20%20%20%20%20%20%20%20%20%20%20marimo%20actually%20uses%20KaTeX%2C%20a%20math%20typesetting%20library%20for%20the%0A%20%20%20%20%20%20%20%20%20%20%20%20web%20which%20supports%20a%20subset%20of%20LaTeX.%20For%20a%20list%20of%0A%20%20%20%20%20%20%20%20%20%20%20%20(un)supported%20commands%2C%20visit%0A%20%20%20%20%20%20%20%20%20%20%20%20https%3A%2F%2Fkatex.org%2Fdocs%2Fsupport_table%0A%20%20%20%20%20%20%20%20%20%20%20%20%22%22%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.
def%20_sine_plot()%3A%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%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)
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)
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%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)
import%20polars%20as%20pl%0A%0Adef%20make_dataframe()%3A%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%20pl.DataFrame(%7B%22x%22%3A%20x%2C%20%22sin(x)%22%3A%20y%7D)%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%20Polars%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%0A%20%20%20%20%20%20%20%20markdown%3B%20the%20last%20expression%20of%20a%20cell%20(its%20output)%20is%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)
%40mo.cache%0Adef%20plotsin(amplitude%2C%20period)%3A%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()
mo.md(%0A%20%20%20%20f%22%22%22%0A%20%20%20%20**A%20sin%20curve.**%0A%0A%20%20%20%20-%20%7Bamplitude%7D%0A%20%20%20%20-%20%7Bperiod%7D%0A%20%20%20%20%22%22%22%0A)
mo.md(%0A%20%20%20%20rf%22%22%22%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)
import%20matplotlib.pyplot%20as%20plt%0Aimport%20numpy%20as%20np
import%20math%0A%0Aimport%20marimo%20as%20mo
Back to top