Source code for mytk.figures

import importlib

from .base import Base
from .modulesmanager import ModulesManager


[docs] class Figure(Base): """Wrapper around matplotlib Figure for embedding plots in tkinter.""" def __init__(self, figure=None, figsize=None): Base.__init__(self) self._figure = figure self.figsize = figsize if self.figsize is None: self.figsize = (6, 4) self.canvas = None self.toolbar = None
[docs] def is_environment_valid(self): """Check that matplotlib is installed and importable.""" ModulesManager.install_and_import_modules_if_absent( {"matplotlib": "matplotlib"} ) self.matplotlib = ModulesManager.imported.get("matplotlib", None) if self.matplotlib is not None: self.plt = importlib.import_module("matplotlib.pyplot") self.MPLFigure = importlib.import_module("matplotlib.figure").Figure self.FigureCanvasTkAgg = importlib.import_module( "matplotlib.backends.backend_tkagg" ).FigureCanvasTkAgg self.NavigationToolbar2Tk = importlib.import_module( "matplotlib.backends.backend_tkagg" ).NavigationToolbar2Tk return all( v is not None for v in [ self.matplotlib, self.plt, self.MPLFigure, self.FigureCanvasTkAgg, self.NavigationToolbar2Tk, ] )
[docs] def create_widget(self, master): """Create the matplotlib canvas and navigation toolbar.""" self.parent = master if self.figure is None: self.figure = self.MPLFigure(figsize=self.figsize, dpi=100) self.canvas = self.FigureCanvasTkAgg(self.figure, master=master) self.widget = self.canvas.get_tk_widget() self.toolbar = self.NavigationToolbar2Tk( self.canvas, master, pack_toolbar=False ) self.toolbar.update()
@property def figure(self): """The underlying matplotlib Figure.""" return self._figure @figure.setter def figure(self, figure): if self._figure is not None: self._figure.close() self._figure = figure # HACK : For now, we need to destroy the old widget and canvas self.create_widget(self.parent) @property def first_axis(self): """The first axes of the figure, or None if unavailable.""" if self.figure is not None: axes = self.figure.axes if len(axes) > 0: return axes[0] return None @property def axes(self): """All axes of the figure, or None if the figure is not set.""" if self.figure is not None: return self.figure.axes return None
[docs] def styles_pointmarker(self, linestyle=""): """Return a list of point-marker style dictionaries for plotting.""" default_size = 8 plain_black = dict( fillstyle="full", marker="o", linestyle=linestyle, markersize=default_size, color="black", markerfacecolor="black", markerfacecoloralt="black", markeredgecolor="black", ) circle_black = dict( fillstyle="full", marker="o", linestyle=linestyle, markersize=default_size, color="black", markerfacecolor="white", markerfacecoloralt="white", markeredgecolor="black", ) plain_s_black = dict( fillstyle="full", marker="s", linestyle=linestyle, markersize=default_size, color="black", markerfacecolor="black", markerfacecoloralt="black", markeredgecolor="black", ) square_black = dict( fillstyle="full", marker="s", linestyle=linestyle, markersize=default_size, color="black", markerfacecolor="white", markerfacecoloralt="white", markeredgecolor="black", ) plain_red = dict( fillstyle="full", marker="o", linestyle=linestyle, markersize=default_size, color="red", markerfacecolor="red", markerfacecoloralt="red", markeredgecolor="red", ) circle_red = dict( fillstyle="none", marker="o", linestyle=linestyle, markersize=default_size, color="red", markerfacecolor="white", markerfacecoloralt="white", markeredgecolor="red", ) styles = [ plain_black, circle_black, plain_s_black, square_black, plain_red, circle_red, ] return styles
[docs] def styles_points_linemarkers(self, linestyle="-"): """Return a list of point-and-line marker style dictionaries for plotting.""" default_size = 8 plain_black = dict( fillstyle="full", marker="o", linestyle=linestyle, markersize=default_size, color="black", markerfacecolor="black", markerfacecoloralt="black", markeredgecolor="black", ) circle_black = dict( fillstyle="none", marker="o", linestyle=linestyle, markersize=default_size, color="black", markerfacecolor=None, markerfacecoloralt=None, markeredgecolor="black", ) plain_s_black = dict( fillstyle="full", marker="s", linestyle=linestyle, markersize=default_size, color="black", markerfacecolor="black", markerfacecoloralt="black", markeredgecolor="black", ) square_black = dict( fillstyle="none", marker="s", linestyle=linestyle, markersize=default_size, color="black", markerfacecolor=None, markerfacecoloralt=None, markeredgecolor="black", ) plain_red = dict( fillstyle="full", marker="o", linestyle=linestyle, markersize=default_size, color="red", markerfacecolor="red", markerfacecoloralt="red", markeredgecolor="red", ) circle_red = dict( fillstyle="none", marker="o", linestyle=linestyle, markersize=default_size, color="red", markerfacecolor=None, markerfacecoloralt=None, markeredgecolor="red", ) styles = [ plain_black, circle_black, plain_s_black, square_black, plain_red, circle_red, ] return styles
[docs] class XYPlot(Figure): """Simple XY line plot backed by matplotlib.""" def __init__(self, figsize): super().__init__(figsize=figsize) self.x = [] self.y = [] self.x_range = 10 # self.style = "https://raw.githubusercontent.com/dccote/Enseignement/master/SRC/dccote-basic.mplstyle"
[docs] def create_widget(self, master, **kwargs): """Create the plot widget and draw the initial plot.""" super().create_widget(master, *kwargs) if self.first_axis is None: self.figure.add_subplot() self.update_plot()
[docs] def clear_plot(self): """Clear all data and redraw the plot.""" self.x = [] self.y = [] self.first_axis.clear() self.update_plot()
[docs] def update_plot(self): """Redraw the plot with the current data.""" # with plt.style.context(self.style): self.first_axis.clear() self.first_axis.plot(self.x, self.y, "k-") self.figure.canvas.draw() self.figure.canvas.flush_events()
[docs] def append(self, x, y): """Append a data point to the plot.""" self.x.append(x) self.y.append(y)
# self.x = self.x[-self.x_range : -1] # self.y = self.y[-self.x_range : -1]
[docs] class Histogram(Figure): """Histogram plot backed by matplotlib and numpy.""" def __init__(self, figsize): super().__init__(figsize=figsize) self.x = [] self.y = []
[docs] def is_environment_valid(self): """Check that matplotlib and numpy are installed and importable.""" if super().is_environment_valid(): ModulesManager.install_and_import_modules_if_absent({"numpy": "numpy"}) return ModulesManager.imported["numpy"] else: return False
[docs] def create_widget(self, master, **kwargs): """Create the histogram widget and draw the initial plot.""" super().create_widget(master, *kwargs) if self.first_axis is None: self.figure.add_subplot() self.update_plot()
[docs] def clear_plot(self): """Clear all histogram data and the axes.""" self.x = [] self.y = [] self.first_axis.clear()
[docs] def update_plot(self): """Redraw the histogram with the current data.""" if len(self.x) > 1: colors = ["red", "green", "blue"] for i, y in enumerate(self.y): self.first_axis.stairs(y[:-1], self.x, color=colors[i]) numpy = ModulesManager.imported["numpy"] self.first_axis.set_ylim((0, numpy.mean(self.y) + numpy.std(self.y) * 2)) self.first_axis.set_yticklabels([]) self.first_axis.set_xticklabels([]) self.first_axis.set_xticks([]) self.first_axis.set_yticks([]) self.figure.canvas.draw() self.figure.canvas.flush_events()