mcetl.plot_utils¶
Provides utility functions, classes, and constants for plotting.
Separated from utils.py to reduce import load time since matplotlib imports are not needed for base usage. Useful functions are put here in order to prevent circular importing within the other files.
@author: Donald Erb Created on Nov 11, 2020
-
mcetl.plot_utils.
CANVAS_SIZE
¶ A tuple specifying the size (in pixels) of the figure canvas used in various GUIs for mcetl. This can be modified if the user wishes a larger or smaller canvas. The default is (800, 800).
Module Contents¶
Classes¶
Class defining a PySimpleGUI window with an embedded matplotlib Figure. |
|
Custom toolbar without the subplots and save figure buttons. |
Functions¶
Gives the correct dpi to fit the figure within the GUI canvas. |
|
Places the figure and toolbar onto the canvas. |
|
Calculates the correction factor needed to create a figure with the desired dpi. |
|
Calculates the new bounds to scale the current axis bounds. |
-
class
mcetl.plot_utils.
EmbeddedFigure
(x, y, click_list=None, enable_events=True, enable_keybinds=True, toolbar_class=NavigationToolbar2Tk)¶ Class defining a PySimpleGUI window with an embedded matplotlib Figure.
Class to be used to define BackgroundSelector and PeakSelector classes, which share common functions.
- Parameters
x (array-like) -- The x-values to be plotted.
y (array-like) -- The y-values to be plotted.
click_list (list, optional) -- A list of selected points on the plot.
enable_events (bool, optional) -- If True (default), will connect self.events (defaults to self._on_click, self._on_pick, and self._on_key) to the figure when it is drawn on the canvas. If False, the figure will have no connected events.
enable_keybinds (bool, optional) -- If True (default), will connect the matplotlib keybind events to the figure.
toolbar_class (NavigationToolbar2Tk, optional) -- The class of the toolbar to place in the window. The default is NavigationToolbar2Tk.
-
x
¶ The x-values to be plotted.
- Type
array-like
-
y
¶ The y-values to be plotted.
- Type
array-like
-
figure
¶ The figure embedded in the window.
- Type
plt.Figure
-
axis
¶ The main axis on the figure which owns the events.
- Type
plt.Axes
-
canvas
¶ The PySimpleGUI canvas element in the window which contains the figure.
- Type
sg.Canvas
-
toolbar_canvas
¶ The PySimpleGUI canvas element that contains the toolbar for the figure.
- Type
sg.Canvas
-
picked_object
¶ The selected Artist objected on the figure. Useful for pick events.
- Type
plt.Artist
-
xaxis_limits
¶ The x axis limits when the figure is first created. The values are used to determine the size of the Ellipse place by the _create_circle function. The initial limits are used so that zooming on the figure does not change the size of the Ellipse.
- Type
-
events
¶ A list containing the events for the figure. Each item in the list is a list or tuple with the first item being the matplotlib event, such as 'pick_event', and the second item is a callable (function) to be executed when the event occurs.
-
canvas_size
¶ The size, in pixels, of the figure to be created. Default is (CANVAS_SIZE[0], CANVAS_SIZE[1] - 100), which is (800, 700).
-
toolbar_class
¶ The class of the toolbar to place in the window. The default is NavigationToolbar2Tk.
- Type
NavigationToolbar2Tk
-
window
¶ The PySimpleGUI window containing the figure.
- Type
sg.Window
-
enable_keybinds
¶ If True, will allow using matplotlib's keybinds to trigger events on the figure.
- Type
Notes
This class allows easy subclassing to create simple windows with embedded matplotlib figures.
A typical __init__ for a subclass should create the figure and axes, create the window, and then place the figure within the window's canvas. For example (note that plt designates matplotlib.pyplot)
>>> class SimpleEmbeddedFigure(EmbeddedFigure): def __init__(x, y, **kwargs): super().__init__(x, y, **kwargs) self.figure, self.axis = plt.subplots() self.axis.plot(self.x, self.y) self._create_window() self._place_figure_on_canvas()
The only function that should be publically available is the event_loop method, which should return the desired output.
To close the window, use the self._close() method, which ensures that both the window and the figure are correctly closed.
Initialize self. See help(type(self)) for accurate signature.
-
event_loop
(self)¶ Handles the event loop for the GUI.
Notes
This function should typically be overwritten by a subclass, and should typically return any desired values from the embedded figure.
This simple implementation makes the window visible, and closes the window as soon as anything in the window is clicked.
-
class
mcetl.plot_utils.
PlotToolbar
(fig_canvas, canvas, **kwargs)¶ Bases:
matplotlib.backends.backend_tkagg.NavigationToolbar2Tk
Custom toolbar without the subplots and save figure buttons.
Ensures that saving is done through the save menu in the window, which gives better options for output image quality and ensures the figure dimensions are correct. The subplots button is removed so that the user does not mess with the plot layout since it is handled by using matplotlib's tight layout.
- Parameters
fig_canvas (matplotlib.FigureCanvas) -- The figure canvas on which to operate.
canvas (tkinter.Canvas) -- The Canvas element which owns this toolbar.
**kwargs -- Any additional keyword arguments to pass to NavigationToolbar2Tk.
-
mcetl.plot_utils.
determine_dpi
(fig_height, fig_width, dpi, canvas_size=CANVAS_SIZE)¶ Gives the correct dpi to fit the figure within the GUI canvas.
- Parameters
- Returns
The correct dpi to fit the figure onto the GUI canvas.
- Return type
Notes
When not saving, the dpi needs to be scaled to fit the figure on the GUI's canvas, and that scaling is called size_scale. For example, if the desired size was 1600 x 1200 pixels with a dpi of 300, the figure would be scaled down to 800 x 600 pixels to fit onto the canvas, so the dpi would be changed to 150, with a size_scale of 0.5.
A dpi_scale correction is needed because the qt5Agg backend will change the dpi to 2x the specified dpi when the display scaling in Windows is not 100%. I am not sure how it works on non-Windows operating systems.
The final dpi when not saving is equal to dpi * size_scale * dpi_scale.
-
mcetl.plot_utils.
draw_figure_on_canvas
(canvas, figure, toolbar_canvas=None, toolbar_class=NavigationToolbar2Tk, kwargs=None)¶ Places the figure and toolbar onto the canvas.
- Parameters
canvas (tkinter.Canvas) -- The tkinter Canvas element for the figure.
figure (plt.Figure) -- The figure to be place on the canvas.
toolbar_canvas (tkinter.Canvas, optional) -- The tkinter Canvas element for the toolbar.
toolbar_class (NavigationToolbar2Tk, optional) -- The toolbar class used to create the toolbar for the figure. The default is NavigationToolbar2Tk.
kwargs (dict, optional) -- Keyword arguments designating how to pack the figure into the window. Relevant keys are 'canvas' and 'toolbar', with values being dictionaries containing keyword arguments to pass to pack.
- Returns
figure_canvas (FigureCanvasTkAgg or None) -- The canvas containing the figure. Is None if drawing the canvas caused an exception.
toolbar (NavigationToolbar2Tk or None) -- The created toolbar. Is None if toolbar_canvas is None, or if there was an error when drawing figure_canvas.
Notes
The canvas children are destroyed after drawing the figure canvas so that there is a seamless transition from the old canvas to the new canvas.
The toolbar is packed before the figure canvas because the figure canvas shoulud be more flexible to resizing if they are on the same canvas.
-
mcetl.plot_utils.
get_dpi_correction
(dpi)¶ Calculates the correction factor needed to create a figure with the desired dpi.
Necessary because some matplotlib backends (namely qt5Agg) will adjust the dpi of the figure after creation.
- Parameters
- Returns
dpi_correction -- The scaling factor needed to create a figure with the desired dpi.
- Return type
Notes
The matplotlib dpi correction occurs when the operating system display scaling is set to any value not equal to 100% (at least on Windows, other operating systems are unknown). This may cause issues when using UHD monitors, but I cannot test.
To get the desired dpi, simply create a figure with a dpi equal to dpi * dpi_correction.
-
mcetl.plot_utils.
scale_axis
(axis_bounds, lower_scale=None, upper_scale=None)¶ Calculates the new bounds to scale the current axis bounds.
The new bounds are calculated by multiplying the desired scale factor by the current difference of the upper and lower bounds, and then adding (for upper bound) or subtracting (for lower bound) from the current bound.
- Parameters
axis_bounds (tuple(float, float)) -- The current lower and upper axis bounds.
lower_scale (float, optional) -- The desired fraction by which to scale the current lower bound. If None, will not scale the current lower bounds.
upper_scale (float, optional) -- The desired fraction by which to scale the current upper bound. If None, will not scale the current upper bounds.
- Returns
lower_bound (float) -- The lower bound after scaling.
upper_bound (float) -- The upper bound after scaling.