HTML with Hiccup
In [1]:
Copied!
import genstudio.plot as Plot
from genstudio.plot import html, js
Plot.configure(display_as="html")
import genstudio.plot as Plot
from genstudio.plot import html, js
Plot.configure(display_as="html")
Plot.html
is a Python implementation of Clojure's Hiccup, which uses built-in data structures to represent HTML. The basic format of an html element is a list containing the element name, optional props, followed by any number of children:
In [2]:
Copied!
html(["p", {"style": {"border": "1px solid black"}}, "Hello, world!"])
html(["p", {"style": {"border": "1px solid black"}}, "Hello, world!"])
Out[2]:
CSS Classes & Tailwind¶
Add classes to an element either using the class
prop, or using the shorthand syntax:
In [3]:
Copied!
html(["p.bg-black.text-white", "Hello, world!"])
html(["p.bg-black.text-white", "Hello, world!"])
Out[3]:
Add attributes and nest elements:
In [4]:
Copied!
html(
[
"div",
{"style": {"fontSize": "20px"}},
[
"button.bg-blue-500.hover:bg-green-500.text-white.font-bold.py-2.px-4.rounded",
"Hover me",
],
]
)
html(
[
"div",
{"style": {"fontSize": "20px"}},
[
"button.bg-blue-500.hover:bg-green-500.text-white.font-bold.py-2.px-4.rounded",
"Hover me",
],
]
)
Out[4]:
Interactive Elements¶
Create an interactive slider using reactive $state
:
In [5]:
Copied!
html(
[
"div",
[
"input",
{
"type": "range",
"min": 0,
"max": 100,
"value": js("$state.sliderValue || 0"),
"onInput": js("(e) => $state.sliderValue = e.target.value"),
},
],
["p", js("`Current value: ${$state.sliderValue || 0}`")],
]
)
html(
[
"div",
[
"input",
{
"type": "range",
"min": 0,
"max": 100,
"value": js("$state.sliderValue || 0"),
"onInput": js("(e) => $state.sliderValue = e.target.value"),
},
],
["p", js("`Current value: ${$state.sliderValue || 0}`")],
]
)
Out[5]:
Combining with Observable Plot¶
Combine Plot.html with Observable Plot:
In [6]:
Copied!
(
Plot.line(
{"x": range(100)},
{
"y": js(
"""(d, i) => {
return Math.sin(i * 2 * Math.PI / 100 * $state.frequency)
}"""
)
},
)
+ Plot.domain([0, 99], [-1, 1])
+ {"height": 300, "width": 500}
) | Plot.Slider(
key="frequency",
label="Frequency:",
showValue=True,
range=[0.5, 5],
step=0.1,
init=1,
)
(
Plot.line(
{"x": range(100)},
{
"y": js(
"""(d, i) => {
return Math.sin(i * 2 * Math.PI / 100 * $state.frequency)
}"""
)
},
)
+ Plot.domain([0, 99], [-1, 1])
+ {"height": 300, "width": 500}
) | Plot.Slider(
key="frequency",
label="Frequency:",
showValue=True,
range=[0.5, 5],
step=0.1,
init=1,
)
Out[6]: