mirror of
https://github.com/wassname/baukit.git
synced 2026-06-27 17:29:37 +08:00
Add demo notebook.
This commit is contained in:
Executable
+99
@@ -0,0 +1,99 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
Suppress output and prompt numbers in git version control.
|
||||
|
||||
This script will tell git to ignore prompt numbers and cell output
|
||||
when looking at ipynb files UNLESS their metadata contains:
|
||||
|
||||
"git" : { "keep_output" : true }
|
||||
|
||||
The notebooks themselves are not changed.
|
||||
|
||||
See also this blogpost: http://pascalbugnion.net/blog/ipython-notebooks-and-git.html.
|
||||
|
||||
Usage instructions
|
||||
==================
|
||||
|
||||
1. Put this script in a directory that is on the system's path.
|
||||
For future reference, I will assume you saved it in
|
||||
`~/scripts/ipynb_drop_output`.
|
||||
2. Make sure it is executable by typing the command
|
||||
`chmod +x ~/scripts/ipynb_drop_output`.
|
||||
3. Register a filter for ipython notebooks by
|
||||
putting the following line in `~/.config/git/attributes`:
|
||||
`*.ipynb filter=clean_ipynb`
|
||||
4. Connect this script to the filter by running the following
|
||||
git commands:
|
||||
|
||||
git config --global filter.clean_ipynb.clean ipynb_drop_output
|
||||
git config --global filter.clean_ipynb.smudge cat
|
||||
|
||||
To tell git NOT to ignore the output and prompts for a notebook,
|
||||
open the notebook's metadata (Edit > Edit Notebook Metadata). A
|
||||
panel should open containing the lines:
|
||||
|
||||
{
|
||||
"name" : "",
|
||||
"signature" : "some very long hash"
|
||||
}
|
||||
|
||||
Add an extra line so that the metadata now looks like:
|
||||
|
||||
{
|
||||
"name" : "",
|
||||
"signature" : "don't change the hash, but add a comma at the end of the line",
|
||||
"git" : { "keep_outputs" : true }
|
||||
}
|
||||
|
||||
You may need to "touch" the notebooks for git to actually register a change, if
|
||||
your notebooks are already under version control.
|
||||
|
||||
Notes
|
||||
=====
|
||||
|
||||
Changed by David Bau to make stripping output the default.
|
||||
|
||||
This script is inspired by http://stackoverflow.com/a/20844506/827862, but
|
||||
lets the user specify whether the ouptut of a notebook should be kept
|
||||
in the notebook's metadata, and works for IPython v3.0.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import json
|
||||
|
||||
nb = sys.stdin.read()
|
||||
|
||||
json_in = json.loads(nb)
|
||||
nb_metadata = json_in["metadata"]
|
||||
keep_output = False
|
||||
if "git" in nb_metadata:
|
||||
if "keep_outputs" in nb_metadata["git"] and nb_metadata["git"]["keep_outputs"]:
|
||||
keep_output = True
|
||||
if keep_output:
|
||||
sys.stdout.write(nb)
|
||||
exit()
|
||||
|
||||
|
||||
ipy_version = int(json_in["nbformat"]) - 1 # nbformat is 1 more than actual version.
|
||||
|
||||
|
||||
def strip_output_from_cell(cell):
|
||||
if "outputs" in cell:
|
||||
cell["outputs"] = []
|
||||
if "prompt_number" in cell:
|
||||
del cell["prompt_number"]
|
||||
if "execution_count" in cell:
|
||||
cell["execution_count"] = None
|
||||
|
||||
|
||||
if ipy_version == 2:
|
||||
for sheet in json_in["worksheets"]:
|
||||
for cell in sheet["cells"]:
|
||||
strip_output_from_cell(cell)
|
||||
else:
|
||||
for cell in json_in["cells"]:
|
||||
strip_output_from_cell(cell)
|
||||
|
||||
json.dump(json_in, sys.stdout, sort_keys=True, indent=1, separators=(",", ": "),
|
||||
ensure_ascii=False)
|
||||
Executable
+12
@@ -0,0 +1,12 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Start from directory of script
|
||||
cd "$(dirname "${BASH_SOURCE[0]}")"
|
||||
|
||||
# Set up git config filters so huge output of notebooks is not committed.
|
||||
git config filter.clean_ipynb.clean "$(pwd)/ipynb_drop_output.py"
|
||||
git config filter.clean_ipynb.smudge cat
|
||||
git config filter.clean_ipynb.required true
|
||||
|
||||
# Set up directory for testing.
|
||||
ln -s ../torchkit .
|
||||
@@ -0,0 +1,327 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "d5d14b97",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%%bash\n",
|
||||
"!(stat -t /usr/local/lib/*/dist-packages/google/colab > /dev/null 2>&1) && exit\n",
|
||||
"pip install git+https://github.com/davidbau/baukit > /dev/null"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "5bf765e1",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Using baukit show()\n",
|
||||
"\n",
|
||||
"`show()` is similar to notebook's `display()`, but it is gives you more control over layout and rendering of the HTML.\n",
|
||||
"\n",
|
||||
"To start, you can use it just like `print()` or `display()`."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "ac2488b8",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from baukit import show\n",
|
||||
"\n",
|
||||
"show('hello', 'world')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "8d40a6a9",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Easy layouts by nesting arrays\n",
|
||||
"\n",
|
||||
"`show()` makes it easy to produce layouts of data by arranging it in nested arrays. At the top level, data is arranged in rows; then at the second level, data is arranged in columns; then at the third level, it is split into rows again, and so on.\n",
|
||||
"\n",
|
||||
"(Technical detail: the HTML it produces uses [CSS flexbox layouts](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flexible_Box_Layout/Basic_Concepts_of_Flexbox), alternating row and column flex containers for each level of nesting.)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "c67bd9a1",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"show(['first row ' * 30,\n",
|
||||
" ['second row ' * 10, 'second row second item ' * 5],\n",
|
||||
" ['third row ' * 10, ['third row second item ' * 5, ['some more', 'data', 'here']]]])"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "b43c195d",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## A simple grid layout example\n",
|
||||
"\n",
|
||||
"A very common pattern is to show data in a grid. Here is a three-level nested piece of retangular data:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "c969092b",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"show([[['hello', [i, j]] for j in range(1, 8)] for i in range(1, 6)])"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "3c2ec531",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Showing images\n",
|
||||
"\n",
|
||||
"Unlike `display()`, `show()` knows how to directly render PIL images and matplotlib figures and other types of data. It also provides more powerful layout in HTML and gives you much more control over CSS formatting. "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "623a727b",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from PIL import Image\n",
|
||||
"from numpy.random import randint\n",
|
||||
"\n",
|
||||
"show([[[f'image {i}',\n",
|
||||
" Image.fromarray(randint(0,255,(128,128,3),dtype='uint8'))]\n",
|
||||
" for i in range(10)]])\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "118175c2",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Controlling CSS\n",
|
||||
"\n",
|
||||
"The style of anything emitted by show can be controlled by using `show.style()` to inject CSS properties. `show.style` will alter the CSS style of the next item rendered by `show()`."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "0799c0f5",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"show([show.style(background='pink', font='italic 24px serif'), 'A demonstration of CSS control',\n",
|
||||
" [show.style(background='skyblue'), 2, show.style(background='yellow', flex=2), 3],\n",
|
||||
" show.style(background='lightgreen'), 4])"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "b78f64fa",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Tight columns and Wrapped rows\n",
|
||||
"\n",
|
||||
"A few useful `show.style` instances are defined as constants. For example, `show.style(display='inline-flex')` is also called `show.TIGHT`, because it provides a tight layout of rows that are sized to fit the content instead of making the flexbox expand to fill its container. Similaly `show.WRAP` makes a row that packs the data to the left and wraps it (like the way text flows), instad of as spaced-out columns."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "a3e7884e",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"show(show.TIGHT,\n",
|
||||
" [[[show.style(font='italic 24px serif'), 'lots of data',\n",
|
||||
" show.style(background='gainsboro'),\n",
|
||||
" show.WRAP, [f'({a},{b})' for a in range(i) for b in range(j)]]\n",
|
||||
" for j in range(1, 5)] for i in range(1, 3)])"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "92a1c75c",
|
||||
"metadata": {
|
||||
"scrolled": false
|
||||
},
|
||||
"source": [
|
||||
"## Showing widgets\n",
|
||||
"\n",
|
||||
"baukit also contains a bunch of widgets like `Range()` and `Numberbox()` that can be shown and laid out:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "816a2956",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from baukit import Range, Numberbox\n",
|
||||
"\n",
|
||||
"nb = Numberbox()\n",
|
||||
"ra = Range()\n",
|
||||
"\n",
|
||||
"show([[nb, show.style(flex=5), ra]])"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "63713d4b",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Getting and setting widget values\n",
|
||||
"\n",
|
||||
"Widgets are live data-bound objects. So if you change a value in the widget, it will display that value right away. Also, if the user enters some input, it will be reflected in the python value right away. To see that effect, run the following cells while interacting with the widgets above:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "8e8a3115",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import random\n",
|
||||
"nb.value = random.randrange(100)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "74bf1a9c",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"print(nb.value)\n",
|
||||
"print(ra.value)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "770f5858",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Binding live widget properties\n",
|
||||
"\n",
|
||||
"Widget properties can be bound together - if you refer to a widget property using the `widget.prop()` method, it will return a live property object that can be bound to another property.\n",
|
||||
"\n",
|
||||
"(Also notice that if you show the same widget instance multiple times, all the rendered views will in sync.)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "a9c0f78f",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"nb2 = Numberbox()\n",
|
||||
"ra2 = Range(max=1, step=0.001)\n",
|
||||
"\n",
|
||||
"ra2.value = nb2.prop('value')\n",
|
||||
"\n",
|
||||
"show([[nb2, show.style(flex=6), ra2]])\n",
|
||||
"show(ra2)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "8b8a23a9",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Using PlotWidget\n",
|
||||
"\n",
|
||||
"Matplotlib plots can be displayed within HTML by showing the matplotlib figure.\n",
|
||||
"\n",
|
||||
"`PlotWidget` is a widget that manages the matplotlib figure and allows you to create a parameterized plot by writing a plotting function. Any arguments in your plotting function become parameters of the PlotWidget that you can adjust.\n",
|
||||
"\n",
|
||||
"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "1146dbc8",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import torch\n",
|
||||
"from baukit import PlotWidget\n",
|
||||
"\n",
|
||||
"def myplot(plt, frequency=1.0, amplitude=1.0):\n",
|
||||
" [ax] = plt.axes\n",
|
||||
" ax.clear()\n",
|
||||
" ax.set_title(f'Sine wave of frequency {frequency}, amplitude {amplitude}')\n",
|
||||
" x = torch.linspace(0, 20, 300)\n",
|
||||
" y = (frequency * x).sin()\n",
|
||||
" ax.plot(x, amplitude * y)\n",
|
||||
" ax.set_ylim(-5, 5)\n",
|
||||
"\n",
|
||||
"show([[PlotWidget(myplot, format='svg', figsize=(5,3.5)), PlotWidget(myplot, frequency=2, amplitude=3, format='svg', figsize=(5,3.5))]])"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "bc9f6a72",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Making interactive matplotlib plots with PlotWidget\n",
|
||||
"\n",
|
||||
"`PlotWidget` properties can be bound together just like any other widget properties, so it is easy to define an interactive plot interface."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "8ed28ab5",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"\n",
|
||||
"freq_ra = Range(min=0.1, max=5.0, step=0.01, value=1.0)\n",
|
||||
"freq_nb = Numberbox(freq_ra.prop('value'))\n",
|
||||
"amp_ra = Range(min=0.1, max=5.0, step=0.01, value=1.0)\n",
|
||||
"amp_nb = Numberbox(amp_ra.prop('value'))\n",
|
||||
"pw = PlotWidget(myplot, frequency=freq_ra.prop('value'), amplitude=amp_ra.prop('value'))\n",
|
||||
"show(show.TIGHT, [[pw],\n",
|
||||
" ['frequency', show.style(flex=10), freq_ra, freq_nb],\n",
|
||||
" ['amplitude', show.style(flex=10), amp_ra, amp_nb]])"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.9.12"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
Reference in New Issue
Block a user