cdxcore.dynaplot#

Tools for dynamic plotting in Jupyer/IPython.

The aim of the toolkit is making it easier to develop animated visualization with matplotlib, for example during training with machine learing kits such as pyTorch.

It also makes the creation of subplots more streamlined.

This has been tested with Anaconda’s JupyterHub and %matplotlib inline.

Overview#

Animated Graphs, Simple#

The package now contains a lazy method to manage updates to graphs (animations). This is implemented as follows:

Here is an example of animated line plots using cdxcore.dynaplot.DynaFig.store():

%matplotlib inline
import numpy as np
import time
from cdxcore.dynaplot import figure, MODE

x  = np.linspace(0,1,100)
pm = 0.2

with figure(col_size=10) as fig:
    ax  = fig.add_subplot()
    ax2 = fig.add_subplot()
    ax2.sharey(ax)
    store = fig.store()    
    fig.render()

    for i in range(10):
        y = np.random.random(size=(100,))
        ax.set_title(f"Test {i}")
        ax2.set_title(f"Test {i}")

        store.remove() # delete all prviously stored elements
        store += ax.plot(x,y,":", label=f"data {i}")
        store += ax2.plot(x,y,"-",color="red", label=f"data {i}")
        store += ax2.fill_between( x, y-pm, y+pm, color="blue", alpha=0.2 )
        store += ax.legend()

        fig.render()
        time.sleep(0.5)
../../_images/dynaplot.gif

In above example we used the with context of a cdxcore.dynaplot.DynaFig figure. The point of using with where convenient is that it will call cdxcore.dynaplot.DynaFig.close() which will avoid duplicate copies of the figure in jupyter.

To do close the figure manually, call cdxcore.dynaplot.DynaFig.close() directy:

 %matplotlib inline
 import numpy as np
 import time
 from cdxcore.dynaplot import figure, MODE

 x  = np.linspace(0,1,100)
 pm = 0.2

 fig = figure(col_size=10)
 ax  = fig.add_subplot()
 ax2 = fig.add_subplot()
 ax2.sharey(ax)
 store = fig.store()    
 fig.render()

 for i in range(10):
     y = np.random.random(size=(100,))
     ax.set_title(f"Test {i}")
     ax2.set_title(f"Test {i}")

     store.remove() # delete all prviously stored elements
     store += ax.plot(x,y,":", label=f"data {i}")
     store += ax2.plot(x,y,"-",color="red", label=f"data {i}")
     store += ax2.fill_between( x, y-pm, y+pm, color="blue", alpha=0.2 )
     store += ax.legend()

     fig.render()
     time.sleep(0.5)

 fig.close() 

Here is an example with animated 3D plots, calling matplotlib.axes.Axes.remove() manually:

%matplotlib inline
import numpy as np
from cdxcore.dynaplot import figure
import math

x = np.linspace(0.,2.*math.pi,51)
y = x

with figure() as fig:
    ax1  = fig.add_subplot(projection='3d')
    ax2  = fig.add_subplot(projection='3d')
    ax1.set_xlim(0.,2.*math.pi)
    ax1.set_ylim(0.,2.*math.pi)
    ax1.set_zlim(-2,+2)
    ax1.set_title("Color specified")
    ax2.set_xlim(0.,2.*math.pi)
    ax2.set_ylim(0.,2.*math.pi)
    ax2.set_zlim(-2,+2)
    ax2.set_title("Color not specified")
    fig.render()
    r1 = None
    r2 = None
    import time
    for i in range(50):
        time.sleep(0.01)
        z = np.cos( float(i)/10.+x )+np.sin( float(i)/2.+y )
        if not r1 is None: r1.remove()
        if not r2 is None: r2.remove()
        r1 = ax1.scatter( x,y,z, color="blue" )
        r2 = ax2.scatter( 2.*math.pi-x,math.pi*(1.+np.sin( float(i)/2.+y )),z )
        fig.render()
../../_images/dynaplot3D.gif

The jupyter notebook contains a few more examples.

Simpler sub_plot#

The package lets you create sub plots without having to know the number of plots in advance. You have the following two main options when creating a new cdxcore.dynaplot.figure():

  • Define as usual figsize, and specify the number of columns. In this case the figure will arrange plots you add with cdxcore.dynaplot.DynaFig.add_subplot() iteratively with at most columns plots per row. add_subplot() will not need any additional positional arguments.

  • Instead, you can specify col_size, row_size, and columns: the first two define the size per subplot. Like before you then add your sub plots using cdxcore.dynaplot.DynaFig.add_subplot() without any additional positioning arguments.

    Assuming you add N subplots, then the overall figsize will be (col_size* (N%col_num),  row_size (N//col_num)).

When adding plots with cdxcore.dynaplot.DynaFig.add_subplot() you can make it skip to the first column in the next row, by calling cdxcore.dynaplot.DynaFig.next_row().

The example also shows that we can specify titles for subplots and figures easily:

%matplotlib inline
import numpy as np
import time
from cdxcore.dynaplot import figure

x = np.linspace(0,1,100)

with figure(title="Multi Graph", fig_size=(10,6), columns=4) as fig:
    lines  = []
    ref_ax = None
    for k in range(9):
        ax = fig.add_subplot()
        ax.set_title("Test %ld" % k)
        y = np.random.random(size=(100,1))
        l = ax.plot(x,y,":",color="red", label="data")
        lines.append(l)
        ax.legend()

        if not ref_ax is None:
            ax.sharey(ref_ax)
            ax.sharex(ref_ax)
        else:
            ref_ax = ax
    fig.render()

    for i in range(5):
        time.sleep(0.2)
        for l in lines:
            y = np.random.random(size=(100,1))
            l[0].set_ydata( y )
        fig.render()
../../_images/multi.gif

Grid Spec#

Another method to place plots is by explicitly positioning them using a matplotlib.gridspec.GridSpec. In line with the paradigm of delayed creation, use cdxcore.dynaplot.DynaFig.add_gridspec() to generate a deferred grid spec.

Example:

%matplotlib inline
from cdxcore.dynaplot import figure
import numpy as np

x = np.linspace(-2.,+2,21)

with figure(tight=False) as fig:
    ax = fig.add_subplot()
    ax.plot( x, np.sin(x) )
    fig.render()

    ax = fig.add_axes( (0.5,0.5,0.3,0.3), "axes" )
    ax.plot( x, np.cos(x) )
../../_images/gridspec.gif

Color Management#

Use cdxcore.dynaplot.color_css4(), cdxcore.dynaplot.color_base(), cdxcore.dynaplot.color_tableau(), cdxcore.dynaplot.color_xkcd() to return an i th element of the respective matplotlib color table. This simplifies using consistent colors accross different plots or when re-creating plots during an animation.

Example of using the same colors by order in two plots:

%matplotlib inline
import numpy as np
import math
import time
from cdxcore.dynaplot import figure, color_base   # 'figure' is an alias for DynaFig

x = np.linspace(0.,2.*math.pi,51)

with figure(fig_size=(14,6)) as fig:
    ax = fig.add_subplot("Sin")
    store = fig.store()
    # draw 10 lines in the first sub plot, and add a legend
    for i in range(10):
        y = np.sin(x/(i+1))
        ax.plot( x, y, color=color_base(i), label=f"f(x/{i+1})" )
    ax.legend(loc="lower right")

    # draw 10 lines in the second sub plot.
    # use the same colors for the same scaling of 'x'
    ax = fig.add_subplot("Cos")

    for i in range(10):
        z = np.cos(x/(i+1))
        store += ax.plot( x, z, color=color_base(i) )
    fig.render()

    # animiate, again with the same colors
    for p in np.linspace(0.,4.,11,endpoint=False):
        time.sleep(0.1)
        store.clear() # alias for 'remove'
        for i in range(10):
            z = np.cos((x+p)/(i+1))
            store += ax.plot( x, z, color=color_base(i) )
        fig.render() 
../../_images/colors.gif

Here is a view of the first 20 colors of the four supported maps, computed with:

%matplotlib inline
from cdxcore.dynaplot import figure, color_names, color
import numpy as np
x = np.linspace(-2.*np.pi,+2*np.pi,101)
N = 20
with figure(f"Color tables up to #{N}", figsize=(20,15), columns=2) as fig:
    for color_name in color_names:
        ax  = fig.add_subplot(color_name)
        for i in range(N):
            r =1./(i+1)
            ax.plot( x, np.sin(x*r), color
../../_images/colormap.gif

The classes cdxcore.dynaplot.colors_css4, cdxcore.dynaplot.colors_base, cdxcore.dynaplot.colors_tableau, cdxcore.dynaplot.colors_xkcd are generators for the same colors.

Known Issues#

Some users reported that the package does not update figures consistently in some versions of Jupyter, in particular with VSCode. In this case, please try changing the draw_mode parameter when calling cdxcore.dynaplot.figure().

Import#

from cdxcore.dynaplot import figure

Documentation#

Module Attributes

color_names

List of available colors names.

Functions

color(i[, table])

Returns a color with a given index to allow consistent colouring.

color_base(i)

Returns the i'th base color:

color_css4(i)

Returns the i'th css4 color:

color_tableau(i)

Returns the i'th tableau color:

color_xkcd(i)

Returns the i th xkcd color.

colors([table])

Returns a generator for the colors of the specified table.

colors_base()

Iterator for "base" matplotlib colors:

colors_css4()

Iterator for "css4" matplotlib colors:

colors_tableau()

Iterator for ""tableau"" matplotlib colors:"

colors_xkcd()

Iterator for xkcd matplotlib colors

figure([title, row_size, col_size, ...])

Creates a dynamic figure of type cdxcore.dynaplot.DynaFig.

focus_line(left, right, N, *[, ...])

Returns a line from left to right which has more points in focus.

m_o_m(*args[, pos_floor, buf, min_dx])

Computes cdxcore.dynaplot.min_o_min() and cdxcore.dynaplot.max_o_max() for args to obtain their minimum of minima and maximum of maxima.

max_o_max(*args[, default])

Computes maximum of maxima.

min_o_min(*args[, default])

Computes minimum of minima.

store()

Creates a cdxcore.dynaplot.FigStore which can be used to dynamically update a figure.

Classes

DynaAx(*, fig_id, fig_list, row, col, ...)

Deferred wrapper around a matplotlib.axes.Axes objects returned by cdxcore.dynaplot.DynaFig.add_subplot() or similar.

DynaFig([title, row_size, col_size, ...])

Deferred wrapper around matplotlib.figure.Figure.

FigStore()

Utility class to manage dynamic content by removing old graphical elements (instead of using element-specifc update).

MODE()

How to draw graphs.

class cdxcore.dynaplot.DynaAx(*, fig_id, fig_list, row, col, spec_pos, rect, title, projection, kwargs)[source]#

Bases: _DynaDeferred

Deferred wrapper around a matplotlib.axes.Axes objects returned by cdxcore.dynaplot.DynaFig.add_subplot() or similar.

You should not need to know that this object is not actually a matplotlib.axes.Axes. If you receive error messages which you do not understand, please contact the authors of this module.

auto_limits(low_quantile, high_quantile, min_length=10, lookback=None)[source]#

Add automatic limits using cdxcore.dynalimits.AutoLimits.

Parameters:
low_quantilefloat

Lower quantile to use for computing a ‘min’ y value. Set to 0 to use the actual ‘min’.

high_quantilefloat

Higher quantile to use for computing a ‘min’ y value. Set to 1 to use the actual ‘max’.

min_lengthint, optional

Minimum length data must have to use numpy.quantile(). If less data is presented, use min/max, respectively. Default is 10.

lookbackint

How many steps to lookback for any calculation. None to use all steps.

plot(*args, scalex=True, scaley=True, data=None, **kwargs)[source]#

Wrapper around matplotlib.axes.Axes.plot().

This function wrapper does not support the data interface of matplotlib.axes.Axes.plot().

If automatic limits are not used, this is a wrapper with deferred pass-through. If automatic limits are used, then this function will update the underlying automated limits accordingly.

Parameters:
args, scalex, scaley, data, kwargs

See matplotlib.axes.plot().

Returns:
plotDeferred

This function will return a wrapper around an actual axis which is used to defer actioning any subsequent calls to until cdxcore.dynaplot.DynaFig.render() is called.

You should not need to consider this. If you encounter problems in usability please contact the authors.

remove()[source]#

Equivalent of matplotlib.axes.Axes.remove(): removes this axis from the underlying figure. Note that this will not trigger a removal from the actual visualization until cdxcore.dynaplot.DynaFig.render() is called.

set_auto_lims(*args, **kwargs)[source]#

Apply cdxcore.dynalimits.AutoLimits for this axis. See cdxcore.dynalimits.AutoLimits.set_lims for parameter description.

class cdxcore.dynaplot.DynaFig(title=None, *, row_size=5, col_size=4, fig_size=None, columns=5, tight=True, draw_mode=1, **fig_kwargs)[source]#

Bases: _DynaDeferred

Deferred wrapper around matplotlib.figure.Figure.

Provides a simple cdxcore.dynaplot.DynaFig.add_subplot() without the need to pre-specify axes positions as is common for matplotlib.

Construct elements of this class with cdxcore.dynaplot.figure().

add_axes(rect, title=None, *, projection=None, **kwargs)[source]#

Add a freely placed sub plot.

Like matplotlib.figure.Figure.add_axes() this function allows placing a plot at a given position within a figure using rect. This plot may overlay previously generated plots.

This function can be called after the cdxcore.dynaplot.DynaFig.close() was called.

Note that using this function with a tight figure will result in a UserWarning. Use tight=False when constructing your figure to avoid this warning.

Parameters:
recttuple (left, bottom, width, height)

The dimensions (left, bottom, width, height) of the new plot. All quantities are in fractions of figure width and height.

titlestr | None, default None

Title for the plot, or None for no plot.

projectionstr | None, default None

What projection to use. The default None matches the default choice for matplotlib.figure.Figure.add_axes()

args, kwargs

keyword arguments to be passed to matplotlib.figure.Figure.add_axes().

Returns:
Axiscdxcore.dynaplot.DynaAx

A wrapper around an matplotlib axis.

add_gridspec(ncols=1, nrows=1, **kwargs)[source]#

Wrapper for matplotlib.figure.Figure.add_gridspec(), returning a defered GridSpec.

add_plot(title=None, *, new_row=None, spec_pos=None, projection=None, **kwargs)#

Adds a subplot.

Compared to matplotlib.figure.Figure.add_subplot() this function does not require the tedious positioning arguments which are required when using matplotlib.figure.Figure.add_subplot(). This function also allows to directly specify a plot title.

Implementation Comment:

This function returns a wrapper which defers the creation of the actual sub plot until cdxcore.dynaplot.DynaFig.render() or cdxcore.dynaplot.DynaFig.close() is called.

Thus this function cannot be called after cdxcore.dynaplot.DynaFig.render() was called as then the geometry of the plots is set. Use cdxcore.dynaplot.DynaFig.add_axes() to draw plots at any time.

Parameters:
titlestr | None, default None

Optional title for the plot.

new_rowbool | None, default None

Whether to force a new row and place this plot in the first column. Default is False.

spec_posgrid spec | None, default None

Grid spec position from cdxcore.dynaplot.DynaFig.add_gridspec(), or None.

projectionstr | None, default None

What projection to use. The default None matches the default choice for matplotlib.figure.Figure.add_subplot().

kwargsdict

Other arguments to be passed to matplotlib’s matplotlib.figure.Figure.add_subplot().

Returns:
Axiscdxcore.dynaplot.DynaAx

A wrapper around an matplotlib axis.

add_subplot(title=None, *, new_row=None, spec_pos=None, projection=None, **kwargs)[source]#

Adds a subplot.

Compared to matplotlib.figure.Figure.add_subplot() this function does not require the tedious positioning arguments which are required when using matplotlib.figure.Figure.add_subplot(). This function also allows to directly specify a plot title.

Implementation Comment:

This function returns a wrapper which defers the creation of the actual sub plot until cdxcore.dynaplot.DynaFig.render() or cdxcore.dynaplot.DynaFig.close() is called.

Thus this function cannot be called after cdxcore.dynaplot.DynaFig.render() was called as then the geometry of the plots is set. Use cdxcore.dynaplot.DynaFig.add_axes() to draw plots at any time.

Parameters:
titlestr | None, default None

Optional title for the plot.

new_rowbool | None, default None

Whether to force a new row and place this plot in the first column. Default is False.

spec_posgrid spec | None, default None

Grid spec position from cdxcore.dynaplot.DynaFig.add_gridspec(), or None.

projectionstr | None, default None

What projection to use. The default None matches the default choice for matplotlib.figure.Figure.add_subplot().

kwargsdict

Other arguments to be passed to matplotlib’s matplotlib.figure.Figure.add_subplot().

Returns:
Axiscdxcore.dynaplot.DynaAx

A wrapper around an matplotlib axis.

add_subplots(*titles, sharex=None, sharey=None, **kwargs)[source]#

Generate a number of sub-plots in one function call.

Use strings to generate subplots with such titles, \n for a new row, and integers to mass-generate a number of plots.

Example:

from cdxcore.dynaplot import figure

with figure("Test", col_size=4, row_size=4) as fig:
    axA1, axA2, axB1, axB2 = fig.add_subplots("A1", "A2", "\n", "B1", "B2")
Parameters:
titleslist

A list if strings, integers, \n and/or None’s: a string generates a sub-plot with that title; an int generates as many subplots, and \n starts a new row. None skips the entry. This is useful when creating conditional lists of sub-plots, e.g.:

from cdxcore.dynaplot import figure

with figure("Test", col_size=4, row_size=4) as fig:
    axA1, axA2, axB1, axB2 = fig.add_subplots("A1", "A2" if show2 else None, "\n", "B1", "B2" if show2 else None)
    if show2: assert not axA2 is None and not axB2 is None
    if not show2: assert axA2 is None and axB2 is None

None will not create an empty slot; it will simply not generate the plot. To generate empty slots or span plots over several columsn or rows, use cdxcore.dynaplot.DynaFig.add_subplot() with grid_spec.

Note that the number of columns is usually limited by the columns parameter when cdxcore.dynaplot.figure() is called. You can set columns to None to freely generate blocks of graphs.

sharexDynaAx | bool | None, default None

Can be used to share the x axis either with a specific axis, or with the first axis generated by this function call (True). If False or None this keyword has no effect.

shareyDynaAx | bool | None, default None

Can be used to share the y axis either with a specific axis, or with the first axis generated by this function call (True). If False or None this keyword has no effect.

Returns:
Sub-plots: tuple

A tuple of sub-plots, one for each title.

property axes: list[DynaAx]#

List of axes. Until cdxcore.dynaplot.DynaFig.render() is called, these are cdxcore.dynaplot.DynaAx objects; afterwards, these are matplotlib.axes.Axes objects.

close(render=True, clear=False)[source]#

Closes the figure.

Call this to avoid a duplicate in jupyter output cells. By dault this function will call cdxcore.dynaplot.DynaFig.render() to draw the figure, and then close it.

Parameters:
renderbool, default True

If True, the default, this function will call cdxcore.dynaplot.DynaFig.render() and therefore renders the figure before closing the figure.

clearbool, default False

If True, all axes will be cleared. This is experimental. The default is False.

delaxes(ax, *, render=False)[source]#

Equivalent of matplotlib.figure.Figure.delaxes(), but this function can also take a list.

property fig: Figure | None#

Returns the figure or None if it was not yet rendered.

property hdisplay#

Returns the IPython.display.DisplayHandle for the current display, if MODE.HDISPLAY was used for draw_mode when the figure was constructed, and if the figure was rendered yet. Otherwise returns None.

property is_closed: bool#

Returrns whether the figure was closed

next_row()[source]#

Skip to next row.

The next plot generated by cdxcore.dynaplot.DynaFig.add_subplot() will appears in the first column of the next row.

remove_all_axes(*, render=False)[source]#

Calls cdxcore.dynaplot.DynaAx.remove() for all cdxcore.dynaplot.DynaFig.axes

render(draw=True)[source]#

Draw all axes.

If this function does not display the plots you generated, review the draw_mode parameter provided to cdxcore.dynaplot.figure() or cdxcore.dynaplot.DynaFig(), respectively,

Once called, no further plots can be added, but the plots can be updated in place.

Parameters:
drawbool, default True

If False, then the figure is created, but not drawn. You usually use False when planning to use cdxcore.dynaplot.DynaFig.savefig() or cdxcore.dynaplot.DynaFig.to_bytes().

savefig(fname, silent_close=True, **kwargs)[source]#

Saves the figure to a file.

Wrapper around matplotlib.pyplot.savefig(). Essentially, this function writes the figure to a file rather than displaying itl.

Parameters:
fnamestr

filename or file-like object

silent_closebool, default True

If True (the default), call cdxcore.dynaplot.DynaFig.close() once the figure was saved to disk. Unless the figure was drawn before, this means that the figure will not be displayed in jupyter, and subsequent activity is blocked.

kwargsdict

These arguments will be passed to matplotlib.pyplot.savefig().

static store()[source]#

Create a cdxcore.dynaplot.FigStore. Such a store allows managing graphical elements (artists) dynamically. See the examples in the introduction.

to_bytes(silent_close=True)[source]#

Convert figure to a byte stream.

This stream can be used to generate a IPython image using:

from IPython.display import Image, display
bytes = fig.to_bytes()
image = Image(data=byes)
display(image)
Parameters:
silent_closebool, default True

If True, call cdxcore.dynaplot.DynaFig.close() after this genersating the byte streanm. Unless the figure was drawn before, this means that the figure will not be displayed in jupyter, and subsequent activity is blocked.

Returns:
imagebytes

Buyte stream of the image.

class cdxcore.dynaplot.FigStore[source]#

Bases: object

Utility class to manage dynamic content by removing old graphical elements (instead of using element-specifc update).

Allows implementing a fairly cheap dynamic pattern:

from cdxbasics.dynaplot import figure
import time as time

fig = figure()
ax = fig.add_subplot()
store = fig.store()

x = np.linspace(-2.,+2,21)

for i in range(10):
    store.remove()
    store += ax.plot( x, np.sin(x+float(i)) )
    fig.render()
    time.sleep(1)

fig.close()

As in the example above, the most convenient way to create a FigStore object is to call cdxcore.dynaplot.DynaFig.store() on your figure.

The above pattern is not speed or memory optimal. It is more efficient to modify the artist directly. While true, for most applications a somewhat rude cancel+replace is simpler. FigStore was introduced to facilitiate that.

add(element)[source]#

Add an element to the store. The same operation is available using +=.

Parameters:
elementmatplotlib.artist.Artist

Graphical matplot element derived from matplotlib.artist.Artist such as matplotlib.lines.Line2D; or a Collection of the above; or None.

Returns:
selfFigstore

Returns self. This way compound statements a.add(x).add(y).add(z) work.

clear()#

Removes all elements by calling their matplotlib.artist.Artist.remove() function. Handles any Collection of such elements is as well.

remove()[source]#

Removes all elements by calling their matplotlib.artist.Artist.remove() function. Handles any Collection of such elements is as well.

class cdxcore.dynaplot.MODE[source]#

Bases: object

How to draw graphs. The best mode depends on the output IPython implementation.

CANVAS_DRAW = 4#

Call matplotlib.pyplot.figure.canvas.draw_idle

CANVAS_IDLE = 2#

Call matplotlib.pyplot.figure.canvas.draw_idle

DEFAULT = 1#

Setting which works for Jupyter lab and VSCode with %matplotlib inline as far as we can tell.

HDISPLAY = 1#

Call IPython.display.display().

PLT_SHOW = 128#

Call matplotlib.pyplot.show().

cdxcore.dynaplot.color(i, table='css4')[source]#

Returns a color with a given index to allow consistent colouring.

Parameters:
iint

Integer number. Colors will be rotated.

tablestr, default css4

Which color table from matplotlib to use: “css4”, “base”, “tableau” or “xkcd”. Default is "css4".

Returns:
Color codestr
cdxcore.dynaplot.color_base(i)[source]#

Returns the i’th base color:

https://matplotlib.org/stable/_images/sphx_glr_named_colors_001_2_00x.png
cdxcore.dynaplot.color_css4(i)[source]#

Returns the i’th css4 color:

https://matplotlib.org/stable/_images/sphx_glr_named_colors_003_2_00x.png
cdxcore.dynaplot.color_names = ['css4', 'base', 'tableau', 'xkcd']#

List of available colors names.

cdxcore.dynaplot.color_tableau(i)[source]#

Returns the i’th tableau color:

https://matplotlib.org/stable/_images/sphx_glr_named_colors_002_2_00x.png
cdxcore.dynaplot.color_xkcd(i)[source]#

Returns the i th xkcd color.

cdxcore.dynaplot.colors(table='css4')[source]#

Returns a generator for the colors of the specified table.

Parameters:
tablestr, optional

Which color table from matplotlib.colors to use: "css4", "base", "tableau", or "xkcd". Default is "css4".

Returns:
Generator for colors.

Use next() or iterate.

cdxcore.dynaplot.colors_base()[source]#

Iterator for “base” matplotlib colors:

https://matplotlib.org/stable/_images/sphx_glr_named_colors_001_2_00x.png
cdxcore.dynaplot.colors_css4()[source]#

Iterator for “css4” matplotlib colors:

https://matplotlib.org/stable/_images/sphx_glr_named_colors_003_2_00x.png
cdxcore.dynaplot.colors_tableau()[source]#

Iterator for “”tableau”” matplotlib colors:”

https://matplotlib.org/stable/_images/sphx_glr_named_colors_002_2_00x.png
cdxcore.dynaplot.colors_xkcd()[source]#

Iterator for xkcd matplotlib colors

cdxcore.dynaplot.figure(title=None, *, row_size=5, col_size=4, fig_size=None, columns=5, tight=True, draw_mode=1, add_plots=None, **fig_kwargs)[source]#

Creates a dynamic figure of type cdxcore.dynaplot.DynaFig.

By default the fig_size of the underlying matplotlib.figure.Figure will be derived from the number of plots vs cols, row_size and col_size as (col_size* (N%col_num),  row_size (N//col_num)).

If fig_size is specified then row_size and col_size are ignored.

Once the figure is constructed:

  1. Use cdxcore.dynaplot.DynaFig.add_subplot() to add plots (without the cumbersome need to know the number of plots in advance).

  2. Call cdxcore.dynaplot.DynaFig.render() to place those plots.

  3. Call cdxcore.dynaplot.DynaFig.close() to close the figure and avoid duplicate copies in Jupyter.

    A convenient wrapper is to use with to ensure close() gets called.

Examples:

Simply use cdxcore.dynaplot.DynaFig.add_subplot() without the matplotlib need to pre-specify axes positions:

from cdxcore.dynaplot import figure    
with dynaplot.figure("Two plots") as fig:
    ax = fig.add_subplot("1")
    ax.plot(x,y)
    ax = fig.add_subplot("2")
    ax.plot(x,y)

Here is an example using matplotlib.figure.Figure.add_gridspec():

from cdxcore.dynaplot import figure    
with dynaplot.figure() as fig:
    gs  = fig.add_gridspec(2,2)
    ax = fig.add_subplot( gs[:,0] )
    ax.plot(x,y)
    ax = fig.add_subplot( gs[:,1] )
    ax.plot(x,y)

Important Functions:

The returned cdxcore.dynaplot.DynaFig will defer all other function calls to the figure object until cdxcore.dynaplot.DynaFig.render() or cdxcore.dynaplot.DynaFig.close() are called. Whenever you use with at the end of the context window cdxcore.dynaplot.DynaFig.close() will be called for you.

The following direct members are important for using the framework:

Parameters:
titlestr, default None

An optional title which will be passed to matplotlib.pyplot.suptitle().

fig_sizetuple[int] | None, default None

By default the fig_size of the underlying matplotlib.pyplot.figure() will be derived from the number of plots vs cols, row_size and col_size as (col_size* (N%col_num),  row_size (N//col_num)).

If fig_size is specified then row_size and col_size are ignored.

row_sizeint, default 5

Size for a row for matplot lib. Default is 5. This is ignored if fig_size is specified.

col_sizeint, default 4

Size for a column for matplot lib. Default is 4. This is ignored if fig_size is specified.

columnsint, default 5

How many columns to use when cdxcore.dynaplot.DynaFig.add_subplot() is used. If omitted then the default is 5.

tightbool, default True

Short cut for matplotlib.figure.Figure.set_tight_layout(). The default is True.

Note that when tight is True and cdxcore.dynaplot.DynaFig.add_axes() is called a UserWarning is generated. Turn tight off to avoid this.

draw_modeint, default MODE.DEFAULT

A combination of cdxcore.dynaplot.MODE flags on how to draw plots once they were rendered. The required function call differs by IPython platform. The default, cdxcore.dynaplot.MODE.DEFAULT draws well on Jupyter notebooks and in VSCode if %matplotlin inline or widget is used. The latter requires the packages ipympl and ipywidgets.

Use the function cdxcore.dynaplot.dynamic_backend() to set the widget mode if possible.

fig_kwargs

Other matplotlib parameters for matplotlib.pyplot.figure() to create the figure.

Returns:
figure: cdxcore.dynaplot.DynaFig

A dynamic figure.

cdxcore.dynaplot.focus_line(left, right, N, *, concentration=0.9, power=2, focus=None, focus_on_grid=False, eps=1e-08, dtype=None)[source]#

Returns a line from left to right which has more points in focus.

This function computes a number of points on a line between left and right such that points around focus are more dense. The concentration parameter allowws to blend between linear and focused points.

The function is an appropriately scaled and shifted version of $x mapsto x (1-c) + c, x, mathrm{abs}(x)^{p-1}$ where $c$ is concentration.

Parameters:
left, rightfloat, float

Left hand and right hand points.

Nint,

Number of points; must be at least 3.

concentrationfloat, default 0.9

How much concentration: maximum is 1 while 0 give a linear distibution of points.

focusfloat | None, default None

Focus point. If not provided, the mid-point is used.

focus_on_gridbool, default None

Whether to place focus on the grid.

dtypetype, default None

Numpy dtype.

Returns:
pointsnumpy.ndarray

Numpy vector

cdxcore.dynaplot.m_o_m(*args, pos_floor=None, buf=0.05, min_dx=0.01)[source]#

Computes cdxcore.dynaplot.min_o_min() and cdxcore.dynaplot.max_o_max() for args to obtain their minimum of minima and maximum of maxima.

This function is useful to compute arguments for matplotlib.axes.Axes.set_xlim() or matplotlib.axes.Axes.set_ylim().

If pos_floor is None then the function returns:

dx = max( min_dx, max_ - min_ )
return min_ - dx*buf, max_dx*buf

If pos_floor is not None, then the function floors min_ - dx*buf at pos_floor.

Usage:

from cdxcore.dynaplot import figure, m_o_m
import numpy as np

x = np.random.normal(size=(10,))
y = np.random.normal(size=(8,2))
z = [ np.random.normal(size=(3,2)), 0.1, None ]

with figure() as fig:
    ax = fig.add_subplot()
    ax.plot( x )
    ax.plot( y )
    ax.plot( z[1] )
    ax.set_ylim( *m_o_m(x,y,z, min_dx=0.01) )                
Returns:
min, maxfloat | None, float | None

The adjusted minimum and maximum values as discussed above. The function returns None, None if args does not contain any numbers. Such result can be passed directly to matplotlib.axes.Axes.set_xlim() or matplotlib.axes.Axes.set_ylim() as both accept None as default values.

cdxcore.dynaplot.max_o_max(*args, default=None)[source]#

Computes maximum of maxima.

This function iterates through all arguments, and takes the maximum of all maxima. Parmaters can be numbers, numpy.ndarray arrays or lists of the former.

This function is useful to compute arguments for matplotlib.axes.Axes.set_xlim() or matplotlib.axes.Axes.set_ylim().

Parameters:
argslist[int | float | np.ndarray | None | list]

Numbers, numpy.ndarray arrays or lists of the former. Elements which are None are skipped.

defaultfloat | None, default None

Default value if args was empty.

Returns:
maxfloat | None

The maximum of all maxima, or default if no elements were found.

cdxcore.dynaplot.min_o_min(*args, default=None)[source]#

Computes minimum of minima.

This function iterates through all arguments, and takes the minimum of all minima. Parmaters can be numbers, numpy.ndarray arrays or lists of the former.

This function is useful when calling matplotlib.axes.Axes.set_xlim() or matplotlib.axes.Axes.set_ylim().

Parameters:
argslist[int | float | np.ndarray | None | list]

Numbers, numpy.ndarray arrays or lists of the former. Elements which are None are skipped.

defaultfloat | None, default None

Default value if args was empty.

Returns:
minfloat | None

The minimum of all minima, or default if no elements were found.

cdxcore.dynaplot.store()[source]#

Creates a cdxcore.dynaplot.FigStore which can be used to dynamically update a figure.