From 7282ce5ad02998c09ef7d47cb2045fe6104d4b76 Mon Sep 17 00:00:00 2001 From: Ian Hunt-Isaak Date: Fri, 17 Feb 2023 13:51:10 -0500 Subject: [PATCH] init wip --- paper/imgs/sinusoid.png | Bin 0 -> 33855 bytes paper/paper.bib | 11 +++++ paper/paper.md | 107 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 118 insertions(+) create mode 100644 paper/imgs/sinusoid.png create mode 100644 paper/paper.bib create mode 100644 paper/paper.md diff --git a/paper/imgs/sinusoid.png b/paper/imgs/sinusoid.png new file mode 100644 index 0000000000000000000000000000000000000000..a9cdff1837ccd7235b171cb629c926a5d15c57ad GIT binary patch literal 33855 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 literal 0 HcmV?d00001 diff --git a/paper/paper.bib b/paper/paper.bib new file mode 100644 index 0000000..c5b04ad --- /dev/null +++ b/paper/paper.bib @@ -0,0 +1,11 @@ +@article{Pearson:2017, + url = {http://adsabs.harvard.edu/abs/2017arXiv170304627P}, + Archiveprefix = {arXiv}, + Author = {{Pearson}, S. and {Price-Whelan}, A.~M. and {Johnston}, K.~V.}, + Eprint = {1703.04627}, + Journal = {ArXiv e-prints}, + Keywords = {Astrophysics - Astrophysics of Galaxies}, + Month = mar, + Title = {{Gaps in Globular Cluster Streams: Pal 5 and the Galactic Bar}}, + Year = 2017 +} diff --git a/paper/paper.md b/paper/paper.md new file mode 100644 index 0000000..3777048 --- /dev/null +++ b/paper/paper.md @@ -0,0 +1,107 @@ +--- +title: "mpl-interactions: A Python package for dynamic Matplotlib plots" +tags: + - Python + - some-other-tags-maybe +authors: + - name: Ian Hunt-Isaak + orcid: 0000-0002-7591-083X + affiliation: "1" # (Multiple affiliations must be quoted) +affiliations: + - name: John A. Paulson School of Engineering and Applied Sciences, Harvard University, USA + index: 1 +date: 14 February 2023 +bibliography: paper.bib +--- + +# Summary + + + +`mpl-interactions` enables users to transform static matplotlib figures to dynamic figures with control of the parameters of the plot elements through automatically generated widgets. It creates widgets and connects them to update plot elements automatically using a shorthand for widgets optimized for control of plots. In order to be as easy to use as possible it adds these features while otherwise staying as close to the `matplotlib.pyplot` interface as possible. It is built to be composable with itself while not interfering with static plotting elements. This allows for building any figure that `matplotlib` can produce while adding dynamism to specific parts as necessary to increase the utility of the plot. `mpl-interactions` allows to be used for exploring the parameters of computational and mathematical models. + +# Statement of Need + + + +A plot that dynamically updates as a user interacts with a widget such as a slider can be a very powerful tool in the scientific process as well as in pedagogy. For instance varying a parameter of a mathematical model plotted on top of data helps to understand the model - useful for both modelling in research and for pedagogy. Similarly it very useful during exploratory data analysis to interactively modify aspects of the plot such as points are displayed, or the threshold level of image. + +While it is possible to accomplish this using existing tools such as `matplotlib` and `ipywidgets`, the complexity of doing so dramatically slows down analysis and learning. `matplotlib` is a powerful Python library for visualizations. For static plots it is the defacto standard for academic work and many students and scientists have familirity produce data visualizations with it. In addition to the capability of creating static figures it has mechanisms for building interactive visualizations. Many of it's artists have APIs that allow updating them to reflect new data and it implements a basic set of widgets such as sliders and radio buttons. However, artist APIs are not consistent and sometimes under or undocumented, and positioning the widgets can be non-trivial. Learning, and then remembering the specifics of how to update an artist along with writing the boilerplate of callbacks significantly slows iteration when investigating data. + +The `ipywidgets` makes widget creation easier, and handles layout for the user, but is still difficult to use quickly with matplotlib as doing so requires remembering how update matplotlib artists and writing approriate callbacks. The easiest approach for users is to use hte `ipywidgets`' `interact` function (footnote: this is inspiration for the package name) which automatically generates sliders and other widgets to control arguments to arbitrary python functions. However, the this has drawbacks as well, the recommended usage is to re-make the plot every time a parameter changes, and it only works in an context where ipywidgets can be displayed (e.g. jupyterlab). Finally, `ipywidgets` is a general framework, and thus constrained in how it's choices of how to intrepret shorthands for widget generation - the choices it makes are not always optimal for scientific plotting. + +`mpl-interactions` builds on top of both of these packages in order make their power available while reducing the complexity of generating an interactive plot to a single line. It automates the creation of widgets, using a shorthand optimized for scientific plotting. It works anywhere matplotlib does, creating ipywidgets if they are available, but falling back to matplotlib widgets necessary. In addition when generating matplotlib widgets it automatically handles widget layout. After creating widgets it connects callbacks to update the matplotlib artists in the most performant way possible. Finally, `mpl-interactions` handles, updating the matplotlib axis limits as the plot elements update. Without this plot elements can easily go off screen. + +# Examples + +Imports for examples: + +```python +import mpl_interactions.ipyplot as iplt +import matplotlib.pyplot as plt +import numpy as np +``` + +Example demonstrating the ability to update the axis limits, as well passing a numpy array, or a tuple to generate a slider: + +```python +x = np.linspace(0, np.pi, 100) +tau = np.linspace(0.5, 10, 100) + +def f1(x, tau, beta): + return np.sin(x * tau) * x * beta + +fig, ax = plt.subplots() +controls = iplt.plot(x, f1, tau=tau, beta=(1, 10, 100)) +plt.show() +``` + +And example demonstrating reusing widgets generated from earlier function calls to control other plot elements. + +```python +N = 128 +im = np.random.randn(N * N).reshape(N, N) + +fig, axs = plt.subplots(1, 2, figsize=(12, 5)) + +# plot histogram of pixel intensities +axs[1].hist(im.flatten(), bins="auto") +axs[1].set_title("Histogram of Pixel Intensities") + +# create interactive controls +ctrls = iplt.imshow(im, vmin_vmax=("r", im.min(), im.max()), ax=axs[0]) +iplt.axvline(ctrls["vmin"], ax=axs[1], c="k") +_ = iplt.axvline(ctrls["vmax"], ax=axs[1], c="k") +``` + +# Overview + +`mpl-interactions` builds on top of the `matplotlib.pyplot`. While `matplotlib` requires users are to pass in arrays as arguments, `mpl-interactions` allows passing a function that returns numeric values. Parameters to these functions are specified by adding extra keyword arguments (`kwargs`) to the function call. Then `mpl-interactions` will generate the approriate widgets for the parameters and run the functions to generate the numerical data to plot. For example to plot a sinusoid and control it's amplitude and frequency using sliders a function returning the `y` values is defined and passed as the `y` parameter to the `plot` function. The ranges of the `A` and `f` parameters are defined using as extra kwargs using tuples as a widget shorthand. + +```python +import mpl_interactions.ipyplot as iplt +import matplotlib.pyplot as plt +import numpy as np + +fig, ax = plt.subplots() + +def sinusoid(x, A, f): + return A*np.sin(x * f) +x = np.linspace(0, np.pi, 100) + +ctrls = iplt.plot(x, sinusoid, A=(1, 10), f = (.5, 2)) +plt.show() +``` + +![Generated figure and sliders after running above example in jupyter lab.\label{fig:sinusoid}](imgs/sinusoid.png){ width=75% } + +# Acknowledgements + +Ian was supported by the NDSEG + Doeke + +Discussion: Kevin Dalton +Contributions: John Russell, Remco De Boer, Samantha Hamilton, + +- other contributors. + +Many users who have posted questions + feedback