Unterschiede
Hier werden die Unterschiede zwischen zwei Versionen der Seite angezeigt.
| Beide Seiten, vorherige Überarbeitung Vorherige Überarbeitung Nächste Überarbeitung | Vorherige Überarbeitung | ||
| user:hof:pyeditor [2024-05-21 20:42] – [Bottom.ch with direct component] hof | user:hof:pyeditor [2026-08-20 19:49] (aktuell) – [Installing files] hof | ||
|---|---|---|---|
| Zeile 1: | Zeile 1: | ||
| - | # Inline | + | # Bottom |
| - | ## Bottom.ch | + | Bottom |
| - | With iframe on bottom.ch/ksr/py/embed.html, which is based on pyodide and codemirror. | + | |
| - | <code html> | + | Also see [[~kara]] for a Kara shim on top of bottom-editor. |
| - | < | + | ## Basic Usage |
| + | |||
| + | ### Direct HTML | ||
| + | Requires HTML-authoring (which may be a security risk with broad authorship). | ||
| + | |||
| + | Within Dokuwiki, the HTML needs to be embedded into `< | ||
| - | < | ||
| - | ## Bottom.ch with direct component | ||
| <code html> | <code html> | ||
| - | <!-- Include the script once (or from a DokuWiki plugin, or from userscripts. --> | + | <!-- Include the script once (or from a DokuWiki plugin, or from userscripts). --> |
| - | < | + | < |
| <!-- Include a custom component in HTML. Use height, min-height, max-height to control the size. --> | <!-- Include a custom component in HTML. Use height, min-height, max-height to control the size. --> | ||
| - | < | + | <!-- Leading empty lines will be dropped. --> |
| + | < | ||
| + | print(42) | ||
| + | </ | ||
| </ | </ | ||
| - | < | ||
| - | < | + | ### With Plugin |
| - | print(21)</ | + | To avoid needing raw trusted HTML access, install the [[https:// |
| + | |||
| + | <code html> | ||
| + | < | ||
| + | print(42) | ||
| + | </ | ||
| + | </ | ||
| + | |||
| + | |||
| + | ## Shared Sessions | ||
| + | By default, all editors on a page share a single python runtime. Functions defined in one execution are available in all editors afterwards, similar to jupyter notebooks. If you want an editor to have a separate python runtime, use the `session` attribute: | ||
| + | <code html> | ||
| + | < | ||
| + | def greet(name): | ||
| + | | ||
| + | </ | ||
| + | |||
| + | < | ||
| + | greet(' | ||
| + | </bottom-editor> | ||
| + | |||
| + | < | ||
| + | greet(' | ||
| + | </ | ||
| + | </ | ||
| + | |||
| + | < | ||
| + | def greet(name): | ||
| + | print(f' | ||
| + | </ | ||
| + | |||
| + | < | ||
| + | greet(' | ||
| + | </ | ||
| + | |||
| + | < | ||
| + | greet(' | ||
| + | </ | ||
| + | |||
| + | |||
| + | ## Turtle | ||
| + | Standard Python turtle with a small canvas. Use `layout=" | ||
| + | |||
| + | < | ||
| + | < | ||
| + | import turtle | ||
| + | |||
| + | t = turtle.Turtle() | ||
| + | t.speed(9) | ||
| + | colors = [' | ||
| + | for i in range(90): | ||
| + | t.pencolor(colors[i % len(colors)]) | ||
| + | t.forward(i * 0.5) | ||
| + | t.left(59) | ||
| + | </ | ||
| + | </ | ||
| + | |||
| + | < | ||
| + | import turtle | ||
| + | |||
| + | t = turtle.Turtle() | ||
| + | t.speed(9) | ||
| + | colors = [' | ||
| + | for i in range(90): | ||
| + | t.pencolor(colors[i % len(colors)]) | ||
| + | t.forward(i * 0.5) | ||
| + | t.left(59) | ||
| + | </ | ||
| + | |||
| + | ## Matplotlib | ||
| + | `plt.show()` renders to the canvas. | ||
| + | |||
| + | <code html> | ||
| + | < | ||
| + | # Load packages from within python using micropip | ||
| + | import micropip | ||
| + | await micropip.install(' | ||
| + | |||
| + | import matplotlib.pyplot as plt | ||
| + | import math | ||
| + | |||
| + | x = [i * 0.1 for i in range(63)] | ||
| + | plt.figure(figsize=(5, | ||
| + | plt.plot(x, [math.sin(v) for v in x], label=' | ||
| + | plt.plot(x, [math.cos(v) for v in x], label=' | ||
| + | plt.legend() | ||
| + | plt.title(' | ||
| + | plt.tight_layout() | ||
| + | plt.show() | ||
| + | </ | ||
| + | </ | ||
| + | |||
| + | < | ||
| + | # Load packages from within python using micropip | ||
| + | import micropip | ||
| + | await micropip.install(' | ||
| + | |||
| + | import matplotlib.pyplot as plt | ||
| + | import math | ||
| + | |||
| + | x = [i * 0.1 for i in range(63)] | ||
| + | plt.figure(figsize=(5, | ||
| + | plt.plot(x, [math.sin(v) for v in x], label=' | ||
| + | plt.plot(x, [math.cos(v) for v in x], label=' | ||
| + | plt.legend() | ||
| + | plt.title(' | ||
| + | plt.tight_layout() | ||
| + | plt.show() | ||
| + | </ | ||
| + | |||
| + | ## OpenCV | ||
| + | `cv2.imshow()` renders to the canvas. | ||
| + | |||
| + | <code html> | ||
| + | < | ||
| + | # Load packages from within python using micropip | ||
| + | import micropip | ||
| + | await micropip.install(' | ||
| + | await micropip.install(' | ||
| + | |||
| + | import numpy as np | ||
| + | import cv2 | ||
| + | |||
| + | # Gradient image with a circle | ||
| + | img = np.zeros((300, | ||
| + | for y in range(300): | ||
| + | for x in range(300): | ||
| + | img[y, x] = [x * 255 // 300, y * 255 // 300, 128] | ||
| + | cv2.circle(img, | ||
| + | cv2.putText(img, | ||
| + | cv2.imshow(' | ||
| + | </ | ||
| + | </ | ||
| + | |||
| + | < | ||
| + | # Load packages from within python using micropip | ||
| + | import micropip | ||
| + | await micropip.install(' | ||
| + | await micropip.install(' | ||
| + | |||
| + | import numpy as np | ||
| + | import cv2 | ||
| + | |||
| + | # Gradient image with a circle | ||
| + | img = np.zeros((300, | ||
| + | for y in range(300): | ||
| + | for x in range(300): | ||
| + | img[y, x] = [x * 255 // 300, y * 255 // 300, 128] | ||
| + | cv2.circle(img, | ||
| + | cv2.putText(img, | ||
| + | cv2.imshow(' | ||
| + | </ | ||
| + | ## Installing files | ||
| + | You can install files from an URL (with CORS headers if from a different domain!): | ||
| + | |||
| + | <code html> | ||
| + | < | ||
| + | with open(' | ||
| + | for line in infile: | ||
| + | tokens = line.split(',' | ||
| + | town = tokens[0] | ||
| + | if town == ' | ||
| + | print(f' | ||
| + | </ | ||
| + | </ | ||
| + | |||
| + | < | ||
| + | with open(' | ||
| + | for line in infile: | ||
| + | tokens = line.split(',' | ||
| + | town = tokens[0] | ||
| + | if town == ' | ||
| + | print(f' | ||
| + | </ | ||
| + | |||
| + | ## Exercises | ||
| + | |||
| + | <code html> | ||
| + | < | ||
| + | Write a function < | ||
| + | <tt>1 + 2 + & | ||
| + | <tt>n ≤ 0</ | ||
| + | <script type=" | ||
| + | def sum_to(n): | ||
| + | pass | ||
| + | </ | ||
| + | <script type=" | ||
| + | assert sum_to(5) == 15, " | ||
| + | assert sum_to(1) == 1, " | ||
| + | assert sum_to(0) == 0, " | ||
| + | </ | ||
| + | <script type=" | ||
| + | def sum_to(n): | ||
| + | return sum(range(n+1)) | ||
| + | </ | ||
| + | </ | ||
| + | </ | ||
| + | |||
| + | < | ||
| + | Write a function < | ||
| + | <tt>1 + 2 + & | ||
| + | <tt>n ≤ 0</ | ||
| + | <script type=" | ||
| + | def sum_to(n): | ||
| + | pass | ||
| + | </ | ||
| + | <script type=" | ||
| + | assert sum_to(5) == 15, " | ||
| + | assert sum_to(1) == 1, " | ||
| + | assert sum_to(0) == 0, " | ||
| + | </ | ||
| + | <script type=" | ||
| + | def sum_to(n): | ||
| + | return sum(range(n+1)) | ||
| + | </ | ||
| + | </ | ||
| + | |||
| + | ## Persistence | ||
| + | |||
| + | Editors or excercises with an `id` attribute store the current state in the browser' | ||
| + | |||
| + | <code html> | ||
| + | < | ||
| + | print(42) | ||
| + | </ | ||
| + | </code> | ||
| - | ## JupyterLite | ||
| - | Also based on pyodide, but with jupyter support all around. | + | < |
| + | print(42) | ||
| + | </ | ||
| - | <code html>< | ||
| - | src=" | ||
| - | width=" | ||
| - | height=" | ||