Skip to content

Commit

Permalink
deploy: 830ce25
Browse files Browse the repository at this point in the history
  • Loading branch information
tacaswell committed Dec 27, 2023
0 parents commit e538ad4
Show file tree
Hide file tree
Showing 135 changed files with 37,298 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .buildinfo
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Sphinx build info version 1
# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done.
config: cd3960d4726b78ad06d5a30c8bd36040
tags: 33eac41acc08762151beb8f3b7b86c8f
Empty file added .nojekyll
Empty file.
43 changes: 43 additions & 0 deletions _downloads/0e7d7952485b73289daa910c8be00ede/units.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n# Using pint units with PathCollectionWrapper\n\nUsing third party units functionality in conjunction with Matplotlib Axes\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"import numpy as np\n\nimport matplotlib.pyplot as plt\nimport matplotlib.markers as mmarkers\n\nfrom data_prototype.containers import ArrayContainer\nfrom data_prototype.conversion_node import DelayedConversionNode\n\nfrom data_prototype.wrappers import PathCollectionWrapper\n\nimport pint\n\nureg = pint.UnitRegistry()\nureg.setup_matplotlib()\n\nmarker_obj = mmarkers.MarkerStyle(\"o\")\n\ncont = ArrayContainer(\n x=np.array([0, 1, 2]) * ureg.m,\n y=np.array([1, 4, 2]) * ureg.m,\n paths=np.array([marker_obj.get_path()]),\n sizes=np.array([12]),\n edgecolors=np.array([\"k\"]),\n facecolors=np.array([\"C3\"]),\n)\n\nfig, ax = plt.subplots()\nax.set_xlim(-0.5, 7)\nax.set_ylim(0, 5)\n\n# DelayedConversionNode is used to identify the keys which undergo unit transformations\n# The actual method which does conversions in this example is added by the\n# `Axis`/`Axes`, but `PathCollectionWrapper` does not natively interact with the units.\nxconv = DelayedConversionNode.from_keys((\"x\",), converter_key=\"xunits\")\nyconv = DelayedConversionNode.from_keys((\"y\",), converter_key=\"yunits\")\nlw = PathCollectionWrapper(cont, [xconv, yconv], offset_transform=ax.transData)\nax.add_artist(lw)\nax.xaxis.set_units(ureg.feet)\nax.yaxis.set_units(ureg.m)\nplt.show()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"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.10.13"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
92 changes: 92 additions & 0 deletions _downloads/12252586a39c52c1e308241c43ab220c/lissajous.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
"""
==========================
An animated lissajous ball
==========================
Inspired by https://twitter.com/_brohrer_/status/1584681864648065027
An animated scatter plot using a custom container and :class:`.wrappers.PathCollectionWrapper`
"""
import time
from typing import Dict, Tuple, Any, Union
from functools import partial

import numpy as np

import matplotlib.pyplot as plt
import matplotlib.markers as mmarkers
from matplotlib.animation import FuncAnimation

from data_prototype.containers import _MatplotlibTransform, Desc

from data_prototype.wrappers import PathCollectionWrapper


class Lissajous:
N = 1024
# cycles per minutes
scale = 2

def describe(self):
return {
"x": Desc([self.N], float),
"y": Desc([self.N], float),
"time": Desc([], float),
"sizes": Desc([], float),
"paths": Desc([], float),
"edgecolors": Desc([], str),
"facecolors": Desc([self.N], str),
}

def query(
self,
transform: _MatplotlibTransform,
size: Tuple[int, int],
) -> Tuple[Dict[str, Any], Union[str, int]]:
def next_time():
cur_time = time.time()
cur_time = np.array(
[cur_time, cur_time - 0.1, cur_time - 0.2, cur_time - 0.3]
)

phase = 15 * np.pi * (self.scale * cur_time % 60) / 150
marker_obj = mmarkers.MarkerStyle("o")
return {
"x": np.cos(5 * phase),
"y": np.sin(3 * phase),
"sizes": np.array([256]),
"paths": [
marker_obj.get_path().transformed(marker_obj.get_transform())
],
"edgecolors": "k",
"facecolors": ["#4682b4ff", "#82b446aa", "#46b48288", "#8246b433"],
"time": cur_time[0],
}, hash(cur_time[0])

return next_time()


def update(frame, art):
return art


sot_c = Lissajous()

fig, ax = plt.subplots()
ax.set_xlim(-1.1, 1.1)
ax.set_ylim(-1.1, 1.1)
lw = PathCollectionWrapper(sot_c, offset_transform=ax.transData)
ax.add_artist(lw)
# ax.set_xticks([])
# ax.set_yticks([])
ax.set_aspect(1)
ani = FuncAnimation(
fig,
partial(update, art=(lw,)),
frames=60,
interval=1000 / 100 * 15,
# TODO: blitting does not work because wrappers do not inherent from Artist
# blit=True,
)
plt.show()
43 changes: 43 additions & 0 deletions _downloads/1c53d85aadacff2886f767f44fd5bfe2/widgets.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n# Slider\n\nIn this example, sliders are used to control the frequency and amplitude of\na sine wave.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"import inspect\n\nimport numpy as np\nimport matplotlib.pyplot as plt\nfrom matplotlib.widgets import Slider, Button\n\nfrom data_prototype.wrappers import LineWrapper\nfrom data_prototype.containers import FuncContainer\nfrom data_prototype.conversion_node import FunctionConversionNode\n\n\nclass SliderContainer(FuncContainer):\n def __init__(self, xfuncs, /, **sliders):\n self._sliders = sliders\n for slider in sliders.values():\n slider.on_changed(\n lambda x, sld=slider: sld.ax.figure.canvas.draw_idle(),\n )\n\n def get_needed_keys(f, offset=1):\n return tuple(inspect.signature(f).parameters)[offset:]\n\n super().__init__(\n {\n k: (\n s,\n # this line binds the correct sliders to the functions\n # and makes lambdas that match the API FuncContainer needs\n lambda x, keys=get_needed_keys(f), f=f: f(\n x, *(sliders[k].val for k in keys)\n ),\n )\n for k, (s, f) in xfuncs.items()\n },\n )\n\n def _query_hash(self, coord_transform, size):\n key = super()._query_hash(coord_transform, size)\n # inject the slider values into the hashing logic\n return hash((key, tuple(s.val for s in self._sliders.values())))\n\n\n# Define initial parameters\ninit_amplitude = 5\ninit_frequency = 3\n\n# Create the figure and the line that we will manipulate\nfig, ax = plt.subplots()\nax.set_xlim(0, 1)\nax.set_ylim(-7, 7)\n\nax.set_xlabel(\"Time [s]\")\n\n# adjust the main plot to make room for the sliders\nfig.subplots_adjust(left=0.25, bottom=0.25, right=0.75)\n\n# Make a horizontal slider to control the frequency.\naxfreq = fig.add_axes([0.25, 0.1, 0.65, 0.03])\nfreq_slider = Slider(\n ax=axfreq,\n label=\"Frequency [Hz]\",\n valmin=0.1,\n valmax=30,\n valinit=init_frequency,\n)\n\n# Make a vertically oriented slider to control the amplitude\naxamp = fig.add_axes([0.1, 0.25, 0.0225, 0.63])\namp_slider = Slider(\n ax=axamp,\n label=\"Amplitude\",\n valmin=0,\n valmax=10,\n valinit=init_amplitude,\n orientation=\"vertical\",\n)\n\n# Make a vertically oriented slider to control the phase\naxphase = fig.add_axes([0.85, 0.25, 0.0225, 0.63])\nphase_slider = Slider(\n ax=axphase,\n label=\"Phase [rad]\",\n valmin=-2 * np.pi,\n valmax=2 * np.pi,\n valinit=0,\n orientation=\"vertical\",\n)\n\n# pick a cyclic color map\ncmap = plt.get_cmap(\"twilight\")\n\n# set up the data container\nfc = SliderContainer(\n {\n # the x data does not need the sliders values\n \"x\": ((\"N\",), lambda t: t),\n \"y\": (\n (\"N\",),\n # the y data needs all three sliders\n lambda t, amplitude, frequency, phase: amplitude\n * np.sin(2 * np.pi * frequency * t + phase),\n ),\n # the color data has to take the x (because reasons), but just\n # needs the phase\n \"color\": ((1,), lambda t, phase: phase),\n },\n # bind the sliders to the data container\n amplitude=amp_slider,\n frequency=freq_slider,\n phase=phase_slider,\n)\nlw = LineWrapper(\n fc,\n # color map phase (scaled to 2pi and wrapped to [0, 1])\n FunctionConversionNode.from_funcs(\n {\"color\": lambda color: cmap((color / (2 * np.pi)) % 1)}\n ),\n lw=5,\n)\nax.add_artist(lw)\n\n\n# Create a `matplotlib.widgets.Button` to reset the sliders to initial values.\nresetax = fig.add_axes([0.8, 0.025, 0.1, 0.04])\nbutton = Button(resetax, \"Reset\", hovercolor=\"0.975\")\nbutton.on_clicked(\n lambda event: [sld.reset() for sld in (freq_slider, amp_slider, phase_slider)]\n)\n\nplt.show()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"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.10.13"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
43 changes: 43 additions & 0 deletions _downloads/1d0b7c60915fdc25194d452d702ef50d/mulivariate_cmap.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n# Custom bivariate colormap\n\n\nUsing ``nu`` functions to account for two values when computing the color\nof each pixel.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"import matplotlib.pyplot as plt\nimport numpy as np\n\nfrom data_prototype.wrappers import ImageWrapper\nfrom data_prototype.containers import FuncContainer\nfrom data_prototype.conversion_node import FunctionConversionNode\n\nfrom matplotlib.colors import hsv_to_rgb\n\n\ndef func(x, y):\n return (\n (np.sin(x).reshape(1, -1) * np.cos(y).reshape(-1, 1)) ** 2,\n np.arctan2(np.cos(y).reshape(-1, 1), np.sin(x).reshape(1, -1)),\n )\n\n\ndef image_nu(image):\n saturation, angle = image\n hue = (angle + np.pi) / (2 * np.pi)\n value = np.ones_like(hue)\n return np.clip(hsv_to_rgb(np.stack([hue, saturation, value], axis=2)), 0, 1)\n\n\nfc = FuncContainer(\n {},\n xyfuncs={\n \"xextent\": ((2,), lambda x, y: [x[0], x[-1]]),\n \"yextent\": ((2,), lambda x, y: [y[0], y[-1]]),\n \"image\": ((\"N\", \"M\", 2), func),\n },\n)\n\nim = ImageWrapper(fc, FunctionConversionNode.from_funcs({\"image\": image_nu}))\n\nfig, ax = plt.subplots()\nax.add_artist(im)\nax.set_xlim(-5, 5)\nax.set_ylim(-5, 5)\nplt.show()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"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.10.13"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
43 changes: 43 additions & 0 deletions _downloads/1dfc18ed16c3e8e6146b6197b56ecc2f/mapped.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n# Mapping Line Properties\n\nLeveraging the converter functions to transform users space data to visualization data.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"import matplotlib.pyplot as plt\nimport numpy as np\n\nfrom matplotlib.colors import Normalize\n\nfrom data_prototype.wrappers import LineWrapper, FormattedText\nfrom data_prototype.containers import ArrayContainer\nfrom data_prototype.conversion_node import FunctionConversionNode\n\ncmap = plt.colormaps[\"viridis\"]\ncmap.set_over(\"k\")\ncmap.set_under(\"r\")\nnorm = Normalize(1, 8)\n\nline_converter = FunctionConversionNode.from_funcs(\n {\n # arbitrary functions\n \"lw\": lambda lw: min(1 + lw, 5),\n # standard color mapping\n \"color\": lambda j: cmap(norm(j)),\n # categorical\n \"ls\": lambda cat: {\"A\": \"-\", \"B\": \":\", \"C\": \"--\"}[cat[()]],\n },\n)\n\ntext_converter = FunctionConversionNode.from_funcs(\n {\n \"text\": lambda j, cat: f\"index={j[()]} class={cat[()]!r}\",\n \"y\": lambda j: j,\n \"x\": lambda x: 2 * np.pi,\n },\n)\n\n\nth = np.linspace(0, 2 * np.pi, 128)\ndelta = np.pi / 9\n\nfig, ax = plt.subplots()\n\nfor j in range(10):\n ac = ArrayContainer(\n **{\n \"x\": th,\n \"y\": np.sin(th + j * delta) + j,\n \"j\": np.asarray(j),\n \"lw\": np.asarray(j),\n \"cat\": np.asarray({0: \"A\", 1: \"B\", 2: \"C\"}[j % 3]),\n }\n )\n ax.add_artist(\n LineWrapper(\n ac,\n line_converter,\n )\n )\n ax.add_artist(\n FormattedText(\n ac,\n text_converter,\n x=2 * np.pi,\n ha=\"right\",\n bbox={\"facecolor\": \"gray\", \"alpha\": 0.5},\n )\n )\nax.set_xlim(0, np.pi * 2)\nax.set_ylim(-1.1, 10.1)\n\nplt.show()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"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.10.13"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
86 changes: 86 additions & 0 deletions _downloads/1f0966d964d55653ad834adb5f7aa687/animation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
"""
================
An animated line
================
An animated line using a custom container class,
:class:`.wrappers.LineWrapper`, and :class:`.wrappers.FormattedText`.
"""
import time
from typing import Dict, Tuple, Any, Union
from functools import partial

import numpy as np

import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation

from data_prototype.containers import _MatplotlibTransform, Desc
from data_prototype.conversion_node import FunctionConversionNode

from data_prototype.wrappers import LineWrapper, FormattedText


class SinOfTime:
N = 1024
# cycles per minutes
scale = 10

def describe(self):
return {
"x": Desc([self.N], float),
"y": Desc([self.N], float),
"phase": Desc([], float),
"time": Desc([], float),
}

def query(
self,
coord_transformtransform: _MatplotlibTransform,
size: Tuple[int, int],
) -> Tuple[Dict[str, Any], Union[str, int]]:
th = np.linspace(0, 2 * np.pi, self.N)

def next_time():
cur_time = time.time()

phase = 2 * np.pi * (self.scale * cur_time % 60) / 60
return {
"x": th,
"y": np.sin(th + phase),
"phase": phase,
"time": cur_time,
}, hash(cur_time)

return next_time()


def update(frame, art):
return art


sot_c = SinOfTime()
lw = LineWrapper(sot_c, lw=5, color="green", label="sin(time)")
fc = FormattedText(
sot_c,
FunctionConversionNode.from_funcs(
{"text": lambda phase: f"ϕ={phase:.2f}", "x": lambda: 2 * np.pi, "y": lambda: 1}
),
ha="right",
)
fig, ax = plt.subplots()
ax.add_artist(lw)
ax.add_artist(fc)
ax.set_xlim(0, 2 * np.pi)
ax.set_ylim(-1.1, 1.1)
ani = FuncAnimation(
fig,
partial(update, art=(lw, fc)),
frames=25,
interval=1000 / 60,
# TODO: blitting does not work because wrappers do not inherent from Artist
# blit=True,
)

plt.show()
Loading

0 comments on commit e538ad4

Please sign in to comment.