Restyle examples and add button to show code on all examples (#968)

This commit is contained in:
Fábio Rosado
2022-11-22 15:46:54 +00:00
committed by GitHub
parent 6700856b9f
commit a628026838
24 changed files with 2287 additions and 142 deletions

View File

@@ -4,10 +4,22 @@
<meta charset="utf-8"> <meta charset="utf-8">
<link rel="icon" type="image/x-icon" href="./favicon.png"> <link rel="icon" type="image/x-icon" href="./favicon.png">
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" /> <link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
<link rel="stylesheet" href="./assets/css/examples.css" />
<link rel="stylesheet" href="./assets/prism/prism.css" />
<script defer src="https://pyscript.net/latest/pyscript.js"></script> <script defer src="https://pyscript.net/latest/pyscript.js"></script>
<script defer src="./assets/prism/prism.js"></script>
</head> </head>
<body> <body>
<div id="altair" style="width: 100%; height: 100%"></div> <nav class="navbar" style="background-color: #000000;">
<div class="app-header">
<a href="/">
<img src="./logo.png" class="logo">
</a>
<a class="title" href="" style="color: #f0ab3c;">Altair</a>
</div>
</nav>
<section class="pyscript">
<div id="altair"></div>
<py-config> <py-config>
packages = [ packages = [
"altair", "altair",
@@ -16,47 +28,127 @@
] ]
</py-config> </py-config>
<py-script> <py-script>
import altair as alt import altair as alt
from vega_datasets import data from vega_datasets import data
source = data.movies.url source = data.movies.url
pts = alt.selection(type="single", encodings=['x']) pts = alt.selection(type="single", encodings=['x'])
rect = alt.Chart(data.movies.url).mark_rect().encode( rect = alt.Chart(data.movies.url).mark_rect().encode(
alt.X('IMDB_Rating:Q', bin=True), alt.X('IMDB_Rating:Q', bin=True),
alt.Y('Rotten_Tomatoes_Rating:Q', bin=True), alt.Y('Rotten_Tomatoes_Rating:Q', bin=True),
alt.Color('count()', alt.Color('count()',
scale=alt.Scale(scheme='greenblue'), scale=alt.Scale(scheme='greenblue'),
legend=alt.Legend(title='Total Records') legend=alt.Legend(title='Total Records')
) )
) )
circ = rect.mark_point().encode( circ = rect.mark_point().encode(
alt.ColorValue('grey'), alt.ColorValue('grey'),
alt.Size('count()', alt.Size('count()',
legend=alt.Legend(title='Records in Selection') legend=alt.Legend(title='Records in Selection')
) )
).transform_filter( ).transform_filter(
pts pts
) )
bar = alt.Chart(source).mark_bar().encode( bar = alt.Chart(source).mark_bar().encode(
x='Major_Genre:N', x='Major_Genre:N',
y='count()', y='count()',
color=alt.condition(pts, alt.ColorValue("steelblue"), alt.ColorValue("grey")) color=alt.condition(pts, alt.ColorValue("steelblue"), alt.ColorValue("grey"))
).properties( ).properties(
width=550, width=550,
height=200 height=200
).add_selection(pts) ).add_selection(pts)
display(alt.vconcat( display(alt.vconcat(
rect + circ, rect + circ,
bar bar
).resolve_legend( ).resolve_legend(
color="independent", color="independent",
size="independent" size="independent"
), target="altair") ), target="altair")
</py-script> </py-script>
</section>
<section class="code">
<div id="view-code-button" role="button" aria-pressed="false" tabindex="0">View Code</div>
<div id="code-section" class="code-section-hidden">
<p>index.html</p>
<pre class="prism-code language-html">
<code class="language-html">
&lt;py-config&gt;
packages = [
"altair",
"pandas",
"vega_datasets"
]
&lt;/py-config&gt;
&lt;py-script&gt;
import altair as alt
from vega_datasets import data
source = data.movies.url
pts = alt.selection(type="single", encodings=['x'])
rect = alt.Chart(data.movies.url).mark_rect().encode(
alt.X('IMDB_Rating:Q', bin=True),
alt.Y('Rotten_Tomatoes_Rating:Q', bin=True),
alt.Color('count()',
scale=alt.Scale(scheme='greenblue'),
legend=alt.Legend(title='Total Records')
)
)
circ = rect.mark_point().encode(
alt.ColorValue('grey'),
alt.Size('count()',
legend=alt.Legend(title='Records in Selection')
)
).transform_filter(
pts
)
bar = alt.Chart(source).mark_bar().encode(
x='Major_Genre:N',
y='count()',
color=alt.condition(pts, alt.ColorValue("steelblue"), alt.ColorValue("grey"))
).properties(
width=550,
height=200
).add_selection(pts)
display(alt.vconcat(
rect + circ,
bar
).resolve_legend(
color="independent",
size="independent"
), target="altair")
&lt;/py-script&gt;
</code>
</pre>
</div>
</section>
</body> </body>
<script>
const viewCodeButton = document.getElementById("view-code-button");
const codeSection = document.getElementById("code-section");
const handleClick = () => {
if (codeSection.classList.contains("code-section-hidden")) {
codeSection.classList.remove("code-section-hidden");
codeSection.classList.add("code-section-visible");
} else {
codeSection.classList.remove("code-section-visible");
codeSection.classList.add("code-section-hidden");
}
}
viewCodeButton.addEventListener("click", handleClick)
viewCodeButton.addEventListener("keydown", (e) => {
if (e.key === " " || e.key === "Enter" || e.key === "Spacebar") {
handleClick();
}
})
</script>
</html> </html>

View File

@@ -4,9 +4,21 @@
<meta charset="utf-8"> <meta charset="utf-8">
<link rel="icon" type="image/x-icon" href="./favicon.png"> <link rel="icon" type="image/x-icon" href="./favicon.png">
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" /> <link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
<link rel="stylesheet" href="./assets/css/examples.css" />
<link rel="stylesheet" href="./assets/prism/prism.css" />
<script defer src="https://pyscript.net/latest/pyscript.js"></script> <script defer src="https://pyscript.net/latest/pyscript.js"></script>
<script defer src="./assets/prism/prism.js"></script>
</head> </head>
<body> <body>
<nav class="navbar" style="background-color: #000000;">
<div class="app-header">
<a href="/">
<img src="./logo.png" class="logo">
</a>
<a class="title" href="" style="color: #f0ab3c;">Antigravity</a>
</div>
</nav>
<section class="pyscript">
<py-config> <py-config>
[[fetch]] [[fetch]]
files = ["./antigravity.py"] files = ["./antigravity.py"]
@@ -16,5 +28,91 @@
import antigravity import antigravity
antigravity.fly() antigravity.fly()
</py-script> </py-script>
</section>
<section class="code">
<div id="view-code-button" role="button" aria-pressed="false" tabindex="0">View Code</div>
<div id="code-section" class="code-section-hidden">
<p>index.html</p>
<pre class="prism-code language-html">
<code class="language-html">
&lt;py-config&gt;
[[fetch]]
files = ["./antigravity.py"]
&lt;/py-config&gt;
&lt;py-script&gt;
import antigravity
antigravity.fly()
&lt;/py-script&gt;
</code>
</pre>
<p>antigravity.py</p>
<pre class="prism-code language-python">
<code class="language-python">
import random
import sys
from js import DOMParser, document, setInterval
from pyodide.ffi import create_proxy
from pyodide.http import open_url
class Antigravity:
url = "./antigravity.svg"
def __init__(self, target=None, interval=10, append=True, fly=False):
target = target or sys.stdout._out
self.target = (
document.getElementById(target) if isinstance(target, str) else target
)
doc = DOMParser.new().parseFromString(
open_url(self.url).read(), "image/svg+xml"
)
self.node = doc.documentElement
if append:
self.target.append(self.node)
else:
self.target.replaceChildren(self.node)
self.xoffset, self.yoffset = 0, 0
self.interval = interval
if fly:
self.fly()
def fly(self):
setInterval(create_proxy(self.move), self.interval)
def move(self):
char = self.node.getElementsByTagName("g")[1]
char.setAttribute("transform", f"translate({self.xoffset}, {-self.yoffset})")
self.xoffset += random.normalvariate(0, 1) / 20
if self.yoffset < 50:
self.yoffset += 0.1
else:
self.yoffset += random.normalvariate(0, 1) / 20
_auto = Antigravity(append=True)
fly = _auto.fly
</code>
</div>
</section>
</body> </body>
<script>
const viewCodeButton = document.getElementById("view-code-button");
const codeSection = document.getElementById("code-section");
const handleClick = () => {
if (codeSection.classList.contains("code-section-hidden")) {
codeSection.classList.remove("code-section-hidden");
codeSection.classList.add("code-section-visible");
} else {
codeSection.classList.remove("code-section-visible");
codeSection.classList.add("code-section-hidden");
}
}
viewCodeButton.addEventListener("click", handleClick)
viewCodeButton.addEventListener("keydown", (e) => {
if (e.key === " " || e.key === "Enter" || e.key === "Spacebar") {
handleClick();
}
})
</script>
</html> </html>

View File

@@ -0,0 +1,90 @@
body {
margin: 0;
}
.pyscript {
margin: 0.5rem;
}
.code {
display: flex;
position: absolute;
right: 0px;
z-index: 9998;
top: 7rem;
}
@media (max-width: 1300px) {
.code:has(> .code-section-visible) {
width: 90%;
/* Absolute position is messing up the layout on small screens */
right: 70px;
}
}
.code-section-hidden {
width: 0px;
display: none;
}
.code-section-visible {
display: flex;
flex-direction: column;
width: 100%;
background-color: rgb(45 46 53 / 90%);
padding: 1rem;
border-radius: 10px 0px 0px 10px;
color: #c6c6c8;
}
.code-section-visible p{
margin: 0;
font-style: italic;
font-size: small;
}
.language-html, .language-python {
float: left;
}
#view-code-button {
writing-mode: tb-rl;
text-orientation: sideways-right;
background-color: #1D1D22;
color: white;
padding: 0.5rem;
border-radius: 5px;
cursor: pointer;
height: 81px;
}
nav {
position: sticky;
width: 100%;
top: 0;
left: 0;
z-index: 9999;
}
.logo {
padding-right: 10px;
font-size: 28px;
height: 30px;
max-width: inherit;
}
.title {
text-decoration: none;
text-decoration-line: none;
text-decoration-style: initial;
text-decoration-color: initial;
font-weight: 400;
font-size: 1.5em;
line-height: 2em;
white-space: nowrap;
}
.app-header {
display: flex;
align-items: center;
padding: 0.5rem 1rem;
}

View File

@@ -3,7 +3,7 @@
} }
.example h2{ .example h2{
color: #000000; /* color: #000000; */
font-family: "Inconsolata", monospace; font-family: "Inconsolata", monospace;
font-size: 2.25rem; font-size: 2.25rem;
margin-bottom: 1rem; margin-bottom: 1rem;
@@ -11,10 +11,14 @@
.card { .card {
height: 15rem; height: 15rem;
background-color: #FFFFFF; background-color: var(--color-secondary);
padding: 1rem; padding: 1rem;
-webkit-box-shadow: var(--card-shadow); border-radius: 10px;
box-shadow: var(--card-shadow); }
.card:hover, .card:hover a, .card:hover a:visited, .card:hover h2 {
background-color: var(--color-primary);
color: #1D1D22
} }
.card a h2 { .card a h2 {
@@ -24,6 +28,17 @@
font-size: 2.25rem; font-size: 2.25rem;
} }
.card a p {
color: var(--text-color);
}
a .card {
height: 100%;
display: flex;
flex-direction: column;
justify-content: space-between;
}
.card-content { .card-content {
height: 100%; height: 100%;
display: flex; display: flex;
@@ -31,6 +46,10 @@
justify-content: space-between; justify-content: space-between;
} }
.card-content a, .card-content a:visited {
color: var(--color-primary);
}
.container-card { .container-card {
max-width: 1500px; max-width: 1500px;
margin: 0 auto; margin: 0 auto;

View File

@@ -2,6 +2,14 @@
@import "./variables.css"; @import "./variables.css";
@import "./reset.css"; @import "./reset.css";
body {
background: #2D2E35 url('https://assets.anaconda.com/production/Content/1650828148240.png?w=3240&auto=compress%2Cformat&fit=crop&dm=1650828161&s=c558dc55e0ed1f8419a892e842a5728f') repeat-x center bottom / 250px;
background-attachment: fixed;
overflow-x: hidden;
color: var(--text-color)
}
.container { .container {
max-width: 1510px; max-width: 1510px;
margin: auto; margin: auto;
@@ -9,7 +17,6 @@
} }
.title-main { .title-main {
color: #000000;
font-size: 4.25rem; font-size: 4.25rem;
font-family: "Inconsolata", monospace; font-family: "Inconsolata", monospace;
text-align: center; text-align: center;

View File

@@ -1,4 +1,6 @@
:root { :root {
--color-primary: #2563eb; --color-primary: #FDA703;
--color-secondary: #1D1D22;
--text-color: white;
--card-shadow: 0px 5px 11px 0px rgb(0 0 0 / 15%); --card-shadow: 0px 5px 11px 0px rgb(0 0 0 / 15%);
} }

View File

@@ -0,0 +1,3 @@
/* PrismJS 1.29.0
https://prismjs.com/download.html#themes=prism-okaidia&languages=markup+clike+javascript+python */
code[class*=language-],pre[class*=language-]{color:#f8f8f2;background:0 0;text-shadow:0 1px rgba(0,0,0,.3);font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto;border-radius:.3em}:not(pre)>code[class*=language-],pre[class*=language-]{background:#272822}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#8292a2}.token.punctuation{color:#f8f8f2}.token.namespace{opacity:.7}.token.constant,.token.deleted,.token.property,.token.symbol,.token.tag{color:#f92672}.token.boolean,.token.number{color:#ae81ff}.token.attr-name,.token.builtin,.token.char,.token.inserted,.token.selector,.token.string{color:#a6e22e}.language-css .token.string,.style .token.string,.token.entity,.token.operator,.token.url,.token.variable{color:#f8f8f2}.token.atrule,.token.attr-value,.token.class-name,.token.function{color:#e6db74}.token.keyword{color:#66d9ef}.token.important,.token.regex{color:#fd971f}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}

File diff suppressed because one or more lines are too long

View File

@@ -14,9 +14,20 @@
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" /> <link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
<script defer src="https://pyscript.net/latest/pyscript.js"></script> <script defer src="https://pyscript.net/latest/pyscript.js"></script>
<link rel="stylesheet" href="./assets/css/examples.css" />
<link rel="stylesheet" href="./assets/prism/prism.css" />
<script defer src="./assets/prism/prism.js"></script>
</head> </head>
<body> <body>
<h1>Bokeh Example</h1> <nav class="navbar" style="background-color: #000000;">
<div class="app-header">
<a href="/">
<img src="./logo.png" class="logo">
</a>
<a class="title" href="" style="color: #f0ab3c;">Bokeh Example</a>
</div>
</nav>
<section class="pyscript">
<div id="myplot"></div> <div id="myplot"></div>
<py-config> <py-config>
@@ -45,6 +56,60 @@ p_json = json.dumps(json_item(p, "myplot"))
Bokeh.embed.embed_item(JSON.parse(p_json)) Bokeh.embed.embed_item(JSON.parse(p_json))
</py-script> </py-script>
</section>
<section class="code">
<div id="view-code-button" role="button" aria-pressed="false" tabindex="0">View Code</div>
<div id="code-section" class="code-section-hidden">
<p>index.html</p>
<pre class="prism-code language-html">
<code class="language-html">
&lt;py-config&gt;
packages = [
"bokeh",
"numpy"
]
&lt;/py-config&gt;
&lt;py-script id="main"&gt;
import json
import pyodide
</body> from js import Bokeh, console, JSON
from bokeh.embed import json_item
from bokeh.plotting import figure
from bokeh.resources import CDN
# create a new plot with default tools, using figure
p = figure(plot_width=400, plot_height=400)
# add a circle renderer with x and y coordinates, size, color, and alpha
p.circle([1, 2, 3, 4, 5], [6, 7, 2, 4, 5], size=15, line_color="navy", fill_color="orange", fill_alpha=0.5)
p_json = json.dumps(json_item(p, "myplot"))
Bokeh.embed.embed_item(JSON.parse(p_json))
&lt;/py-script&gt;
</code>
</pre>
</div>
</section>
</body>
<script>
const viewCodeButton = document.getElementById("view-code-button");
const codeSection = document.getElementById("code-section");
const handleClick = () => {
if (codeSection.classList.contains("code-section-hidden")) {
codeSection.classList.remove("code-section-hidden");
codeSection.classList.add("code-section-visible");
} else {
codeSection.classList.remove("code-section-visible");
codeSection.classList.add("code-section-hidden");
}
}
viewCodeButton.addEventListener("click", handleClick)
viewCodeButton.addEventListener("keydown", (e) => {
if (e.key === " " || e.key === "Enter" || e.key === "Spacebar") {
handleClick();
}
})
</script>
</html> </html>

View File

@@ -7,6 +7,9 @@
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-widgets-2.4.2.min.js"></script> <script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-widgets-2.4.2.min.js"></script>
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-tables-2.4.2.min.js"></script> <script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-tables-2.4.2.min.js"></script>
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-mathjax-2.4.2.min.js"></script> <script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-mathjax-2.4.2.min.js"></script>
<link rel="stylesheet" href="./assets/css/examples.css" />
<link rel="stylesheet" href="./assets/prism/prism.css" />
<script defer src="./assets/prism/prism.js"></script>
<script type="text/javascript"> <script type="text/javascript">
Bokeh.set_log_level("info"); Bokeh.set_log_level("info");
@@ -16,6 +19,15 @@
<script defer src="https://pyscript.net/latest/pyscript.js"></script> <script defer src="https://pyscript.net/latest/pyscript.js"></script>
</head> </head>
<body> <body>
<nav class="navbar" style="background-color: #000000;">
<div class="app-header">
<a href="/">
<img src="./logo.png" class="logo">
</a>
<a class="title" href="" style="color: #f0ab3c;">Bokeh Example</a>
</div>
</nav>
<section class="pyscript">
<h1>Bokeh Example</h1> <h1>Bokeh Example</h1>
<div id="myplot"></div> <div id="myplot"></div>
@@ -95,6 +107,110 @@ async def show(plot, target):
asyncio.ensure_future(show(row, 'myplot')) asyncio.ensure_future(show(row, 'myplot'))
</py-script> </py-script>
</section>
<section class="code">
<div id="view-code-button" role="button" aria-pressed="false" tabindex="0">View Code</div>
<div id="code-section" class="code-section-hidden">
<p>index.html</p>
<pre class="prism-code language-html">
<code class="language-html">
&lt;py-config&gt;
packages = [
"bokeh",
"numpy"
]
&lt;/py-config&gt;
&lt;py-script id="main"&gt;
import asyncio
import json
import pyodide
</body> from js import Bokeh, console, JSON
from bokeh import __version__
from bokeh.document import Document
from bokeh.embed.util import OutputDocumentFor, standalone_docs_json_and_render_items
from bokeh.models import Slider, Div
from bokeh.layouts import Row
from bokeh.protocol.messages.patch_doc import process_document_events
# create a new plot with default tools, using figure
p = Slider(start=0.1, end=10, value=1, step=.1, title="Amplitude")
div = Div(text=f'Amplitude is: {p.value}')
def callback(attr, old, new):
div.text = f'Amplitude is: {new}'
p.on_change('value', callback)
row = Row(children=[p, div])
def doc_json(model, target):
with OutputDocumentFor([model]) as doc:
doc.title = ""
docs_json, _ = standalone_docs_json_and_render_items(
[model], suppress_callback_warning=True
)
doc_json = list(docs_json.values())[0]
root_id = doc_json['roots']['root_ids'][0]
return doc, json.dumps(dict(
target_id = target,
root_id = root_id,
doc = doc_json,
version = __version__,
))
def _link_docs(pydoc, jsdoc):
def jssync(event):
if getattr(event, 'setter_id', None) is not None:
return
events = [event]
json_patch = jsdoc.create_json_patch_string(pyodide.ffi.to_js(events))
pydoc.apply_json_patch(json.loads(json_patch))
jsdoc.on_change(pyodide.ffi.create_proxy(jssync), pyodide.ffi.to_js(False))
def pysync(event):
json_patch, buffers = process_document_events([event], use_buffers=True)
buffer_map = {}
for (ref, buffer) in buffers:
buffer_map[ref['id']] = buffer
jsdoc.apply_json_patch(JSON.parse(json_patch), pyodide.ffi.to_js(buffer_map), setter_id='js')
pydoc.on_change(pysync)
async def show(plot, target):
pydoc, model_json = doc_json(plot, target)
views = await Bokeh.embed.embed_item(JSON.parse(model_json))
jsdoc = views[0].model.document
_link_docs(pydoc, jsdoc)
asyncio.ensure_future(show(row, 'myplot'))
&lt;/py-script&gt;
</code>
</pre>
</div>
</section>
</body>
<script>
const viewCodeButton = document.getElementById("view-code-button");
const codeSection = document.getElementById("code-section");
const handleClick = () => {
if (codeSection.classList.contains("code-section-hidden")) {
codeSection.classList.remove("code-section-hidden");
codeSection.classList.add("code-section-visible");
} else {
codeSection.classList.remove("code-section-visible");
codeSection.classList.add("code-section-hidden");
}
}
viewCodeButton.addEventListener("click", handleClick)
viewCodeButton.addEventListener("keydown", (e) => {
if (e.key === " " || e.key === "Enter" || e.key === "Spacebar") {
handleClick();
}
})
</script>
</html> </html>

View File

@@ -6,7 +6,9 @@
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" /> <link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
<script defer src="https://pyscript.net/latest/pyscript.js"></script> <script defer src="https://pyscript.net/latest/pyscript.js"></script>
<link rel="stylesheet" href="./assets/css/examples.css" />
<link rel="stylesheet" href="./assets/prism/prism.css" />
<script defer src="./assets/prism/prism.js"></script>
<style> <style>
.loading { .loading {
display: inline-block; display: inline-block;
@@ -27,6 +29,15 @@
</head> </head>
<body> <body>
<nav class="navbar" style="background-color: #000000;">
<div class="app-header">
<a href="/">
<img src="./logo.png" class="logo">
</a>
<a class="title" href="" style="color: #f0ab3c;">Simple d3 visualization</a>
</div>
</nav>
<section class="pyscript">
<b> <b>
Based on <i><a href="https://observablehq.com/@d3/learn-d3-shapes?collection=@d3/learn-d3>">Learn D3: Shapes</a></i> tutorial. Based on <i><a href="https://observablehq.com/@d3/learn-d3-shapes?collection=@d3/learn-d3>">Learn D3: Shapes</a></i> tutorial.
</b> </b>
@@ -165,6 +176,146 @@ for d in data:
.attr("dy", "1.3em") .attr("dy", "1.3em")
.text(d_py["value"])) .text(d_py["value"]))
</py-script> </py-script>
</section>
<section class="code">
<div id="view-code-button" role="button" aria-pressed="false" tabindex="0">View Code</div>
<div id="code-section" class="code-section-hidden">
<p>index.html</p>
<pre class="prism-code language-html">
<code class="language-html">
&lt;script&gt;
import * as d3 from "https://cdn.skypack.dev/pin/d3@v7.6.1-1Q0NZ0WZnbYeSjDusJT3/mode=imports,min/optimized/d3.js";
</body> const fruits = [
{name: "🍊", count: 21},
{name: "🍇", count: 13},
{name: "🍏", count: 8},
{name: "🍌", count: 5},
{name: "🍐", count: 3},
{name: "🍋", count: 2},
{name: "🍎", count: 1},
{name: "🍉", count: 1},
]
const fn = (d) => d.count
const data = d3.pie().value(fn)(fruits)
const arc = d3.arc()
.innerRadius(210)
.outerRadius(310)
.padRadius(300)
.padAngle(2 / 300)
.cornerRadius(8)
const js = d3.select("#js")
js.select(".loading").remove()
const svg = js
.append("svg")
.attr("viewBox", "-320 -320 640 640")
.attr("width", "400")
.attr("height", "400")
for (const d of data) {
svg.append("path")
.style("fill", "steelblue")
.attr("d", arc(d))
const text = svg.append("text")
.style("fill", "white")
.attr("transform", `translate(${arc.centroid(d).join(",")})`)
.attr("text-anchor", "middle")
text.append("tspan")
.style("font-size", "24")
.attr("x", "0").text(d.data.name)
text.append("tspan")
.style("font-size", "18")
.attr("x", "0")
.attr("dy", "1.3em")
.text(d.value)
}
&lt;/script&gt;
&lt;py-script&gt;
from pyodide.ffi import create_proxy, to_js
import d3
fruits = [
dict(name="🍊", count=21),
dict(name="🍇", count=13),
dict(name="🍏", count=8),
dict(name="🍌", count=5),
dict(name="🍐", count=3),
dict(name="🍋", count=2),
dict(name="🍎", count=1),
dict(name="🍉", count=1),
]
fn = create_proxy(lambda d, *_: d["count"])
data = d3.pie().value(fn)(to_js(fruits))
arc = (d3.arc()
.innerRadius(210)
.outerRadius(310)
.padRadius(300)
.padAngle(2 / 300)
.cornerRadius(8))
py = d3.select("#py")
py.select(".loading").remove()
svg = (py
.append("svg")
.attr("viewBox", "-320 -320 640 640")
.attr("width", "400")
.attr("height", "400"))
for d in data:
d_py = d.to_py()
(svg.append("path")
.style("fill", "steelblue")
.attr("d", arc(d)))
text = (svg.append("text")
.style("fill", "white")
.attr("transform", f"translate({arc.centroid(d).join(',')})")
.attr("text-anchor", "middle"))
(text.append("tspan")
.style("font-size", "24")
.attr("x", "0")
.text(d_py["data"]["name"]))
(text.append("tspan")
.style("font-size", "18")
.attr("x", "0")
.attr("dy", "1.3em")
.text(d_py["value"]))
&lt;/py-script&gt;
</code>
</pre>
</div>
</section>
</body>
<script>
const viewCodeButton = document.getElementById("view-code-button");
const codeSection = document.getElementById("code-section");
const handleClick = () => {
if (codeSection.classList.contains("code-section-hidden")) {
codeSection.classList.remove("code-section-hidden");
codeSection.classList.add("code-section-visible");
} else {
codeSection.classList.remove("code-section-visible");
codeSection.classList.add("code-section-hidden");
}
}
viewCodeButton.addEventListener("click", handleClick)
viewCodeButton.addEventListener("keydown", (e) => {
if (e.key === " " || e.key === "Enter" || e.key === "Spacebar") {
handleClick();
}
})
</script>
</html> </html>

View File

@@ -5,9 +5,21 @@
<link rel="icon" type="image/x-icon" href="./favicon.png"> <link rel="icon" type="image/x-icon" href="./favicon.png">
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" /> <link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
<script defer src="https://pyscript.net/latest/pyscript.js"></script> <script defer src="https://pyscript.net/latest/pyscript.js"></script>
<link rel="stylesheet" href="./assets/css/examples.css" />
<link rel="stylesheet" href="./assets/prism/prism.css" />
<script defer src="./assets/prism/prism.js"></script>
</head> </head>
<body> <body>
<div id="folium" style="width: 100%; height: 100%"></div> <nav class="navbar" style="background-color: #000000;">
<div class="app-header">
<a href="/">
<img src="./logo.png" class="logo">
</a>
<a class="title" href="" style="color: #f0ab3c;">Folium</a>
</div>
</nav>
<section class="pyscript">
<div id="folium"></div>
<py-config> <py-config>
packages = [ packages = [
@@ -49,5 +61,76 @@ folium.LayerControl().add_to(m)
display(m, target="folium") display(m, target="folium")
</py-script> </py-script>
</section>
<section class="code">
<div id="view-code-button" role="button" aria-pressed="false" tabindex="0">View Code</div>
<div id="code-section" class="code-section-hidden">
<p>index.html</p>
<pre class="prism-code language-html">
<code class="language-html">
&lt;div id="folium"&gt;&lt;/div&gt;
&lt;py-config&gt;
packages = [
"folium",
"pandas"
]
&lt;/py-config&gt;
&lt;py-script&gt;
import folium
import json
import pandas as pd
from pyodide.http import open_url
url = (
"https://raw.githubusercontent.com/python-visualization/folium/master/examples/data"
)
state_geo = f"{url}/us-states.json"
state_unemployment = f"{url}/US_Unemployment_Oct2012.csv"
state_data = pd.read_csv(open_url(state_unemployment))
geo_json = json.loads(open_url(state_geo).read())
m = folium.Map(location=[48, -102], zoom_start=3)
folium.Choropleth(
geo_data=geo_json,
name="choropleth",
data=state_data,
columns=["State", "Unemployment"],
key_on="feature.id",
fill_color="YlGn",
fill_opacity=0.7,
line_opacity=0.2,
legend_name="Unemployment Rate (%)",
).add_to(m)
folium.LayerControl().add_to(m)
display(m, target="folium")
&lt;/py-script&gt;
</code>
</pre>
</div>
</section>
</body> </body>
<script>
const viewCodeButton = document.getElementById("view-code-button");
const codeSection = document.getElementById("code-section");
const handleClick = () => {
if (codeSection.classList.contains("code-section-hidden")) {
codeSection.classList.remove("code-section-hidden");
codeSection.classList.add("code-section-visible");
} else {
codeSection.classList.remove("code-section-visible");
codeSection.classList.add("code-section-hidden");
}
}
viewCodeButton.addEventListener("click", handleClick)
viewCodeButton.addEventListener("keydown", (e) => {
if (e.key === " " || e.key === "Enter" || e.key === "Spacebar") {
handleClick();
}
})
</script>
</html> </html>

View File

@@ -8,17 +8,64 @@
<link rel="icon" type="image/png" href="favicon.png" /> <link rel="icon" type="image/png" href="favicon.png" />
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" /> <link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
<link rel="stylesheet" href="./assets/css/examples.css" />
<link rel="stylesheet" href="./assets/prism/prism.css" />
<script defer src="https://pyscript.net/latest/pyscript.js"></script> <script defer src="https://pyscript.net/latest/pyscript.js"></script>
<script defer src="./assets/prism/prism.js"></script>
</head> </head>
<body> <body>
<nav class="navbar" style="background-color: #000000;">
<div class="app-header">
<a href="/">
<img src="./logo.png" class="logo">
</a>
<a class="title" href="" style="color: #f0ab3c;">Hello World</a>
</div>
</nav>
<section class="pyscript">
Hello world! <br> Hello world! <br>
This is the current date and time, as computed by Python: This is the current date and time, as computed by Python:
<py-script> <py-script>
from datetime import datetime from datetime import datetime
now = datetime.now() now = datetime.now()
display(now.strftime("%m/%d/%Y, %H:%M:%S")) display(now.strftime("%m/%d/%Y, %H:%M:%S"))
</py-script> </py-script>
</section>
<section class="code">
<div id="view-code-button" role="button" aria-pressed="false" tabindex="0">View Code</div>
<div id="code-section" class="code-section-hidden">
<p>index.html</p>
<pre class="prism-code language-html">
<code class="language-html">
&lt;py-script&gt;
from datetime import datetime
now = datetime.now()
display(now.strftime("%m/%d/%Y, %H:%M:%S"))
&lt;/py-script&gt;
</code>
</pre>
</div>
</section>
</body> </body>
<script>
const viewCodeButton = document.getElementById("view-code-button");
const codeSection = document.getElementById("code-section");
const handleClick = () => {
if (codeSection.classList.contains("code-section-hidden")) {
codeSection.classList.remove("code-section-hidden");
codeSection.classList.add("code-section-visible");
} else {
codeSection.classList.remove("code-section-visible");
codeSection.classList.add("code-section-hidden");
}
}
viewCodeButton.addEventListener("click", handleClick)
viewCodeButton.addEventListener("keydown", (e) => {
if (e.key === " " || e.key === "Enter" || e.key === "Spacebar") {
handleClick();
}
})
</script>
</html> </html>

View File

@@ -5,8 +5,20 @@
<link rel="icon" type="image/x-icon" href="./favicon.png"> <link rel="icon" type="image/x-icon" href="./favicon.png">
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" /> <link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
<script defer src="https://pyscript.net/latest/pyscript.js"></script> <script defer src="https://pyscript.net/latest/pyscript.js"></script>
<link rel="stylesheet" href="./assets/css/examples.css" />
<link rel="stylesheet" href="./assets/prism/prism.css" />
<script defer src="./assets/prism/prism.js"></script>
</head> </head>
<body> <body>
<nav class="navbar" style="background-color: #000000;">
<div class="app-header">
<a href="/">
<img src="./logo.png" class="logo">
</a>
<a class="title" href="" style="color: #f0ab3c;">Matplotlib</a>
</div>
</nav>
<section class="pyscript">
<div id="mpl"></div> <div id="mpl"></div>
<py-config> <py-config>
@@ -50,5 +62,77 @@ ax1.set_title('tripcolor of Delaunay triangulation, flat shading')
display(fig1, target="mpl") display(fig1, target="mpl")
</py-script> </py-script>
</section>
<section class="code">
<div id="view-code-button" role="button" aria-pressed="false" tabindex="0">View Code</div>
<div id="code-section" class="code-section-hidden">
<p>index.html</p>
<pre class="prism-code language-html">
<code class="language-html">
&lt;div id="mpl"&gt;&lt;/div&gt;
&lt;py-config&gt;
packages = [
"matplotlib",
]
&lt;/py-config&gt;
&lt;py-script&gt;
import matplotlib.pyplot as plt
import matplotlib.tri as tri
import numpy as np
# First create the x and y coordinates of the points.
n_angles = 36
n_radii = 8
min_radius = 0.25
radii = np.linspace(min_radius, 0.95, n_radii)
angles = np.linspace(0, 2 * np.pi, n_angles, endpoint=False)
angles = np.repeat(angles[..., np.newaxis], n_radii, axis=1)
angles[:, 1::2] += np.pi / n_angles
x = (radii * np.cos(angles)).flatten()
y = (radii * np.sin(angles)).flatten()
z = (np.cos(radii) * np.cos(3 * angles)).flatten()
# Create the Triangulation; no triangles so Delaunay triangulation created.
triang = tri.Triangulation(x, y)
# Mask off unwanted triangles.
triang.set_mask(np.hypot(x[triang.triangles].mean(axis=1),
y[triang.triangles].mean(axis=1))
< min_radius)
fig1, ax1 = plt.subplots()
ax1.set_aspect('equal')
tpc = ax1.tripcolor(triang, z, shading='flat')
fig1.colorbar(tpc)
ax1.set_title('tripcolor of Delaunay triangulation, flat shading')
display(fig1, target="mpl")
&lt;/py-script&gt;
</code>
</pre>
</div>
</section>
</body>
<script>
const viewCodeButton = document.getElementById("view-code-button");
const codeSection = document.getElementById("code-section");
const handleClick = () => {
if (codeSection.classList.contains("code-section-hidden")) {
codeSection.classList.remove("code-section-hidden");
codeSection.classList.add("code-section-visible");
} else {
codeSection.classList.remove("code-section-visible");
codeSection.classList.add("code-section-hidden");
}
}
viewCodeButton.addEventListener("click", handleClick)
viewCodeButton.addEventListener("keydown", (e) => {
if (e.key === " " || e.key === "Enter" || e.key === "Spacebar") {
handleClick();
}
})
</script>
</body> </body>
</html> </html>

View File

@@ -5,7 +5,9 @@
<link rel="icon" type="image/x-icon" href="./favicon.png"> <link rel="icon" type="image/x-icon" href="./favicon.png">
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" /> <link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
<script defer src="https://pyscript.net/latest/pyscript.js"></script> <script defer src="https://pyscript.net/latest/pyscript.js"></script>
<link rel="stylesheet" href="./assets/css/examples.css" />
<link rel="stylesheet" href="./assets/prism/prism.css" />
<script defer src="./assets/prism/prism.js"></script>
<style> <style>
.loading { .loading {
display: inline-block; display: inline-block;
@@ -30,8 +32,15 @@
</head> </head>
<body> <body>
<b> <nav class="navbar" style="background-color: #000000;">
</b> <div class="app-header">
<a href="/">
<img src="./logo.png" class="logo">
</a>
<a class="title" href="" style="color: #f0ab3c;">Fractals with NumPy and canvas</a>
</div>
</nav>
<section class="pyscript">
<div style="display: flex; flex-direction: column; gap: 1em; width: 600px"> <div style="display: flex; flex-direction: column; gap: 1em; width: 600px">
<div id="mandelbrot"> <div id="mandelbrot">
<div style="text-align: center">Mandelbrot set</div> <div style="text-align: center">Mandelbrot set</div>
@@ -325,6 +334,281 @@ async def main():
asyncio.ensure_future(main()) asyncio.ensure_future(main())
</py-script> </py-script>
</section>
<section class="code">
<div id="view-code-button" role="button" aria-pressed="false" tabindex="0">View Code</div>
<div id="code-section" class="code-section-hidden">
<p>index.html</p>
<pre class="prism-code language-html">
<code class="language-html">
&lt;py-config type="json"&gt;
{
"packages": [
"numpy",
"sympy"
],
"fetch": [
{
"files": [
"./palettes.py",
"./fractals.py"
]
}
]
}
&lt;/py-config&gt;
&lt;py-script&gt;
from pyodide.ffi import to_js, create_proxy
</body> import numpy as np
import sympy
from palettes import Magma256
from fractals import mandelbrot, julia, newton
from js import (
console,
document,
devicePixelRatio,
ImageData,
Uint8ClampedArray,
CanvasRenderingContext2D as Context2d,
requestAnimationFrame,
)
def prepare_canvas(width: int, height: int, canvas: Element) -> Context2d:
ctx = canvas.getContext("2d")
canvas.style.width = f"{width}px"
canvas.style.height = f"{height}px"
canvas.width = width
canvas.height = height
ctx.clearRect(0, 0, width, height)
return ctx
def color_map(array: np.array, palette: np.array) -> np.array:
size, _ = palette.shape
index = (array/array.max()*(size - 1)).round().astype("uint8")
width, height = array.shape
image = np.full((width, height, 4), 0xff, dtype=np.uint8)
image[:, :, :3] = palette[index]
return image
def draw_image(ctx: Context2d, image: np.array) -> None:
data = Uint8ClampedArray.new(to_js(image.tobytes()))
width, height, _ = image.shape
image_data = ImageData.new(data, width, height)
ctx.putImageData(image_data, 0, 0)
width, height = 600, 600
async def draw_mandelbrot() -> None:
spinner = document.querySelector("#mandelbrot .loading")
canvas = document.querySelector("#mandelbrot canvas")
spinner.style.display = ""
canvas.style.display = "none"
ctx = prepare_canvas(width, height, canvas)
console.log("Computing Mandelbrot set ...")
console.time("mandelbrot")
iters = mandelbrot(width, height)
console.timeEnd("mandelbrot")
image = color_map(iters, Magma256)
draw_image(ctx, image)
spinner.style.display = "none"
canvas.style.display = "block"
async def draw_julia() -> None:
spinner = document.querySelector("#julia .loading")
canvas = document.querySelector("#julia canvas")
spinner.style.display = ""
canvas.style.display = "none"
ctx = prepare_canvas(width, height, canvas)
console.log("Computing Julia set ...")
console.time("julia")
iters = julia(width, height)
console.timeEnd("julia")
image = color_map(iters, Magma256)
draw_image(ctx, image)
spinner.style.display = "none"
canvas.style.display = "block"
def ranges():
x0_in = document.querySelector("#x0")
x1_in = document.querySelector("#x1")
y0_in = document.querySelector("#y0")
y1_in = document.querySelector("#y1")
xr = (float(x0_in.value), float(x1_in.value))
yr = (float(y0_in.value), float(y1_in.value))
return xr, yr
current_image = None
async def draw_newton() -> None:
spinner = document.querySelector("#newton .loading")
canvas = document.querySelector("#newton canvas")
spinner.style.display = ""
canvas.style.display = "none"
ctx = prepare_canvas(width, height, canvas)
console.log("Computing Newton set ...")
poly_in = document.querySelector("#poly")
coef_in = document.querySelector("#coef")
conv_in = document.querySelector("#conv")
iter_in = document.querySelector("#iter")
xr, yr = ranges()
# z**3 - 1
# z**8 + 15*z**4 - 16
# z**3 - 2*z + 2
expr = sympy.parse_expr(poly_in.value)
coeffs = [ complex(c) for c in reversed(sympy.Poly(expr, sympy.Symbol("z")).all_coeffs()) ]
poly = np.polynomial.Polynomial(coeffs)
coef = complex(sympy.parse_expr(coef_in.value))
console.time("newton")
iters, roots = newton(width, height, p=poly, a=coef, xr=xr, yr=yr)
console.timeEnd("newton")
if conv_in.checked:
n = poly.degree() + 1
k = int(len(Magma256)/n)
colors = Magma256[::k, :][:n]
colors[0, :] = [255, 0, 0] # red: no convergence
image = color_map(roots, colors)
else:
image = color_map(iters, Magma256)
global current_image
current_image = image
draw_image(ctx, image)
spinner.style.display = "none"
canvas.style.display = "block"
handler = create_proxy(lambda _event: draw_newton())
document.querySelector("#newton fieldset").addEventListener("change", handler)
canvas = document.querySelector("#newton canvas")
is_selecting = False
init_sx, init_sy = None, None
sx, sy = None, None
async def mousemove(event):
global is_selecting
global init_sx
global init_sy
global sx
global sy
def invert(sx, source_range, target_range):
source_start, source_end = source_range
target_start, target_end = target_range
factor = (target_end - target_start)/(source_end - source_start)
offset = -(factor * source_start) + target_start
return (sx - offset) / factor
bds = canvas.getBoundingClientRect()
event_sx, event_sy = event.clientX - bds.x, event.clientY - bds.y
ctx = canvas.getContext("2d")
pressed = event.buttons == 1
if is_selecting:
if not pressed:
xr, yr = ranges()
x0 = invert(init_sx, xr, (0, width))
x1 = invert(sx, xr, (0, width))
y0 = invert(init_sy, yr, (0, height))
y1 = invert(sy, yr, (0, height))
document.querySelector("#x0").value = x0
document.querySelector("#x1").value = x1
document.querySelector("#y0").value = y0
document.querySelector("#y1").value = y1
is_selecting = False
init_sx, init_sy = None, None
sx, sy = init_sx, init_sy
await draw_newton()
else:
ctx.save()
ctx.clearRect(0, 0, width, height)
draw_image(ctx, current_image)
sx, sy = event_sx, event_sy
ctx.beginPath()
ctx.rect(init_sx, init_sy, sx - init_sx, sy - init_sy)
ctx.fillStyle = "rgba(255, 255, 255, 0.4)"
ctx.strokeStyle = "rgba(255, 255, 255, 1.0)"
ctx.fill()
ctx.stroke()
ctx.restore()
else:
if pressed:
is_selecting = True
init_sx, init_sy = event_sx, event_sy
sx, sy = init_sx, init_sy
canvas.addEventListener("mousemove", create_proxy(mousemove))
import asyncio
async def main():
_ = await asyncio.gather(
draw_mandelbrot(),
draw_julia(),
draw_newton(),
)
asyncio.ensure_future(main())
&lt;/py-script&gt;
</code>
</pre>
</div>
</section>
</body>
<script>
const viewCodeButton = document.getElementById("view-code-button");
const codeSection = document.getElementById("code-section");
const handleClick = () => {
if (codeSection.classList.contains("code-section-hidden")) {
codeSection.classList.remove("code-section-hidden");
codeSection.classList.add("code-section-visible");
} else {
codeSection.classList.remove("code-section-visible");
codeSection.classList.add("code-section-hidden");
}
}
viewCodeButton.addEventListener("click", handleClick)
viewCodeButton.addEventListener("keydown", (e) => {
if (e.key === " " || e.key === "Enter" || e.key === "Spacebar") {
handleClick();
}
})
</script>
</html> </html>

View File

@@ -9,9 +9,20 @@
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/@holoviz/panel@0.13.1/dist/panel.min.js"></script> <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/@holoviz/panel@0.13.1/dist/panel.min.js"></script>
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" /> <link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
<script defer src="https://pyscript.net/latest/pyscript.js"></script> <script defer src="https://pyscript.net/latest/pyscript.js"></script>
<link rel="stylesheet" href="./assets/css/examples.css" />
<link rel="stylesheet" href="./assets/prism/prism.css" />
<script defer src="./assets/prism/prism.js"></script>
</head> </head>
<body> <body>
<h1>Panel Example</h1> <nav class="navbar" style="background-color: #000000;">
<div class="app-header">
<a href="/">
<img src="./logo.png" class="logo">
</a>
<a class="title" href="" style="color: #f0ab3c;">Panel Example</a>
</div>
</nav>
<section class="pyscript">
<div id="simple_app"></div> <div id="simple_app"></div>
<py-config> <py-config>
@@ -32,5 +43,52 @@
pn.Row(slider, pn.bind(callback, slider)).servable(target='simple_app'); pn.Row(slider, pn.bind(callback, slider)).servable(target='simple_app');
</py-script> </py-script>
</body> </section>
<section class="code">
<div id="view-code-button" role="button" aria-pressed="false" tabindex="0">View Code</div>
<div id="code-section" class="code-section-hidden">
<p>index.html</p>
<pre class="prism-code language-html">
<code class="language-html">
&lt;py-config&gt;
packages = [
"bokeh",
"numpy",
"panel==0.13.1"
]
&lt;/py-config&gt;
&lt;py-script&gt;
import panel as pn
slider = pn.widgets.FloatSlider(start=0, end=10, name='Amplitude')
def callback(new):
return f'Amplitude is: {new}'
pn.Row(slider, pn.bind(callback, slider)).servable(target='simple_app');
&lt;/py-script&gt;
</code>
</pre>
</div>
</section>
</body>
<script>
const viewCodeButton = document.getElementById("view-code-button");
const codeSection = document.getElementById("code-section");
const handleClick = () => {
if (codeSection.classList.contains("code-section-hidden")) {
codeSection.classList.remove("code-section-hidden");
codeSection.classList.add("code-section-visible");
} else {
codeSection.classList.remove("code-section-visible");
codeSection.classList.add("code-section-hidden");
}
}
viewCodeButton.addEventListener("click", handleClick)
viewCodeButton.addEventListener("keydown", (e) => {
if (e.key === " " || e.key === "Enter" || e.key === "Spacebar") {
handleClick();
}
})
</script>
</html> </html>

View File

@@ -40,22 +40,21 @@
</style> </style>
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" /> <link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
<script defer src="https://pyscript.net/latest/pyscript.js"></script> <script defer src="https://pyscript.net/latest/pyscript.js"></script>
<link rel="stylesheet" href="./assets/css/examples.css" />
<link rel="stylesheet" href="./assets/prism/prism.css" />
<script defer src="./assets/prism/prism.js"></script>
</head> </head>
<body> <body>
<div class="container-fluid d-flex flex-column vh-100 overflow-hidden" id="container"> <nav class="navbar" style="background-color: #000000;">
<nav class="navbar navbar-expand-md navbar-dark sticky-top shadow" id="header" style="background-color: #000000;">
<button type="button" class="navbar-toggle collapsed" id="sidebarCollapse">
<span class="navbar-toggler-icon"></span>
</button>
<div class="app-header"> <div class="app-header">
<a class="navbar-brand app-logo" href="/"> <a href="/">
<img src="./logo.png" class="app-logo"> <img src="./logo.png" class="logo">
</a> </a>
<a class="title" href="" style="color: #f0ab3c;">Panel DeckGL NYC Taxi Demo</a> <a class="title" href="" style="color: #f0ab3c;">Panel DeckGL NYC Taxi Demo</a>
</div> </div>
</nav> </nav>
<section class="pyscript">
<div class="d-flex flex-nowrap" id="content"> <div class="d-flex flex-nowrap" id="content">
<div class="sidenav" id="sidebar"> <div class="sidenav" id="sidebar">
<ul class="nav flex-column" > <ul class="nav flex-column" >
@@ -219,5 +218,185 @@
app.deck_gl.servable(target='plot') app.deck_gl.servable(target='plot')
controls.servable(target='widgets'); controls.servable(target='widgets');
</py-script> </py-script>
</section>
<section class="code">
<div id="view-code-button" role="button" aria-pressed="false" tabindex="0" style="height: 95px;">View Code</div>
<div id="code-section" class="code-section-hidden">
<p>index.html</p>
<pre class="prism-code language-html">
<code class="language-html">
&lt;py-config&gt;
packages = [
"bokeh",
"numpy",
"pandas",
"panel==0.13.1"
]
&lt;/py-config&gt;
&lt;py-script&gt;
import panel as pn
import pandas as pd
import param
from pyodide.http import open_url
MAPBOX_KEY = "pk.eyJ1IjoicGFuZWxvcmciLCJhIjoiY2s1enA3ejhyMWhmZjNobjM1NXhtbWRrMyJ9.B_frQsAVepGIe-HiOJeqvQ"
class App(param.Parameterized):
data = param.DataFrame(precedence=-1)
view = param.DataFrame(precedence=-1)
arc_view = param.DataFrame(precedence=-1)
radius = param.Integer(default=50, bounds=(20, 1000))
elevation = param.Integer(default=10, bounds=(0, 50))
hour = param.Integer(default=0, bounds=(0, 23))
speed = param.Integer(default=1, bounds=(0, 10), precedence=-1)
play = param.Event(label='▷')
def __init__(self, **params):
self.deck_gl = None
super().__init__(**params)
self.deck_gl = pn.pane.DeckGL(
dict(self.spec),
mapbox_api_key=MAPBOX_KEY,
throttle={'click': 10},
sizing_mode='stretch_both',
margin=0
)
self.deck_gl.param.watch(self._update_arc_view, 'click_state')
self._playing = False
self._cb = pn.state.add_periodic_callback(
self._update_hour, 1000//self.speed, start=False
)
@property
def spec(self):
return {
"initialViewState": {
"bearing": 0,
"latitude": 40.7,
"longitude": -73.9,
"maxZoom": 15,
"minZoom": 5,
"pitch": 40.5,
"zoom": 11
},
"layers": [self.hex_layer, self.arc_layer],
"mapStyle": "mapbox://styles/mapbox/dark-v9",
"views": [
{"@@type": "MapView", "controller": True}
]
}
@property
def hex_layer(self):
return {
"@@type": "HexagonLayer",
"autoHighlight": True,
"coverage": 1,
"data": self.data if self.view is None else self.view,
"elevationRange": [0, 100],
"elevationScale": self.elevation,
"radius": self.radius,
"extruded": True,
"getPosition": "@@=[pickup_x, pickup_y]",
"id": "8a553b25-ef3a-489c-bbe2-e102d18a3211"
}
@property
def arc_layer(self):
return {
"@@type": "ArcLayer",
"id": 'arc-layer',
"data": self.arc_view,
"pickable": True,
"getWidth": 1,
"getSourcePosition": "@@=[pickup_x, pickup_y]",
"getTargetPosition": "@@=[dropoff_x, dropoff_y]",
"getSourceColor": [0, 255, 0, 180],
"getTargetColor": [240, 100, 0, 180]
}
def _update_hour(self):
self.hour = (self.hour+1) % 24
@param.depends('view', watch=True)
def _update_arc_view(self, event=None):
data = self.data if self.view is None else self.view
if not self.deck_gl or not self.deck_gl.click_state:
self.arc_view = data.iloc[:0]
return
lon, lat = self.deck_gl.click_state['coordinate']
tol = 0.001
self.arc_view = data[
(df.pickup_x>=float(lon-tol)) &
(df.pickup_x<=float(lon+tol)) &
(df.pickup_y>=float(lat-tol)) &
(df.pickup_y<=float(lat+tol))
]
@param.depends('hour', watch=True, on_init=True)
def _update_hourly_view(self):
self.view = self.data[self.data.hour==self.hour]
@param.depends('speed', watch=True)
def _update_speed(self):
self._cb.period = 1000//self.speed
@param.depends('play', watch=True)
def _play_pause(self):
if self._playing:
self._cb.stop()
self.param.play.label = '▷'
self.param.speed.precedence = -1
else:
self._cb.start()
self.param.play.label = '❚❚'
self.param.speed.precedence = 1
self._playing = not self._playing
@param.depends('view', 'radius', 'elevation', 'arc_view', watch=True)
def update_spec(self):
self.deck_gl.object = dict(self.spec)
url = 'https://s3.eu-west-1.amazonaws.com/assets.holoviews.org/data/nyc_taxi_wide.csv'
df = pd.read_csv(open_url(url))
app = App(data=df)
controls = pn.Param(app.param, sizing_mode='stretch_width', show_name=False)
app.deck_gl.servable(target='plot')
controls.servable(target='widgets')
&lt;/py-script&gt;
</code>
</pre>
</div>
</section>
</body>
<script>
const viewCodeButton = document.getElementById("view-code-button");
const codeSection = document.getElementById("code-section");
const handleClick = () => {
if (codeSection.classList.contains("code-section-hidden")) {
codeSection.classList.remove("code-section-hidden");
codeSection.classList.add("code-section-visible");
} else {
codeSection.classList.remove("code-section-visible");
codeSection.classList.add("code-section-hidden");
}
}
viewCodeButton.addEventListener("click", handleClick)
viewCodeButton.addEventListener("keydown", (e) => {
if (e.key === " " || e.key === "Enter" || e.key === "Spacebar") {
handleClick();
}
})
</script>
</body> </body>
</html> </html>

View File

@@ -41,22 +41,22 @@
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" /> <link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
<script defer src="https://pyscript.net/latest/pyscript.js"></script> <script defer src="https://pyscript.net/latest/pyscript.js"></script>
<link rel="stylesheet" href="./assets/css/examples.css" />
<link rel="stylesheet" href="./assets/prism/prism.css" />
<script defer src="./assets/prism/prism.js"></script>
<script defer src="https://pyscript.net/latest/pyscript.js"></script>
</head> </head>
<body> <body>
<div class="container-fluid d-flex flex-column vh-100 overflow-hidden" id="container"> <nav class="navbar" style="background-color: #000000;">
<nav class="navbar navbar-expand-md navbar-dark sticky-top shadow" id="header" style="background-color: #000000;">
<button type="button" class="navbar-toggle collapsed" id="sidebarCollapse">
<span class="navbar-toggler-icon"></span>
</button>
<div class="app-header"> <div class="app-header">
<a class="navbar-brand app-logo" href="/"> <a href="/">
<img src="./logo.png" class="app-logo"> <img src="./logo.png" class="logo">
</a> </a>
<a class="title" href="" style="color: #f0ab3c;">Panel KMeans Clustering Demo</a> <a class="title" href="" style="color: #f0ab3c;">Panel KMeans Clustering Demo</a>
</div> </div>
</nav> </nav>
<section class="pyscript">
<div class="row overflow-hidden" id="content"> <div class="row overflow-hidden" id="content">
<div class="sidenav" id="sidebar"> <div class="sidenav" id="sidebar">
<ul class="nav flex-column"> <ul class="nav flex-column">
@@ -159,6 +159,122 @@
update_table() update_table()
update_chart() update_chart()
</py-script> </py-script>
</section>
<section class="code">
<div id="view-code-button" role="button" aria-pressed="false" tabindex="0" style="height: 95px;">View Code</div>
<div id="code-section" class="code-section-hidden">
<p>index.html</p>
<pre class="prism-code language-html">
<code class="language-html">
&lt;py-config&gt;
packages = [
"altair",
"numpy",
"pandas",
"scikit-learn",
"panel==0.13.1"
]
&lt;/py-config&gt;
&lt;py-script&gt;
import altair as alt
import panel as pn
import pandas as pd
from sklearn.cluster import KMeans
from pyodide.http import open_url
pn.config.sizing_mode = 'stretch_width'
url = 'https://raw.githubusercontent.com/rfordatascience/tidytuesday/master/data/2020/2020-07-28/penguins.csv'
penguins = pd.read_csv(open_url(url)).dropna()
cols = list(penguins.columns)[2:6]
x = pn.widgets.Select(name='x', options=cols, value='bill_depth_mm').servable(target='x-widget')
y = pn.widgets.Select(name='y', options=cols, value='bill_length_mm').servable(target='y-widget')
n_clusters = pn.widgets.IntSlider(name='n_clusters', start=1, end=5, value=3).servable(target='n-widget')
brush = alt.selection_interval(name='brush') # selection of type "interval"
def get_clusters(n_clusters):
kmeans = KMeans(n_clusters=n_clusters)
est = kmeans.fit(penguins[cols].values)
df = penguins.copy()
df['labels'] = est.labels_.astype('str')
return df
def get_chart(x, y, df):
centers = df.groupby('labels').mean()
return (
alt.Chart(df)
.mark_point(size=100)
.encode(
x=alt.X(x, scale=alt.Scale(zero=False)),
y=alt.Y(y, scale=alt.Scale(zero=False)),
shape='labels',
color='species'
).add_selection(brush).properties(width=800) +
alt.Chart(centers)
.mark_point(size=250, shape='cross', color='black')
.encode(x=x+':Q', y=y+':Q')
)
intro = pn.pane.Markdown("""
This app provides an example of **building a simple dashboard using
Panel**.\n\nIt demonstrates how to take the output of **k-means
clustering on the Penguins dataset** using scikit-learn,
parameterizing the number of clusters and the variables to
plot.\n\nThe plot and the table are linked, i.e. selecting on the plot
will filter the data in the table.\n\n The **`x` marks the center** of
the cluster.
""").servable(target='intro')
chart = pn.pane.Vega().servable(target='cluster-plot')
table = pn.widgets.Tabulator(pagination='remote', page_size=10).servable(target='table')
def update_table(event=None):
table.value = get_clusters(n_clusters.value)
n_clusters.param.watch(update_table, 'value')
@pn.depends(x, y, n_clusters, watch=True)
def update_chart(*events):
chart.object = get_chart(x.value, y.value, table.value)
chart.selection.param.watch(update_filters, 'brush')
def update_filters(event=None):
filters = []
for k, v in (getattr(event, 'new') or {}).items():
filters.append(dict(field=k, type='>=', value=v[0]))
filters.append(dict(field=k, type='<=', value=v[1]))
table.filters = filters
update_table()
update_chart()
&lt;/py-script&gt;
</code>
</pre>
</div>
</section>
</body>
<script>
const viewCodeButton = document.getElementById("view-code-button");
const codeSection = document.getElementById("code-section");
const handleClick = () => {
if (codeSection.classList.contains("code-section-hidden")) {
codeSection.classList.remove("code-section-hidden");
codeSection.classList.add("code-section-visible");
} else {
codeSection.classList.remove("code-section-visible");
codeSection.classList.add("code-section-hidden");
}
}
viewCodeButton.addEventListener("click", handleClick)
viewCodeButton.addEventListener("keydown", (e) => {
if (e.key === " " || e.key === "Enter" || e.key === "Spacebar") {
handleClick();
}
})
</script>
<script> <script>
$(document).ready(function () { $(document).ready(function () {

View File

@@ -32,22 +32,21 @@
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" /> <link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
<script defer src="https://pyscript.net/latest/pyscript.js"></script> <script defer src="https://pyscript.net/latest/pyscript.js"></script>
<link rel="stylesheet" href="./assets/css/examples.css" />
<link rel="stylesheet" href="./assets/prism/prism.css" />
<script defer src="./assets/prism/prism.js"></script>
</head> </head>
<body> <body>
<div class="container-fluid d-flex flex-column vh-100 overflow-hidden" id="container"> <nav class="navbar" style="background-color: #000000;">
<nav class="navbar navbar-expand-md navbar-dark sticky-top shadow" id="header" style="background-color: #000000;">
<button type="button" class="navbar-toggle collapsed" id="sidebarCollapse">
<span class="navbar-toggler-icon"></span>
</button>
<div class="app-header"> <div class="app-header">
<a class="navbar-brand app-logo" href="/"> <a href="/">
<img src="./logo.png" class="app-logo"> <img src="./logo.png" class="logo">
</a> </a>
<a class="title" href="" style="color: #f0ab3c;">Panel Streaming Demo</a> <a class="title" href="" style="color: #f0ab3c;">Panel Streaming Demo</a>
</div> </div>
</nav> </nav>
<section class="pyscript">
<div class="row overflow-hidden" id="content"> <div class="row overflow-hidden" id="content">
<div class="col mh-100 float-left" id="main"> <div class="col mh-100 float-left" id="main">
<div class="bk-root" id="controls"></div> <div class="bk-root" id="controls"></div>
@@ -115,5 +114,90 @@
pn.pane.Bokeh(p).servable(target='plot') pn.pane.Bokeh(p).servable(target='plot')
pn.Row(cb.param.period, rollover, follow, width=400).servable(target='controls') pn.Row(cb.param.period, rollover, follow, width=400).servable(target='controls')
</py-script> </py-script>
</section>
<section class="code">
<div id="view-code-button" role="button" aria-pressed="false" tabindex="0" style="height: 95px;">View Code</div>
<div id="code-section" class="code-section-hidden">
<p>index.html</p>
<pre class="prism-code language-html">
<code class="language-html">
&lt;py-config&gt;
packages = [
"bokeh",
"numpy",
"pandas",
"panel==0.13.1"
]
&lt;/py-config&gt;
&lt;py-script&gt;
import panel as pn
import numpy as np
import pandas as pd
from bokeh.models import ColumnDataSource
from bokeh.plotting import figure
df = pd.DataFrame(np.random.randn(10, 4), columns=list('ABCD')).cumsum()
rollover = pn.widgets.IntInput(name='Rollover', value=15)
follow = pn.widgets.Checkbox(name='Follow', value=True, align='end')
tabulator = pn.widgets.Tabulator(df, height=450, width=400).servable(target='table')
def color_negative_red(val):
"""
Takes a scalar and returns a string with
the css property `'color: red'` for negative
strings, black otherwise.
"""
color = 'red' if val < 0 else 'green'
return 'color: %s' % color
tabulator.style.applymap(color_negative_red)
p = figure(height=450, width=600)
cds = ColumnDataSource(data=ColumnDataSource.from_df(df))
p.line('index', 'A', source=cds, line_color='red')
p.line('index', 'B', source=cds, line_color='green')
p.line('index', 'C', source=cds, line_color='blue')
p.line('index', 'D', source=cds, line_color='purple')
def stream():
data = df.iloc[-1] + np.random.randn(4)
tabulator.stream(data, rollover=rollover.value, follow=follow.value)
value = {k: [v] for k, v in tabulator.value.iloc[-1].to_dict().items()}
value['index'] = [tabulator.value.index[-1]]
cds.stream(value)
cb = pn.state.add_periodic_callback(stream, 200)
pn.pane.Bokeh(p).servable(target='plot')
pn.Row(cb.param.period, rollover, follow, width=400).servable(target='controls')
&lt;/py-script&gt;
</code>
</pre>
</div>
</section>
</body> </body>
<script>
const viewCodeButton = document.getElementById("view-code-button");
const codeSection = document.getElementById("code-section");
const handleClick = () => {
if (codeSection.classList.contains("code-section-hidden")) {
codeSection.classList.remove("code-section-hidden");
codeSection.classList.add("code-section-visible");
} else {
codeSection.classList.remove("code-section-visible");
codeSection.classList.add("code-section-hidden");
}
}
viewCodeButton.addEventListener("click", handleClick)
viewCodeButton.addEventListener("keydown", (e) => {
if (e.key === " " || e.key === "Enter" || e.key === "Spacebar") {
handleClick();
}
})
</script>
</html> </html>

View File

@@ -9,10 +9,22 @@
<link rel="icon" type="image/png" href="favicon.png" /> <link rel="icon" type="image/png" href="favicon.png" />
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" /> <link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
<script defer src="https://pyscript.net/latest/pyscript.js"></script> <script defer src="https://pyscript.net/latest/pyscript.js"></script>
<link rel="stylesheet" href="./assets/css/examples.css" />
<link rel="stylesheet" href="./assets/prism/prism.css" />
<script defer src="./assets/prism/prism.js"></script>
</head> </head>
<body> <body>
<h1><b>pyscript REPL</b></h1> <nav class="navbar" style="background-color: #000000;">
<div class="app-header">
<a href="/">
<img src="./logo.png" class="logo">
</a>
<a class="title" href="" style="color: #f0ab3c;">PyScript REPL</a>
</div>
</nav>
<section class="pyscript">
<h1><b>PyScript REPL</b></h1>
Tip: press Shift-ENTER to evaluate a cell Tip: press Shift-ENTER to evaluate a cell
<br> <br>
<py-config> <py-config>
@@ -22,5 +34,90 @@
<div> <div>
<py-repl id="my-repl" auto-generate="true"> </py-repl> <py-repl id="my-repl" auto-generate="true"> </py-repl>
</div> </div>
</section>
<section class="code">
<div id="view-code-button" role="button" aria-pressed="false" tabindex="0">View Code</div>
<div id="code-section" class="code-section-hidden">
<p>index.html</p>
<pre class="prism-code language-html">
<code class="language-html">
&lt;py-config&gt;
[[fetch]]
files = [&quot;./antigravity.py&quot;]
&lt;/py-config&gt;
&lt;div&gt;
&lt;py-repl id=&quot;my-repl&quot; auto-generate=&quot;true&quot;&gt; &lt;/py-repl&gt;
&lt;/div&gt;
</code>
</pre>
<p>antigravity.py</p>
<pre class="prism-code language-python">
<code class="language-python">
import random
import sys
from js import DOMParser, document, setInterval
from pyodide.ffi import create_proxy
from pyodide.http import open_url
class Antigravity:
url = "./antigravity.svg"
def __init__(self, target=None, interval=10, append=True, fly=False):
target = target or sys.stdout._out
self.target = (
document.getElementById(target) if isinstance(target, str) else target
)
doc = DOMParser.new().parseFromString(
open_url(self.url).read(), "image/svg+xml"
)
self.node = doc.documentElement
if append:
self.target.append(self.node)
else:
self.target.replaceChildren(self.node)
self.xoffset, self.yoffset = 0, 0
self.interval = interval
if fly:
self.fly()
def fly(self):
setInterval(create_proxy(self.move), self.interval)
def move(self):
char = self.node.getElementsByTagName("g")[1]
char.setAttribute("transform", f"translate({self.xoffset}, {-self.yoffset})")
self.xoffset += random.normalvariate(0, 1) / 20
if self.yoffset < 50:
self.yoffset += 0.1
else:
self.yoffset += random.normalvariate(0, 1) / 20
_auto = Antigravity(append=True)
fly = _auto.fly
</code>
</div>
</section>
</body> </body>
<script>
const viewCodeButton = document.getElementById("view-code-button");
const codeSection = document.getElementById("code-section");
const handleClick = () => {
if (codeSection.classList.contains("code-section-hidden")) {
codeSection.classList.remove("code-section-hidden");
codeSection.classList.add("code-section-visible");
} else {
codeSection.classList.remove("code-section-visible");
codeSection.classList.add("code-section-hidden");
}
}
viewCodeButton.addEventListener("click", handleClick)
viewCodeButton.addEventListener("keydown", (e) => {
if (e.key === " " || e.key === "Enter" || e.key === "Spacebar") {
handleClick();
}
})
</script>
</html> </html>

View File

@@ -9,11 +9,22 @@
<link rel="icon" type="image/png" href="favicon.png" /> <link rel="icon" type="image/png" href="favicon.png" />
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" /> <link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
<link rel="stylesheet" href="repl.css" /> <link rel="stylesheet" href="repl.css" />
<link rel="stylesheet" href="./assets/css/examples.css" />
<link rel="stylesheet" href="./assets/prism/prism.css" />
<script defer src="./assets/prism/prism.js"></script>
<script defer src="https://pyscript.net/latest/pyscript.js"></script> <script defer src="https://pyscript.net/latest/pyscript.js"></script>
</head> </head>
<body> <body>
<nav class="navbar" style="background-color: #000000;">
<div class="app-header">
<a href="/">
<img src="./logo.png" class="logo">
</a>
<a class="title" href="" style="color: #f0ab3c;">Custom REPL</a>
</div>
</nav>
<section class="pyscript">
<h1 class="font-semibold text-2xl ml-5">Custom REPL</h1> <h1 class="font-semibold text-2xl ml-5">Custom REPL</h1>
<py-config> <py-config>
packages = [ packages = [
@@ -28,5 +39,110 @@
<py-repl id="my-repl" auto-generate="true"> </py-repl> <py-repl id="my-repl" auto-generate="true"> </py-repl>
<div id="output" class="p-4"></div> <div id="output" class="p-4"></div>
</div> </div>
</section>
<section class="code">
<div id="view-code-button" role="button" aria-pressed="false" tabindex="0">View Code</div>
<div id="code-section" class="code-section-hidden">
<p>index.html</p>
<pre class="prism-code language-html">
<code class="language-html">
&lt;div&gt;
&lt;py-repl id=&quot;my-repl&quot; auto-generate=&quot;true&quot;&gt; &lt;/py-repl&gt;
&lt;div id=&quot;output&quot; class=&quot;p-4&quot;&gt;&lt;/div&gt;
&lt;/div&gt;
</code>
</pre>
<p>utils.py</p>
<pre class="prism-code language-python">
<code class="language-python">
from datetime import datetime as dt
def format_date(dt_, fmt="%m/%d/%Y, %H:%M:%S"):
return f"{dt_:{fmt}}"
def now(fmt="%m/%d/%Y, %H:%M:%S"):
return format_date(dt.now(), fmt)
def remove_class(element, class_name):
element.element.classList.remove(class_name)
def add_class(element, class_name):
element.element.classList.add(class_name)
</code>
</pre>
<p>antigravity.py</p>
<pre class="prism-code language-python">
<code class="language-python">
import random
import sys
from js import DOMParser, document, setInterval
from pyodide.ffi import create_proxy
from pyodide.http import open_url
class Antigravity:
url = "./antigravity.svg"
def __init__(self, target=None, interval=10, append=True, fly=False):
target = target or sys.stdout._out
self.target = (
document.getElementById(target) if isinstance(target, str) else target
)
doc = DOMParser.new().parseFromString(
open_url(self.url).read(), "image/svg+xml"
)
self.node = doc.documentElement
if append:
self.target.append(self.node)
else:
self.target.replaceChildren(self.node)
self.xoffset, self.yoffset = 0, 0
self.interval = interval
if fly:
self.fly()
def fly(self):
setInterval(create_proxy(self.move), self.interval)
def move(self):
char = self.node.getElementsByTagName("g")[1]
char.setAttribute("transform", f"translate({self.xoffset}, {-self.yoffset})")
self.xoffset += random.normalvariate(0, 1) / 20
if self.yoffset < 50:
self.yoffset += 0.1
else:
self.yoffset += random.normalvariate(0, 1) / 20
_auto = Antigravity(append=True)
fly = _auto.fly
</code>
</pre>
</div>
</section>
</body> </body>
<script>
const viewCodeButton = document.getElementById("view-code-button");
const codeSection = document.getElementById("code-section");
const handleClick = () => {
if (codeSection.classList.contains("code-section-hidden")) {
codeSection.classList.remove("code-section-hidden");
codeSection.classList.add("code-section-visible");
} else {
codeSection.classList.remove("code-section-visible");
codeSection.classList.add("code-section-hidden");
}
}
viewCodeButton.addEventListener("click", handleClick)
viewCodeButton.addEventListener("keydown", (e) => {
if (e.key === " " || e.key === "Enter" || e.key === "Spacebar") {
handleClick();
}
})
</script>
</html> </html>

View File

@@ -10,9 +10,21 @@
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" /> <link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
<script defer src="https://pyscript.net/latest/pyscript.js"></script> <script defer src="https://pyscript.net/latest/pyscript.js"></script>
<link rel="stylesheet" href="./assets/css/examples.css" />
<link rel="stylesheet" href="./assets/prism/prism.css" />
<script defer src="./assets/prism/prism.js"></script>
</head> </head>
<body> <body>
<nav class="navbar" style="background-color: #000000;">
<div class="app-header">
<a href="/">
<img src="./logo.png" class="logo">
</a>
<a class="title" href="" style="color: #f0ab3c;">Simple Clock</a>
</div>
</nav>
<section class="pyscript">
<div class="font-mono">start time: <label id="outputDiv"></label></div> <div class="font-mono">start time: <label id="outputDiv"></label></div>
<div id="outputDiv2" class="font-mono"></div> <div id="outputDiv2" class="font-mono"></div>
<div id="outputDiv3" class="font-mono"></div> <div id="outputDiv3" class="font-mono"></div>
@@ -43,5 +55,78 @@ async def foo():
pyscript.run_until_complete(foo()) pyscript.run_until_complete(foo())
</py-script> </py-script>
</section>
<section class="code">
<div id="view-code-button" role="button" aria-pressed="false" tabindex="0">View Code</div>
<div id="code-section" class="code-section-hidden">
<p>index.html</p>
<pre class="prism-code language-html">
<code class="language-html">
&lt;div class=&quot;font-mono&quot;&gt;start time: &lt;label id=&quot;outputDiv&quot;&gt;&lt;/label&gt;&lt;/div&gt;
&lt;div id=&quot;outputDiv2&quot; class=&quot;font-mono&quot;&gt;&lt;/div&gt;
&lt;div id=&quot;outputDiv3&quot; class=&quot;font-mono&quot;&gt;&lt;/div&gt;
&lt;py-config&gt;
[[fetch]]
files = ["./utils.py"]
&lt;/py-config&gt;
&lt;py-script&gt;
from utils import now
import asyncio
async def foo():
while True:
await asyncio.sleep(1)
output = now()
Element("outputDiv2").write(output)
out3 = Element("outputDiv3")
if output[-1] in ["0", "4", "8"]:
out3.write("It's espresso time!")
else:
out3.clear()
pyscript.run_until_complete(foo())
&lt;/py-script&gt;
</code>
</pre>
<p>utils.py</p>
<pre class="prism-code language-python">
<code class="language-python">
from datetime import datetime as dt
def format_date(dt_, fmt="%m/%d/%Y, %H:%M:%S"):
return f"{dt_:{fmt}}"
def now(fmt="%m/%d/%Y, %H:%M:%S"):
return format_date(dt.now(), fmt)
def remove_class(element, class_name):
element.element.classList.remove(class_name)
def add_class(element, class_name):
element.element.classList.add(class_name)
</code>
</pre>
</div>
</section>
</body> </body>
<script>
const viewCodeButton = document.getElementById("view-code-button");
const codeSection = document.getElementById("code-section");
const handleClick = () => {
if (codeSection.classList.contains("code-section-hidden")) {
codeSection.classList.remove("code-section-hidden");
codeSection.classList.add("code-section-visible");
} else {
codeSection.classList.remove("code-section-visible");
codeSection.classList.add("code-section-hidden");
}
}
viewCodeButton.addEventListener("click", handleClick)
viewCodeButton.addEventListener("keydown", (e) => {
if (e.key === " " || e.key === "Enter" || e.key === "Spacebar") {
handleClick();
}
})
</script>
</html> </html>

View File

@@ -9,6 +9,22 @@
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" /> <link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
<script defer src="https://pyscript.net/latest/pyscript.js"></script> <script defer src="https://pyscript.net/latest/pyscript.js"></script>
<link rel="stylesheet" href="./assets/css/examples.css" />
<link rel="stylesheet" href="./assets/prism/prism.css" />
<script defer src="./assets/prism/prism.js"></script>
</head>
<body>
<nav class="navbar" style="background-color: #000000;">
<div class="app-header">
<a href="/">
<img src="./logo.png" class="logo">
</a>
<a class="title" href="" style="color: #f0ab3c;">Pyscript Native TODO App</a>
</div>
</nav>
<section class="pyscript">
<h1>To Do List</h1>
<py-register-widget src="./pylist.py" name="py-list" klass="PyList"></py-register-widget> <py-register-widget src="./pylist.py" name="py-list" klass="PyList"></py-register-widget>
<py-config> <py-config>
@@ -46,10 +62,6 @@
) )
</py-script> </py-script>
</head>
<body>
<h1>To Do List</h1>
<div class="py-box"> <div class="py-box">
<input id="new-task-content" /> <input id="new-task-content" />
<button py-click="add_task()" id="new-task-btn" class="py-button">Add Task!</button> <button py-click="add_task()" id="new-task-btn" class="py-button">Add Task!</button>
@@ -57,5 +69,101 @@
<py-list id="myList"></py-list> <py-list id="myList"></py-list>
<py-repl id="my-repl" auto-generate="true"> </py-repl> <py-repl id="my-repl" auto-generate="true"> </py-repl>
</section>
<section class="code">
<div id="view-code-button" role="button" aria-pressed="false" tabindex="0">View Code</div>
<div id="code-section" class="code-section-hidden">
<p>index.html</p>
<pre class="prism-code language-html">
<code class="language-html">
&lt;py-register-widget src=&quot;./pylist.py&quot; name=&quot;py-list&quot; klass=&quot;PyList&quot;&gt;&lt;/py-register-widget&gt;
&lt;py-config&gt;
[[fetch]]
files = ["./utils.py"]
&lt;/py-config&gt;
&lt;py-script&gt;
from js import document
from pyodide.ffi.wrappers import add_event_listener
def add_task(*ags, **kws):
# create a new dictionary representing the new task
new_task_content = Element("new-task-content")
task = { "content": new_task_content.value, "done": False, "created_at": dt.now() }
# add a new task to the list and tell it to use the `content` key to show in the UI
# and to use the key `done` to sync the task status with a checkbox element in the UI
myList.add(task)
# clear the inputbox element used to create the new task
new_task_content.clear()
def on_click(evt):
add_task()
def handle_keypress(evt):
if evt.key == "Enter":
add_task()
add_event_listener(
document.getElementById("new-task-content"),
"keypress",
handle_keypress
)
&lt;/py-script&gt;
&lt;div class=&quot;py-box&quot;&gt;
&lt;input id=&quot;new-task-content&quot; /&gt;
&lt;button py-click=&quot;add_task()&quot; id=&quot;new-task-btn&quot; class=&quot;py-button&quot;&gt;Add Task!&lt;/button&gt;
&lt;/div&gt;
&lt;py-list id=&quot;myList&quot;&gt;&lt;/py-list&gt;
&lt;py-repl id=&quot;my-repl&quot; auto-generate=&quot;true&quot;&gt; &lt;/py-repl&gt;
</code>
</pre>
<p>pylist.py</p>
<pre class="prism-code language-python">
<code class="language-python">
from datetime import datetime as dt
class PyItem(PyItemTemplate):
def on_click(self, evt=None):
self.data["done"] = not self.data["done"]
self.strike(self.data["done"])
self.select("input").element.checked = self.data["done"]
class PyList(PyListTemplate):
item_class = PyItem
def add(self, item):
if isinstance(item, str):
item = {"content": item, "done": False, "created_at": dt.now()}
super().add(item, labels=["content"], state_key="done")
</code>
</pre>
</div>
</section>
</body> </body>
<script>
const viewCodeButton = document.getElementById("view-code-button");
const codeSection = document.getElementById("code-section");
const handleClick = () => {
if (codeSection.classList.contains("code-section-hidden")) {
codeSection.classList.remove("code-section-hidden");
codeSection.classList.add("code-section-visible");
} else {
codeSection.classList.remove("code-section-visible");
codeSection.classList.add("code-section-hidden");
}
}
viewCodeButton.addEventListener("click", handleClick)
viewCodeButton.addEventListener("keydown", (e) => {
if (e.key === " " || e.key === "Enter" || e.key === "Spacebar") {
handleClick();
}
})
</script>
</html> </html>

View File

@@ -10,11 +10,21 @@
<link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" /> <link rel="stylesheet" href="https://pyscript.net/latest/pyscript.css" />
<script defer src="https://pyscript.net/latest/pyscript.js"></script> <script defer src="https://pyscript.net/latest/pyscript.js"></script>
<link rel="stylesheet" href="./assets/css/examples.css" />
<link rel="stylesheet" href="./assets/prism/prism.css" />
<script defer src="./assets/prism/prism.js"></script>
</head> </head>
<body class="container"> <body>
<!-- <py-repl id="my-repl" auto-generate="true"> </py-repl> --> <nav class="navbar" style="background-color: #000000;">
<div class="app-header">
<a href="/">
<img src="./logo.png" class="logo">
</a>
<a class="title" href="" style="color: #f0ab3c;">Todo App</a>
</div>
</nav>
<section class="pyscript">
<py-config> <py-config>
[[fetch]] [[fetch]]
files = ["./utils.py"] files = ["./utils.py"]
@@ -50,5 +60,149 @@
</section> </section>
</main> </main>
</section>
<section class="code">
<div id="view-code-button" role="button" aria-pressed="false" tabindex="0">View Code</div>
<div id="code-section" class="code-section-hidden">
<p>index.html</p>
<pre class="prism-code language-html">
<code class="language-html">
&lt;py-config&gt;
[[fetch]]
files = ["./utils.py"]
&lt;/py-config&gt;
&lt;py-script src="./todo.py"&gt;
&lt;/py-script&gt;
&lt;main&gt;
&lt;section&gt;
&lt;div class=&quot;text-center w-full mb-8&quot;&gt;
&lt;h1 class=&quot;text-3xl font-bold text-gray-800 uppercase tracking-tight&quot;&gt;To Do List&lt;/h1&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;input id=&quot;new-task-content&quot; class=&quot;py-input&quot; type=&quot;text&quot;&gt;
&lt;button id=&quot;new-task-btn&quot; class=&quot;py-button&quot; type=&quot;submit&quot; py-click=&quot;add_task()&quot;&gt;
Add task
&lt;/button&gt;
&lt;/div&gt;
&lt;py-list id=&quot;myList&quot;&gt;&lt;/py-list&gt;
&lt;div id=&quot;list-tasks-container&quot; class=&quot;flex flex-col-reverse mt-4&quot;&gt;
&lt;/div&gt;
&lt;template id=&quot;task-template&quot;&gt;
&lt;section class=&quot;task py-li-element&quot;&gt;
&lt;label for=&quot;flex items-center p-2 &quot;&gt;
&lt;input class=&quot;mr-2&quot; type=&quot;checkbox&quot;&gt;
&lt;p class=&quot;m-0 inline&quot;&gt;&lt;/p&gt;
&lt;/label&gt;
&lt;/section&gt;
&lt;/template&gt;
&lt;/section&gt;
&lt;/main&gt;
</code>
</pre>
<p>utils.py</p>
<pre class="prism-code language-python">
<code class="language-python">
from datetime import datetime as dt
def format_date(dt_, fmt="%m/%d/%Y, %H:%M:%S"):
return f"{dt_:{fmt}}"
def now(fmt="%m/%d/%Y, %H:%M:%S"):
return format_date(dt.now(), fmt)
def remove_class(element, class_name):
element.element.classList.remove(class_name)
def add_class(element, class_name):
element.element.classList.add(class_name)
</code>
</pre>
<p>todo.py</p>
<pre class="prism-code language-python">
<code class="language-python">
from datetime import datetime as dt
from utils import add_class, remove_class
tasks = []
# define the task template that will be use to render new templates to the page
task_template = Element("task-template").select(".task", from_content=True)
task_list = Element("list-tasks-container")
new_task_content = Element("new-task-content")
def add_task(*ags, **kws):
# ignore empty task
if not new_task_content.element.value:
return None
# create task
task_id = f"task-{len(tasks)}"
task = {
"id": task_id,
"content": new_task_content.element.value,
"done": False,
"created_at": dt.now(),
}
tasks.append(task)
# add the task element to the page as new node in the list by cloning from a
# template
task_html = task_template.clone(task_id)
task_html_content = task_html.select("p")
task_html_content.element.innerText = task["content"]
task_html_check = task_html.select("input")
task_list.element.appendChild(task_html.element)
def check_task(evt=None):
task["done"] = not task["done"]
if task["done"]:
add_class(task_html_content, "line-through")
else:
remove_class(task_html_content, "line-through")
new_task_content.clear()
task_html_check.element.onclick = check_task
def add_task_event(e):
if e.key == "Enter":
add_task()
new_task_content.element.onkeypress = add_task_event
</code>
</pre>
</div>
</section>
<script>
const viewCodeButton = document.getElementById("view-code-button");
const codeSection = document.getElementById("code-section");
const handleClick = () => {
if (codeSection.classList.contains("code-section-hidden")) {
codeSection.classList.remove("code-section-hidden");
codeSection.classList.add("code-section-visible");
} else {
codeSection.classList.remove("code-section-visible");
codeSection.classList.add("code-section-hidden");
}
}
viewCodeButton.addEventListener("click", handleClick)
viewCodeButton.addEventListener("keydown", (e) => {
if (e.key === " " || e.key === "Enter" || e.key === "Spacebar") {
handleClick();
}
})
</script>
</body> </body>
</html> </html>