Package: manipylate
Description    {#orgedbdd51}The package repository is located athttps://github.com/bottom-bracket/manipylate.
It can also be installed frompypiwithpip install manipylate.In research we spend some time with plotting data, comparing measurement results
or testing the influence of parameter changes. Often the most intuitive approach
is by looking at different plots.
However, while python is great to create reproducible figures, I found no way to
quickly create plots with which one can interact without changing the code used
to create the plot as inmathematica’sManipulate. The closest one can get
to this isinteractfromipywidgetswhich is limited to run inJupyternotebooks.Manipylateshall provide the simplified functionalities from its bigger
siblingManipulate. The tasks I had in mind while writing the tool are:Plotting 1d and 2d cuts of multidimensional data and changing the slice index
with slidersPlot a function for changing parameters which one can modify interactivelyI also wanted to keep things as simple as possible and be able to usemanipylateoutsidejupyternotebooks.Interactivity    {#org1aa4893}Sliders are added automaticallyViews can be saved withShift + middle mouse clickin the figure if used in
purematplotlibmode and by click on the camera button injupyterExamples    {#org69b706b}First we get the environment ready (leave out the lines starting with%for
non-ipython shells).%matplotlib qt
%load_ext autoreload
%autoreload 2
import matplotlib as mpl
from matplotlib import pyplot as plt
import numpy as np
from manipylate import ifigure

The autoreload extension is already loaded. To reload it, use:
  %reload_ext autoreload1d cut through a 2d array    {#orgd93ca72}Let’s create some data:x = np.linspace(-5, 5, 200)
X, Y = np.meshgrid(x, x)
data = np.sinc(X * Y**2)The figure is created by creating anifigureobject. We can then call itsadd_plotmethod to add an axis and a line plot. Hereaxposdefines where the
plot shall be placed,xis thex-axis data.datathe 2d array of which we
want to plot a cut along the axis given byplot_ax, andparametersis a list
of dimension parameters we want to change using sliders.Callingshowcreates the figure. It needs to be called after all plots have been
added to the figure since here we’ll create the sliders and arange the slider
axes (in case of execution outside jupyter).ifig = ifigure(1,1)
ifig.add_plot(axpos=[0,0],x=x,data=data,parameters=['x'],plot_ax=1)
ifig.show()In jupyter notebook    {#org51186c9}In order to use theipywidgetwidgets, we callifigurewith thejupyterwidgetkeyword argument.ifig = ifigure(1,1,jupyterwidget=True)
ifig.add_plot(axpos=[0,0],x=x,data=data,parameters=['x'],plot_ax=1)
ifig.show()Adding a second plot    {#orgb7c979f}In the same axis    {#orgc24bc08}Axes are remembered by theifigureobject based on their position, so we can
call the sameadd_plotcommand with another dataset. Note that any keyword
arguments are passed tomatplotlib.axes.plot, so we can use this to change the
line style.ifig = ifigure(1,1)
ifig.add_plot(axpos=[0,0],x=x,data=data,parameters=['x'],plot_ax=1)
ifig.add_plot(axpos=[0,0],x=x,data=-data,parameters=['x'],plot_ax=1,ls=':')
ifig.show()Note that here both plots share the same parameter. In the next example we will
see that if called with a different name, a new slider will be created.As twinned axis    {#orgd05a4f2}Sometimes I want to compare two different values (like amplitude and phase) over
the same x axis. This can be done by passing thetwinx=Trueto theadd_plotmethod. Here I also use thefix_limflag to prevent the phase axis from
updating.
Note thatadd_plotreturns a matplotlib axis instance which we can modify as
usual (here setting the y scale to logarithmic).fc = np.linspace(-5, 5, 50) ** 2 + 250
x = np.linspace(200, 300, 120)
FC, X = np.meshgrid(fc, x, indexing="ij")
data = 1 / ((FC ** 2 - X ** 2 - 1j * X * 1) ** 2)

ifig = ifigure(1, 1)
ax = ifig.add_plot(axpos=[0, 0], x=x, data=np.abs(data), parameters=["fc"], plot_ax=1)
ax.set_yscale("log")
ifig.add_plot(
    axpos=[0, 0],
    x=x,
    data=np.angle(data, deg=True),
    parameters=["x"],
    plot_ax=1,
    twinx=True,
    ls=":",
    fix_lim=True,
)
ifig.show()As new axis    {#org08b1530}In order to add more than one subplots we adjust theifigurecreation.
Here we also use another parameter for the second plot.fc = np.linspace(-5, 5, 50) ** 2 + 250
x = np.linspace(200, 300, 120)
FC, X = np.meshgrid(fc, x, indexing="ij")
data = 1 / ((FC ** 2 - X ** 2 - 1j * X * 1) ** 2)

ifig = ifigure(2, 1)
ax = ifig.add_plot(axpos=[0, 0], x=x, data=np.abs(data), parameters=["fc"], plot_ax=1)
ax.set_yscale("log")
ifig.add_plot(
    axpos=[1, 0],
    x=fc,
    data=np.abs(data),
    parameters=["x"],
    plot_ax=0,
    ls=":",
)
ifig.show()2d cut trough nd array    {#orgb43b3a9}Plotting a 2d cut is nearly the same as a 1d line.ifigurecreates animshowplot when being passed data which has two more dimensions than the number of
parameters passed to the function.
For the 2d plot we need to specify along which axes we want to cut by changing
theplot_axargument to a list of length 2.x = np.linspace(-5, 5, 200)
y = np.linspace(-3, 3, 100)
z = np.linspace(-4, 4, 80)
X, Y ,Z = np.meshgrid(x, y, z,indexing='ij')
data = np.sinc(X * Y**2 * Z**3)

ifig=ifigure(1,1)

ifig.add_plot(axpos=[0,0],x=[x,y],data=data,parameters=['x'],plot_ax=[0,1])
ifig.show()Plotting a functions value    {#org86172e6}Thedataargument can be replaced by a function that returns either a 1d
array for a line plot or a 2d array for a map plot.In 1d    {#org01d16db}The main difference to calling the plot on an array is that we do not need to
specify theplot_axparameter but we need to define a range and step size for
the slider, which is done by replacing the string argument in the parameter list
by a list containing name,minimum, maximum and step size.fc = 250
x = np.linspace(200, 800, 120)
def lor(y):
    return np.abs(1 / ((4*fc ** 2 - (x+y) ** 2 - 1j * x * 20) ** 2))

ifig = ifigure(1, 1)
ax = ifig.add_plot(axpos=[0, 0], x=x, data=lor, parameters=[["y",-100,100,1]])
ax.set_yscale("log")
ifig.show()Furthermore it is possible to do parametric plots using a function forxanddataarguments. Make sure that the variable names are the same in the
definition andadd_plotcall.import numpy as np
from manipylate import ifigure

def x(theta,npts):
    th = np.linspace(1,theta,npts)
    return th/50*np.cos(th)
def y(theta,npts):
    th = np.linspace(1,theta,npts)
    return -th/50*np.sin(th)

ifig = ifigure(1,1)
ax = ifig.add_plot(axpos=[0,0],x=x,data=y,parameters=[['theta',1,100,1],['npts',10,1000,1]],fix_lim=True)
ax.set_ylim(-2,2)
ax.set_xlim(-2,2)
ax.set_aspect('equal')
ifig.show()If one of the functionsx,ytakes more arguments than the other just add a**kwargsto its definition (e.g.def x(theta,npts,**kwargs)).In 2d    {#org898b6eb}Complex figure layout    {#org3f5c33c}Since the subplot layout creation is based onGridSpec, we can create more
complicated layouts. We use the handynumpy.s_to create the exact slices to
index theGridSpec.x = np.linspace(-5, 5, 200)
y = np.linspace(-3, 3, 100)
z = np.linspace(-4, 4, 80)
X, Y ,Z = np.meshgrid(x, y, z,indexing='ij')
data = np.sinc(X * Y**2 + Z)

ifig = ifigure(6, 4,figsize=(12,8))
ax=ifig.add_plot(axpos=np.s_[0,:], x=x, data=data, parameters=["y",'z'],plot_ax=0)
ax.set(xlabel='x')
ax=ifig.add_plot(axpos=np.s_[1,:2], x=y, data=data, parameters=["x","z"],plot_ax=1)
ax.set(xlabel='y')
ax=ifig.add_plot(axpos=np.s_[1,2:], x=z, data=data, parameters=["x","y"],plot_ax=2)
ax.set(xlabel='z')
ax=ifig.add_plot(axpos=np.s_[2::,:], x=[x,z], data=data, parameters=["y"],plot_ax=[0,2])
ax.set(xlabel='x',ylabel='y')
ifig.show()Naming and saving views    {#org6c3014c}Theifigureclass can be called with thefigurenameparameter which will
determine the base name and the extension for individually saved views. The full
filename is constructed from thefigurenameand the current slider names and
values.
Slider axes are removed during saving.TODOs    {#orgab035fc}TODOs    {#org5997233}Comment and document codeBugs    {#org662cf6f}Missing Features    {#org873105d}addconvert_parammethod to display physical parameter values (e.g. 0-1μm
instead of index values 1-51)3d plots ?choice for 2d plots (contour)