Plotting template

Usage

Plot objects that inherit from the template plot classes have the following properties.

  • Fast plotting by use of matplotlib.canvas.blit.

  • Redrawing past iterations of the figure by storing all changes in history.

  • Keyboard navigation for iteration selection.

  • Plot object information by picking.

When the focus is on the figure, indicated by a green circle in the bottom right corner, the user can navigate through the history of the figure by the commands below.

key

function

h

show help

i

show all iterations

enter or right

go to next iteration, enter iteration number

backspace or left

go to previous iteration

n

go to newest iteration

0-9

input iteration number

If the focus is lost, it can be regained by calling template.focus on the plot object.

Default values for plot properties such as colors and linewidths are saved in a plot.ini file. Any plot property can be overwritten by supplying the override value as a keyword argument during object initialization or a custom plot.ini file in the working directory.

Development

class qsurface.plot.PlotParams(blocking_wait=- 1, blocking_pick_radius=10, scale_figure_length=10, scale_figure_height=10, scale_font_primary=12, scale_font_secondary=10, scale_3d_layer=8, color_background=1, 1, 1, 0, color_edge=0.8, 0.8, 0.8, 1, color_qubit_edge=0.7, 0.7, 0.7, 1, color_qubit_face=0.95, 0.95, 0.95, 1, color_x_primary=0.9, 0.3, 0.3, 1, color_z_primary=0.5, 0.5, 0.9, 1, color_y_primary=0.9, 0.9, 0.5, 1, color_x_secondary=0.9, 0.7, 0.3, 1, color_z_secondary=0.3, 0.9, 0.3, 1, color_y_secondary=0.9, 0.9, 0.5, 1, color_x_tertiary=0.5, 0.1, 0.1, 1, color_z_tertiary=0.1, 0.1, 0.5, 1, color_y_tertiary=0.9, 0.9, 0.5, 1, alpha_primary=0.35, alpha_secondary=0.5, line_width_primary=1.5, line_width_secondary=3, line_style_primary='solid', line_style_secondary='dashed', line_style_tertiary='dotted', patch_circle_2d=0.1, patch_rectangle_2d=0.1, patch_circle_3d=30, patch_rectangle_3d=30, axis_main=0.075, 0.1, 0.7, 0.85, axis_main_non_interact=0.0, 0.05, 0.8, 0.9, axis_block=0.96, 0.01, 0.03, 0.03, axis_nextbutton=0.85, 0.05, 0.125, 0.05, axis_prevbutton=0.85, 0.12, 0.125, 0.05, axis_legend=0.85, 0.5, 0.125, 0.3, axis_text=0.05, 0.025, 0.7, 0.05, axis_radio=0.85, 0.19, 0.125, 0.125, font_default_size=12, font_title_size=16, font_button_size=12, axis3d_pane_color=1, 1, 1, 0, axis3d_line_color=0, 0, 0, 0.1, axis3d_grid_line_style='dotted', axis3d_grid_line_alpha=0.2)

Parameters for the plotting template classes.

Contains all parameters used in inherited objects of Template2D and Template3D. The dataclass is initialized with many default values for an optimal plotting experience. But if any parameters should be changed, the user can call the class to create its own instance of plotting paramters, where the altered paramters are supplied as keyword arguments. The instance can be supplied to the plotting class via the plot_params keyword argument.

Examples

See the below example where the background color of the figure is changed to black. Note that we have to inherit from the Template2D class.

>>> class Plotting(Template2D):
...     pass
>>> custom_params = PlotParams(color_background = (0,0,0,1))
>>> plot_with_custom_params = Plotting(plot_params=custom_params)
load_params(param_dict)

Loads extra plotting parameters.

Additional parameters can be loaded to the dataclass via this method. The additional parameters must be a dictionary where values are stored to the dataclass with the key as attribute name. If the value is a string that equals to any already defined dataclass attribute, the value at the existing attribute is used for the new parameter. See examples.

Parameters

params_dict – Dictionary or dictionary of dictionaries of additional parameters.

Examples

New parameters can be added to the dataclass. Values of dataclass attributes are used if present.

>>> params = PlotParams()
>>> params.alpha_primary
0.35
>>> params.load_params({
...     "new_attr" : "some_value",
...     "use_existing" : "alpha_primary",
... })
>>> params.new_attr
some_value
>>> params.use_existing
0.35

Nested dictionaries will also load existing attribute values.

>>> params.load_params({
...     "category": {
...         "new_attr" : "some_value",
...         "use_existing" : "alpha_primary",
...     }
... })
>>> params.category
{"new_attr" : "some_value", "use_existing" : 0.35}
class qsurface.plot.BlockingKeyInput(*args, **kwargs)

Blocking class to receive key presses.

See also

None

Inherited blocking class.

class qsurface.plot.Template2D(plot_params=None, projection=None, **kwargs)

Template 2D plot object with history navigation.

This template plot object which can either be an interactive figure using the Tkinter backend, or shows each plotting iteration as a separate figure for the IPython inline backend. The interactive figure has the following features.

  • Fast plotting by use of “blitting”.

  • Redrawing past iterations of the figure by storing all changes in history.

  • Keyboard navigation for iteration selection.

  • Plot object information by picking.

To instance this class, one must inherit the current class. The existing objects can then be altered by updating their plot properties by new_properties(), where the changed properties must be a dictionary with keywords and values corresponding tho the respective matplotlib object. Every change in plot property is stored in self.history_dict. This allows to undo or redo changes by simply applying the saved changed properties in the dictionary. Fast plotting is enabled by not drawing the figure after every queued change. Instead, each object is draw in the canvas individually after a property change and a series of changes is drawn to the figure when a new plot iteration is requested via new_iter(). This is performed by blitting the canvas.

Keyboard navigation and picking is enabled by blocking the code via a custom BlockingKeyInput class. While the code is blocked, inputs are caught by the blocking class and processed for history navigation or picking navigation. Moving the iteration past the available history allows for the code to continue. The keyboard input is parsed by focus().

Default values for plot properties such as colors and linewidths loaded from PlotParams. A custom parameter dataclass can be supplied via the plot_params keyword argument.

Parameters

plot_params (Optional[PlotParams]) – Plotting parameters dataclass containing colors, styles and others.

figure

Main figure.

Type

matplotlib.figure.Figure

interactive

Enables GUI elements and interactive plotting.

Type

bool

main_ax

Main axis of the figure.

Type

matplotlib.axes.Axes

history_dict

For each iteration, for every plot object with changed properties, the properties are stored as a nested dictionary. See the example below.

>>> history_dict = {
        0: {
            "<Line2D object>": {
                "color": "k",
            },
            "<Circle object>": {
                "linestyle": "-",
            }
        }
        1: {
            "<Line2D object>": {
                "color": "r",
            },
            "<Circle object>": {
                "linestyle": ":",
            }
        }
    }
Type

collections.defaultdict

history_iters

Total number of iterations in history.

Type

int

history_iter

The current plot iteration.

Type

int

history_iter_names

List of length history_iters containing a title for each iteration.

Type

list of str

history_at_newest

Whether the current plot iteration is the latest or newest.

Type

bool

history_event_iter

String catching the keyboard input for the wanted plot iteration.

Type

str

future_dict

Same as history_dict but for changes for future iterations.

Type

collections.defaultdict

temporary_changes

Temporary changes for plot properties, requested by temporary_properties(), which are immediately drawn to the figure. These properties can be overwritten or undone before a new iteration is requested via new_iter(). When a new iteration is requested, we need to find the difference in properties of the queued changes with the current iteration and save all differences to self.history_dict.

Type

collections.defaultdict

temporary_saved

Temporary changes are saved to the current iteration iter. Thus when a new iteration iter + 1 is requested, we need to recalculate the differences of the properties in iter-1 and the current iteration with the temporary changes. The previous property values when temporary changes are requested by temporary_properties() are saved to self.temporary_saved and used as the property changes for iter-1.

Type

collections.defaultdict

interact_axes

All iteractive elements should have their own axis saved in self.interact_axes. The axis.active attribute must be added to define when the axis is shown. If the focus on the figure is lost, all axes in self.interact_axes are hidden by setting axis.active=False.

Type

dict of matplotlib.axes.Axes

interact_bodies

All interactive elements such as buttons, radiobuttons, sliders, should be saved to this dictionary with the same key as their axes in self.interact_axes.

Type

dict

Notes

Note all backends support blitting. It does not work with the OSX backend (but does work with other GUI backends on mac).

Examples

A matplotlib.lines.Line2D object is initiated with color="k" and ls="-". We request that the color of the object is red in a new plot iteration.

>>> import matplotlib.pyplot as plt
... class Example(Template2D):
...     def __init__(self, *args, **kwargs):
...         super().__init__(*args, **kwargs)
...         self.line = plt.plot(0, 0, color="k", ls="-")[0]    # Line located at [0] after plot
>>> fig = Example()
>>> fig.new_properties(fig.line, {"color": "r})
>>> fig.new_iter()
>>> fig.history_dict
{
    0: {"<Line2D>": {"color": "k"}},
    1: {"<Line2D>": {"color": "r"}},
}

The attribute self.history_dict thus only contain changes to plot properties. If we request another iteration but change the linestyle to “:”, the initial linestyle will be saved to iteration 1.

>>> fig.new_properties(fig.line, {"ls": ":"})
>>> fig.new_iter()
>>> fig.history_dict
{
    0: {"<Line2D>": {"color": "k"}},
    1: {"<Line2D>": {"color": "r", "ls: "-"}},
    2: {"<Line2D>": {ls: ":"}},
}

We temporarily alter the linewidth to 2, and then to 1.5. After we are satisfied with the temporary changes. we request a new iteration with the final change of color to green.

>>> fig.temporary_properties(fig.line, {"lw": 2})
>>> fig.temporary_properties(fig.line, {"lw": 1.5})
>>> fig.temporary_changes
{"<Line2D>": {"lw": 1.5}}
>>> fig.temporary_saved
{"<Line2D>": {"lw": 1}}      # default value
>>> fig.new_properties(fig.line, {"color": "g"})
>>> fig.new_iter()
>>> fig.history_dict
{
    0: {"<Line2D>": {"color": "k"}},
    1: {"<Line2D>": {"color": "r", "ls: "-", "lw": 1}},
    2: {"<Line2D>": {"lw": 1.5, color": "r"},
    3: {"<Line2D>": {"color": "g"}},
}

Properties in self.temporary_saved are saved to self.history_dict in the previous iteration, properties in self.temporary_changes are saved to the current iteration, and new properties are saved to the new iteration.

The history_dict for a plot with a Line2D object and a Circle object. In the second iteration, the color of the Line2D object is updated from black to red, and the linestyle of the Circle object is changed from “-” to “:”.

load_interactive_backend()

Configures the plotting backend.

If the Tkinter backend is enabled or can be enabled, the function returns True. For other backends False is returned.

Return type

bool

close()

Closes the figure.

focus()

Enables the blocking object, catches input for history navigation.

The BlockingKeyInput object is called which blocks the execution of the code. During this block, the user input is received by the blocking object and return to the current method. From here, we can manipulate the plot or move through the plot history and call focus() again when all changes in the history have been drawn and blit.

key

function

h

show help

i

show all iterations

d

redraw current iteration

enter or right

go to next iteration, enter iteration number

backspace or left

go to previous iteration

n

go to newest iteration

0-9

input iteration number

When the method is active, the focus is on the figure. This will be indicated by a green circle in the bottom right of the figure. When the focus is lost, the code execution is continued and the icon is red. The change is icon color is performed by _set_figure_state(), which also hides the interactive elements when the focus is lost.

draw_figure(new_iter_name=None, output=True, carriage_return=False, **kwargs)

Draws the canvas and blocks code execution.

Draws the queued plot changes onto the canvas and calls for focus() which blocks the code execution and catches user input for history navigation.

If a new iteration is called by supplying a new_iter_name, we additionally check for future property changes in the self.future_dict, and add these changes to the queue. Finally, all queued property changes for the next iteration are applied by change_properties.

Parameters
  • new_iter_name (Optional[str]) – Name of the new iteration. If no name is supplied, no new iteration is called.

  • output (bool) – Prints information to the console.

  • carriage_return (bool) – Applies carriage return to remove last line printed.

new_artist(artist, axis=None)

Adds a new artist to the axis.

Newly added artists must be hidden in the previous iteration. To make sure the history is properly logged, the visibility of the artist is set to False, and a new property of shown visibility is added to the queue of the next iteration.

Parameters
  • artist (Artist) – New plot artist to add to the axis.

  • axis (Optional[Axes]) – Axis to add the figure to.

Return type

None

static change_properties(artist, prop_dict)

Changes the plot properties and draw the plot object or artist.

new_properties(artist, properties, saved_properties={}, **kwargs)

Parses a dictionary of property changes of a matplotlib artist.

New properties are supplied via properties. If any of the new properties is different from its current value, this is seen as a property change. The old property value is stored in self.history_dict[self.history_iteration], and the new property value is stored at self.history_dict[self.history_iteration+1]. These new properties are queued for the next interation. The queue is emptied by applying all changes when draw_figure is called. If the same property changes 2+ times within the same iteration, the previous property change is removed with next_prop.pop(key, None).

The saved_properties parameter is used when temporary property changes have been applied by temporary_changes, in which the original properties are saved to self.temporary_saved as the saved properties. Before a new iteration is drawn, the temporary changes, which can be overwritten, are compared with the saved changes and the differences in properties are saved to [self.history_dict[self.history_iter-1]] and self.history_dict[self.history_iteration].

Some color values from different matplotlib objects are nested, some are list or tuple, and others may be a numpy.ndarray. The nested methods get_nested() and get_nested_property() make sure that the return type is always a list.

Parameters
  • artist (Artist) – Plot object whose properties are changed.

  • properties (dict) – Plot properties to change.

  • saved_properties (dict) – Override current properties and parse previous and current history.

temporary_properties(artist, properties, **kwargs)

Applies temporary property changes to a matplotlib artist.

Only available on the newest iteration, as we cannot change what is already in the past. All values in properties are immediately applied to artist. Since temporary changes can be overwritten within the same iteration, the first time a temporary property change is requested, the previous value is saved to self.temporary_saved. When the iteration changes, the property differences of the previous and current iteration are recomputed and saved to self.history_dict in _draw_from_history().

Parameters
  • artist (Artist) – Plot object whose properties are changed.

  • properties (dict) – Plot properties to change.

class qsurface.plot.Template3D(*args, **kwargs)

Template 3D plot object with history navigation.