-
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 ad931a3
Showing
157 changed files
with
37,645 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: 4aee839fe731f715ff87f679f4fdb3db | ||
tags: 33eac41acc08762151beb8f3b7b86c8f |
Empty file.
Binary file not shown.
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\nfrom collections import defaultdict\n\nimport matplotlib.pyplot as plt\nimport matplotlib.markers as mmarkers\n\nfrom data_prototype.artist import CompatibilityAxes\nfrom data_prototype.containers import ArrayContainer\nfrom data_prototype.conversion_edge import FuncEdge\nfrom data_prototype.description import Desc\n\nfrom data_prototype.line import Line\n\nimport pint\n\nureg = pint.UnitRegistry()\nureg.setup_matplotlib()\n\nmarker_obj = mmarkers.MarkerStyle(\"o\")\n\n\ncoords = defaultdict(lambda: \"auto\")\ncoords[\"x\"] = coords[\"y\"] = \"units\"\ncont = ArrayContainer(\n coords,\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, nax = plt.subplots()\nax = CompatibilityAxes(nax)\nnax.add_artist(ax)\nax.set_xlim(-0.5, 7)\nax.set_ylim(0, 5)\n\nscalar = Desc((), \"units\")\nunit_vector = Desc((\"N\",), \"units\")\n\nxconv = FuncEdge.from_func(\n \"xconv\",\n lambda x, xunits: x.to(xunits).magnitude,\n {\"x\": unit_vector, \"xunits\": scalar},\n {\"x\": Desc((\"N\",), \"data\")},\n)\nyconv = FuncEdge.from_func(\n \"yconv\",\n lambda y, yunits: y.to(yunits).magnitude,\n {\"y\": unit_vector, \"yunits\": scalar},\n {\"y\": Desc((\"N\",), \"data\")},\n)\nlw = Line(cont, [xconv, yconv])\n\nax.add_artist(lw)\nnax.xaxis.set_units(ureg.ft)\nnax.yaxis.set_units(ureg.m)\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.14" | ||
} | ||
}, | ||
"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,94 @@ | ||
""" | ||
========================== | ||
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.conversion_edge import Graph | ||
from data_prototype.description import Desc | ||
|
||
from data_prototype.wrappers import PathCollectionWrapper | ||
|
||
|
||
class Lissajous: | ||
N = 1024 | ||
# cycles per minutes | ||
scale = 2 | ||
|
||
def describe(self): | ||
return { | ||
"x": Desc((self.N,)), | ||
"y": Desc((self.N,)), | ||
"time": Desc(()), | ||
"sizes": Desc(()), | ||
"paths": Desc(()), | ||
"edgecolors": Desc(()), | ||
"facecolors": Desc((self.N,)), | ||
} | ||
|
||
def query( | ||
self, | ||
graph: Graph, | ||
parent_coordinates: str = "axes", | ||
) -> 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() |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
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.artist import CompatibilityArtist as CA\nfrom data_prototype.line import Line\nfrom data_prototype.containers import FuncContainer\nfrom data_prototype.description import Desc\nfrom data_prototype.conversion_edge import FuncEdge\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 _, 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, graph, parent_coordinates):\n key = super()._query_hash(graph, parent_coordinates)\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 _, 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 = Line(\n fc,\n # color map phase (scaled to 2pi and wrapped to [0, 1])\n [\n FuncEdge.from_func(\n \"color\",\n lambda color: cmap((color / (2 * np.pi)) % 1),\n {\"color\": Desc((1,))},\n {\"color\": Desc((), \"display\")},\n )\n ],\n linewidth=5.0,\n linestyle=\"-\",\n)\nax.add_artist(CA(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 _: [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.14" | ||
} | ||
}, | ||
"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.14" | ||
} | ||
}, | ||
"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 FormattedText\nfrom data_prototype.artist import CompatibilityArtist as CA\nfrom data_prototype.line import Line\nfrom data_prototype.containers import ArrayContainer\nfrom data_prototype.description import Desc\nfrom data_prototype.conversion_node import FunctionConversionNode\nfrom data_prototype.conversion_edge import FuncEdge\n\n\ncmap = plt.colormaps[\"viridis\"]\ncmap.set_over(\"k\")\ncmap.set_under(\"r\")\nnorm = Normalize(1, 8)\n\nline_edges = [\n FuncEdge.from_func(\n \"lw\",\n lambda lw: min(1 + lw, 5),\n {\"lw\": Desc((), \"auto\")},\n {\"linewidth\": Desc((), \"display\")},\n ),\n # Probably should separate out norm/cmap step\n # Slight lie about color being a string here, because of limitations in impl\n FuncEdge.from_func(\n \"cmap\",\n lambda j: cmap(norm(j)),\n {\"j\": Desc((), \"auto\")},\n {\"color\": Desc((), \"display\")},\n ),\n FuncEdge.from_func(\n \"ls\",\n lambda cat: {\"A\": \"-\", \"B\": \":\", \"C\": \"--\"}[cat],\n {\"cat\": Desc((), \"auto\")},\n {\"linestyle\": Desc((), \"display\")},\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\": {0: \"A\", 1: \"B\", 2: \"C\"}[j % 3],\n }\n )\n ax.add_artist(\n CA(\n Line(\n ac,\n line_edges,\n )\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.14" | ||
} | ||
}, | ||
"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,88 @@ | ||
""" | ||
================ | ||
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.conversion_edge import Graph | ||
from data_prototype.description import Desc | ||
|
||
from data_prototype.conversion_node import FunctionConversionNode | ||
|
||
from data_prototype.wrappers import FormattedText | ||
from data_prototype.artist import CompatibilityArtist as CA | ||
from data_prototype.line import Line | ||
|
||
|
||
class SinOfTime: | ||
N = 1024 | ||
# cycles per minutes | ||
scale = 10 | ||
|
||
def describe(self): | ||
return { | ||
"x": Desc((self.N,)), | ||
"y": Desc((self.N,)), | ||
"phase": Desc(()), | ||
"time": Desc(()), | ||
} | ||
|
||
def query( | ||
self, | ||
graph: Graph, | ||
parent_coordinates: str = "axes", | ||
) -> Tuple[Dict[str, Any], Union[str, int]]: | ||
th = np.linspace(0, 2 * np.pi, self.N) | ||
|
||
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) | ||
|
||
|
||
def update(frame, art): | ||
return art | ||
|
||
|
||
sot_c = SinOfTime() | ||
lw = CA(Line(sot_c, linewidth=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.