mathmat.vis
MathMat Visualization Toolbox.
1"""MathMat Visualization Toolbox.""" 2 3import matplotlib.pyplot as plt 4from matplotlib import use as use_mpl_backend 5import numpy as np 6 7from mathmat import Matrix, EPS 8 9# Configure Matplotlib 10use_mpl_backend("TkAgg") 11params = {"ytick.color": "black", 12 "xtick.color": "black", 13 "axes.labelcolor": "black", 14 "axes.edgecolor": "black", 15 "axes.formatter.use_mathtext": True, 16 "text.usetex": False, 17 "font.family": "serif", 18 "font.serif": "cmr10", 19 "mathtext.fontset": "cm", 20 "figure.dpi": 100, 21 "figure.autolayout": True, 22 "savefig.dpi": 300, 23 "savefig.transparent": True, 24 "savefig.bbox": "tight", 25 "font.size": 12, 26 "lines.linewidth": 2} 27plt.rcParams.update(params) 28 29 30class Plot: 31 """A Plot is the base class for all visualizations. 32 Do not use Plot directly, as it does not show any data. 33 Instead, extend it or use a specific type of Plot.""" 34 35 def __init__(self, legend_labels=None, title=None, x_label=None, 36 y_label=None, **mpl_kwargs): 37 if type(legend_labels) is not list \ 38 and legend_labels is not None: 39 legend_labels = [legend_labels] 40 self.legend_labels = legend_labels 41 self.title = title 42 self.x_label = x_label 43 self.y_label = y_label 44 self._mpl_kwargs = mpl_kwargs 45 46 def plot_on(self, axes): 47 """Show the Plot on the specified matplotlib Axes.""" 48 if self.legend_labels is not None: 49 axes.legend(self.legend_labels) 50 if self.title is not None: 51 axes.set_title(self.title) 52 if self.x_label is not None: 53 axes.set_xlabel(self.x_label) 54 if self.y_label is not None: 55 axes.set_ylabel(self.y_label) 56 axes.margins(x=0, y=0) 57 58 59class DataPlot(Plot): 60 """A DataPlot visualizes data. Do not use it directly, instead 61 call LinePlot or ScatterPlot.""" 62 63 def __init__(self, Xs, Ys, formats=None, legend_labels=None, log_x=False, 64 log_y=False, title=None, x_label=None, 65 y_label=None, **mpl_kwargs): 66 super().__init__(legend_labels, title, x_label, y_label, **mpl_kwargs) 67 self.Xs = np.array(Xs) 68 self.Ys = np.array(Ys) 69 self.formats = formats 70 self.log_x = log_x 71 self.log_y = log_y 72 self._plt_args = (self.Xs.T, self.Ys.T) if self.formats is None else \ 73 (self.Xs, self.Ys, self.formats) 74 75 def plot_on(self, axes): 76 if self.log_x: 77 axes.set_xscale("log") 78 else: 79 axes.set_xscale("linear") 80 if self.log_y: 81 axes.set_yscale("log") 82 else: 83 axes.set_yscale("linear") 84 super().plot_on(axes) 85 86 87class LinePlot(DataPlot): 88 """A LinePlot visualizes data as lines. 89 `Xs` and `Ys` must be are array-like objects of equal length. 90 Optionally, `formats` is an array of equal length containing 91 format specifications for `matplotlib`. 92 `log_x` and `log_y` are used to specify logarithmic scaling of axes.""" 93 94 def plot_on(self, axes): 95 axes.plot(*self._plt_args, **self._mpl_kwargs) 96 super().plot_on(axes) 97 98 99class ScatterPlot(DataPlot): 100 """A LinePlot visualizes data as points. 101 `Xs` and `Ys` must be are array-like objects of equal length. 102 Optionally, `formats` is an array of equal length containing 103 format specifications for `matplotlib`. 104 `log_x` and `log_y` are used to specify logarithmic scaling of axes.""" 105 106 def plot_on(self, axes): 107 axes.scatter(*self._plt_args, **self._mpl_kwargs) 108 super().plot_on(axes) 109 110 111class Histogram(Plot): 112 """A Histogram visualizes data by grouping it based on values. 113 `log_x` and `log_y` are used to specify logarithmic scaling of axes.""" 114 115 def __init__(self, Xs, bins=None, 116 legend_labels=None, title=None, x_label=None, y_label=None, 117 **mpl_kwargs): 118 super().__init__(legend_labels, title, x_label, y_label, 119 **mpl_kwargs) 120 self.Xs = np.array(Xs) 121 self.bins = min(len(Xs), 10) if bins is None else bins 122 123 def plot_on(self, axes): 124 axes.hist(self.Xs, self.bins, **self._mpl_kwargs) 125 super().plot_on(axes) 126 127 128class MagnitudePlot(Plot): 129 """A MagnitudePlot shows the magnitude of the entries of a Matrix. 130 Densifies.""" 131 132 def __init__(self, M, 133 legend_labels=None, title=None, x_label=None, y_label=None, 134 **mpl_kwargs): 135 super().__init__(legend_labels, title, x_label, y_label, **mpl_kwargs) 136 if not isinstance(M, Matrix): 137 M = Matrix(M) 138 if M.is_sparse(): 139 M = M.to_dense() 140 if M.is_complex(): 141 M = Matrix(np.absolute(M.entries)) 142 self.M = M 143 if "cmap" not in self._mpl_kwargs: 144 self._mpl_kwargs["cmap"] = "gray_r" 145 146 def plot_on(self, axes): 147 pos = axes.matshow(self.M.entries, **self._mpl_kwargs) 148 plt.gcf().colorbar(pos, ax=axes, fraction=0.046) 149 super().plot_on(axes) 150 151 152class SparsityPlot(MagnitudePlot): 153 """A SparsityPlot shows the sparsity of a Matrix object. 154 Optionally specify a tolerance to treat entries as zero. Densifies.""" 155 156 def __init__(self, M, tolerance=EPS, 157 legend_labels=None, title=None, x_label=None, y_label=None, 158 **mpl_kwargs): 159 super().__init__(M, legend_labels, title, x_label, y_label, 160 **mpl_kwargs) 161 self.M = Matrix(~np.isclose(self.M.entries, 0, atol=tolerance)) 162 163 def plot_on(self, axes): 164 axes.matshow(self.M.entries, **self._mpl_kwargs) 165 Plot.plot_on(self, axes) 166 167 168class OrthogonalityPlot(MagnitudePlot): 169 """An OrthogonalityPlot treats a Matrix as a set of column vectors, 170 and shows the magnitude of each dot product by computing M^H M.""" 171 172 def __init__(self, M, 173 legend_labels=None, title=None, x_label=None, y_label=None, 174 **mpl_kwargs): 175 super().__init__(M, legend_labels, title, x_label, y_label, 176 **mpl_kwargs) 177 self.M = Matrix( 178 np.abs((self.M.conjugate().transpose() @ self.M).entries)) 179 180 181def single(plot, **mpl_kwargs): 182 """Show a single Plot on a new figure.""" 183 if not isinstance(plot, Plot): 184 raise ValueError("Cannot plot {}.".format(str(plot))) 185 186 figure = plt.figure(**mpl_kwargs) 187 plot.plot_on(figure.gca()) 188 return figure 189 190 191def tiled(plot_array, sup_title=None, sup_x_label=None, sup_y_label=None, 192 **mpl_kwargs): 193 """Tile the given plots in a grid. 194 `plot_array` can be a single plot, a one-dimensional list, 195 which will be rendered as a row of plots, or a two dimensional 196 list, which will be rendered as a grid of plots.""" 197 if isinstance(plot_array, Plot): 198 plot_array = [[plot_array]] 199 if type(plot_array) is list or type(plot_array) is tuple: 200 if type(plot_array[0]) is list or type(plot_array[0]) is tuple: 201 nr = len(plot_array) 202 nc = len(plot_array[0]) 203 else: 204 nr = 1 205 nc = len(plot_array) 206 plot_array = [plot_array] 207 else: 208 raise ValueError( 209 "Cannot interpret the plot array {}.".format(str(plot_array))) 210 211 figure, axes_arr = plt.subplots(nr, nc, **mpl_kwargs) 212 if len(axes_arr.shape) == 1: 213 axes_arr = np.array([axes_arr], dtype=object) 214 # Plot the super-titles and labels if specified 215 if sup_title is not None: 216 figure.suptitle(sup_title) 217 if sup_x_label is not None: 218 figure.supxlabel(sup_x_label) 219 if sup_y_label is not None: 220 figure.supylabel(sup_y_label) 221 222 # Generate all plots 223 for row in range(nr): 224 for col in range(nc): 225 plot_array[row][col].plot_on(axes_arr[row][col]) 226 227 return figure
31class Plot: 32 """A Plot is the base class for all visualizations. 33 Do not use Plot directly, as it does not show any data. 34 Instead, extend it or use a specific type of Plot.""" 35 36 def __init__(self, legend_labels=None, title=None, x_label=None, 37 y_label=None, **mpl_kwargs): 38 if type(legend_labels) is not list \ 39 and legend_labels is not None: 40 legend_labels = [legend_labels] 41 self.legend_labels = legend_labels 42 self.title = title 43 self.x_label = x_label 44 self.y_label = y_label 45 self._mpl_kwargs = mpl_kwargs 46 47 def plot_on(self, axes): 48 """Show the Plot on the specified matplotlib Axes.""" 49 if self.legend_labels is not None: 50 axes.legend(self.legend_labels) 51 if self.title is not None: 52 axes.set_title(self.title) 53 if self.x_label is not None: 54 axes.set_xlabel(self.x_label) 55 if self.y_label is not None: 56 axes.set_ylabel(self.y_label) 57 axes.margins(x=0, y=0)
A Plot is the base class for all visualizations. Do not use Plot directly, as it does not show any data. Instead, extend it or use a specific type of Plot.
36 def __init__(self, legend_labels=None, title=None, x_label=None, 37 y_label=None, **mpl_kwargs): 38 if type(legend_labels) is not list \ 39 and legend_labels is not None: 40 legend_labels = [legend_labels] 41 self.legend_labels = legend_labels 42 self.title = title 43 self.x_label = x_label 44 self.y_label = y_label 45 self._mpl_kwargs = mpl_kwargs
47 def plot_on(self, axes): 48 """Show the Plot on the specified matplotlib Axes.""" 49 if self.legend_labels is not None: 50 axes.legend(self.legend_labels) 51 if self.title is not None: 52 axes.set_title(self.title) 53 if self.x_label is not None: 54 axes.set_xlabel(self.x_label) 55 if self.y_label is not None: 56 axes.set_ylabel(self.y_label) 57 axes.margins(x=0, y=0)
Show the Plot on the specified matplotlib Axes.
60class DataPlot(Plot): 61 """A DataPlot visualizes data. Do not use it directly, instead 62 call LinePlot or ScatterPlot.""" 63 64 def __init__(self, Xs, Ys, formats=None, legend_labels=None, log_x=False, 65 log_y=False, title=None, x_label=None, 66 y_label=None, **mpl_kwargs): 67 super().__init__(legend_labels, title, x_label, y_label, **mpl_kwargs) 68 self.Xs = np.array(Xs) 69 self.Ys = np.array(Ys) 70 self.formats = formats 71 self.log_x = log_x 72 self.log_y = log_y 73 self._plt_args = (self.Xs.T, self.Ys.T) if self.formats is None else \ 74 (self.Xs, self.Ys, self.formats) 75 76 def plot_on(self, axes): 77 if self.log_x: 78 axes.set_xscale("log") 79 else: 80 axes.set_xscale("linear") 81 if self.log_y: 82 axes.set_yscale("log") 83 else: 84 axes.set_yscale("linear") 85 super().plot_on(axes)
A DataPlot visualizes data. Do not use it directly, instead call LinePlot or ScatterPlot.
64 def __init__(self, Xs, Ys, formats=None, legend_labels=None, log_x=False, 65 log_y=False, title=None, x_label=None, 66 y_label=None, **mpl_kwargs): 67 super().__init__(legend_labels, title, x_label, y_label, **mpl_kwargs) 68 self.Xs = np.array(Xs) 69 self.Ys = np.array(Ys) 70 self.formats = formats 71 self.log_x = log_x 72 self.log_y = log_y 73 self._plt_args = (self.Xs.T, self.Ys.T) if self.formats is None else \ 74 (self.Xs, self.Ys, self.formats)
76 def plot_on(self, axes): 77 if self.log_x: 78 axes.set_xscale("log") 79 else: 80 axes.set_xscale("linear") 81 if self.log_y: 82 axes.set_yscale("log") 83 else: 84 axes.set_yscale("linear") 85 super().plot_on(axes)
Show the Plot on the specified matplotlib Axes.
Inherited Members
88class LinePlot(DataPlot): 89 """A LinePlot visualizes data as lines. 90 `Xs` and `Ys` must be are array-like objects of equal length. 91 Optionally, `formats` is an array of equal length containing 92 format specifications for `matplotlib`. 93 `log_x` and `log_y` are used to specify logarithmic scaling of axes.""" 94 95 def plot_on(self, axes): 96 axes.plot(*self._plt_args, **self._mpl_kwargs) 97 super().plot_on(axes)
A LinePlot visualizes data as lines.
Xs
and Ys
must be are array-like objects of equal length.
Optionally, formats
is an array of equal length containing
format specifications for matplotlib
.
log_x
and log_y
are used to specify logarithmic scaling of axes.
100class ScatterPlot(DataPlot): 101 """A LinePlot visualizes data as points. 102 `Xs` and `Ys` must be are array-like objects of equal length. 103 Optionally, `formats` is an array of equal length containing 104 format specifications for `matplotlib`. 105 `log_x` and `log_y` are used to specify logarithmic scaling of axes.""" 106 107 def plot_on(self, axes): 108 axes.scatter(*self._plt_args, **self._mpl_kwargs) 109 super().plot_on(axes)
A LinePlot visualizes data as points.
Xs
and Ys
must be are array-like objects of equal length.
Optionally, formats
is an array of equal length containing
format specifications for matplotlib
.
log_x
and log_y
are used to specify logarithmic scaling of axes.
112class Histogram(Plot): 113 """A Histogram visualizes data by grouping it based on values. 114 `log_x` and `log_y` are used to specify logarithmic scaling of axes.""" 115 116 def __init__(self, Xs, bins=None, 117 legend_labels=None, title=None, x_label=None, y_label=None, 118 **mpl_kwargs): 119 super().__init__(legend_labels, title, x_label, y_label, 120 **mpl_kwargs) 121 self.Xs = np.array(Xs) 122 self.bins = min(len(Xs), 10) if bins is None else bins 123 124 def plot_on(self, axes): 125 axes.hist(self.Xs, self.bins, **self._mpl_kwargs) 126 super().plot_on(axes)
A Histogram visualizes data by grouping it based on values.
log_x
and log_y
are used to specify logarithmic scaling of axes.
124 def plot_on(self, axes): 125 axes.hist(self.Xs, self.bins, **self._mpl_kwargs) 126 super().plot_on(axes)
Show the Plot on the specified matplotlib Axes.
Inherited Members
129class MagnitudePlot(Plot): 130 """A MagnitudePlot shows the magnitude of the entries of a Matrix. 131 Densifies.""" 132 133 def __init__(self, M, 134 legend_labels=None, title=None, x_label=None, y_label=None, 135 **mpl_kwargs): 136 super().__init__(legend_labels, title, x_label, y_label, **mpl_kwargs) 137 if not isinstance(M, Matrix): 138 M = Matrix(M) 139 if M.is_sparse(): 140 M = M.to_dense() 141 if M.is_complex(): 142 M = Matrix(np.absolute(M.entries)) 143 self.M = M 144 if "cmap" not in self._mpl_kwargs: 145 self._mpl_kwargs["cmap"] = "gray_r" 146 147 def plot_on(self, axes): 148 pos = axes.matshow(self.M.entries, **self._mpl_kwargs) 149 plt.gcf().colorbar(pos, ax=axes, fraction=0.046) 150 super().plot_on(axes)
A MagnitudePlot shows the magnitude of the entries of a Matrix. Densifies.
133 def __init__(self, M, 134 legend_labels=None, title=None, x_label=None, y_label=None, 135 **mpl_kwargs): 136 super().__init__(legend_labels, title, x_label, y_label, **mpl_kwargs) 137 if not isinstance(M, Matrix): 138 M = Matrix(M) 139 if M.is_sparse(): 140 M = M.to_dense() 141 if M.is_complex(): 142 M = Matrix(np.absolute(M.entries)) 143 self.M = M 144 if "cmap" not in self._mpl_kwargs: 145 self._mpl_kwargs["cmap"] = "gray_r"
147 def plot_on(self, axes): 148 pos = axes.matshow(self.M.entries, **self._mpl_kwargs) 149 plt.gcf().colorbar(pos, ax=axes, fraction=0.046) 150 super().plot_on(axes)
Show the Plot on the specified matplotlib Axes.
Inherited Members
153class SparsityPlot(MagnitudePlot): 154 """A SparsityPlot shows the sparsity of a Matrix object. 155 Optionally specify a tolerance to treat entries as zero. Densifies.""" 156 157 def __init__(self, M, tolerance=EPS, 158 legend_labels=None, title=None, x_label=None, y_label=None, 159 **mpl_kwargs): 160 super().__init__(M, legend_labels, title, x_label, y_label, 161 **mpl_kwargs) 162 self.M = Matrix(~np.isclose(self.M.entries, 0, atol=tolerance)) 163 164 def plot_on(self, axes): 165 axes.matshow(self.M.entries, **self._mpl_kwargs) 166 Plot.plot_on(self, axes)
A SparsityPlot shows the sparsity of a Matrix object. Optionally specify a tolerance to treat entries as zero. Densifies.
164 def plot_on(self, axes): 165 axes.matshow(self.M.entries, **self._mpl_kwargs) 166 Plot.plot_on(self, axes)
Show the Plot on the specified matplotlib Axes.
Inherited Members
169class OrthogonalityPlot(MagnitudePlot): 170 """An OrthogonalityPlot treats a Matrix as a set of column vectors, 171 and shows the magnitude of each dot product by computing M^H M.""" 172 173 def __init__(self, M, 174 legend_labels=None, title=None, x_label=None, y_label=None, 175 **mpl_kwargs): 176 super().__init__(M, legend_labels, title, x_label, y_label, 177 **mpl_kwargs) 178 self.M = Matrix( 179 np.abs((self.M.conjugate().transpose() @ self.M).entries))
An OrthogonalityPlot treats a Matrix as a set of column vectors, and shows the magnitude of each dot product by computing M^H M.
Inherited Members
182def single(plot, **mpl_kwargs): 183 """Show a single Plot on a new figure.""" 184 if not isinstance(plot, Plot): 185 raise ValueError("Cannot plot {}.".format(str(plot))) 186 187 figure = plt.figure(**mpl_kwargs) 188 plot.plot_on(figure.gca()) 189 return figure
Show a single Plot on a new figure.
192def tiled(plot_array, sup_title=None, sup_x_label=None, sup_y_label=None, 193 **mpl_kwargs): 194 """Tile the given plots in a grid. 195 `plot_array` can be a single plot, a one-dimensional list, 196 which will be rendered as a row of plots, or a two dimensional 197 list, which will be rendered as a grid of plots.""" 198 if isinstance(plot_array, Plot): 199 plot_array = [[plot_array]] 200 if type(plot_array) is list or type(plot_array) is tuple: 201 if type(plot_array[0]) is list or type(plot_array[0]) is tuple: 202 nr = len(plot_array) 203 nc = len(plot_array[0]) 204 else: 205 nr = 1 206 nc = len(plot_array) 207 plot_array = [plot_array] 208 else: 209 raise ValueError( 210 "Cannot interpret the plot array {}.".format(str(plot_array))) 211 212 figure, axes_arr = plt.subplots(nr, nc, **mpl_kwargs) 213 if len(axes_arr.shape) == 1: 214 axes_arr = np.array([axes_arr], dtype=object) 215 # Plot the super-titles and labels if specified 216 if sup_title is not None: 217 figure.suptitle(sup_title) 218 if sup_x_label is not None: 219 figure.supxlabel(sup_x_label) 220 if sup_y_label is not None: 221 figure.supylabel(sup_y_label) 222 223 # Generate all plots 224 for row in range(nr): 225 for col in range(nc): 226 plot_array[row][col].plot_on(axes_arr[row][col]) 227 228 return figure
Tile the given plots in a grid.
plot_array
can be a single plot, a one-dimensional list,
which will be rendered as a row of plots, or a two dimensional
list, which will be rendered as a grid of plots.