-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit e538ad4
Showing
135 changed files
with
37,298 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
43
_downloads/1d0b7c60915fdc25194d452d702ef50d/mulivariate_cmap.ipynb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
Oops, something went wrong.