class EigsVisualizer:
def __init__(self, eigs):
self.eigs = eigs
def show(self):
self.plot_eigs(narrow_view=True, show_axes=True)
def _enforce_ratio(self, goal_ratio, supx, infx, supy, infy):
"""
Computes the right value of `supx,infx,supy,infy` to obtain the desired
ratio in :func:`plot_eigs`. Ratio is defined as
::
dx = supx - infx
dy = supy - infy
max(dx,dy) / min(dx,dy)
:param float goal_ratio: the desired ratio.
:param float supx: the old value of `supx`, to be adjusted.
:param float infx: the old value of `infx`, to be adjusted.
:param float supy: the old value of `supy`, to be adjusted.
:param float infy: the old value of `infy`, to be adjusted.
:return tuple: a tuple which contains the updated values of
`supx,infx,supy,infy` in this order.
"""
dx = supx - infx
if dx == 0:
dx = 1.e-16
dy = supy - infy
if dy == 0:
dy = 1.e-16
ratio = max(dx, dy) / min(dx, dy)
if ratio >= goal_ratio:
if dx < dy:
goal_size = dy / goal_ratio
supx += (goal_size - dx) / 2
infx -= (goal_size - dx) / 2
elif dy < dx:
goal_size = dx / goal_ratio
supy += (goal_size - dy) / 2
infy -= (goal_size - dy) / 2
return (supx,infx,supy,infy)
def _plot_limits(self, narrow_view):
if narrow_view:
supx = max(self.eigs.real) + 0.05
infx = min(self.eigs.real) - 0.05
supy = max(self.eigs.imag) + 0.05
infy = min(self.eigs.imag) - 0.05
return self._enforce_ratio(8, supx, infx, supy,
infy)
else:
return np.max(np.ceil(np.absolute(self.eigs)))
def plot_eigs(self,
show_axes=True,
show_unit_circle=True,
figsize=(8, 8),
title='',
narrow_view=False,
dpi=None,
filename=None):
"""
Plot the eigenvalues.
:param bool show_axes: if True, the axes will be showed in the plot.
Default is True.
:param bool show_unit_circle: if True, the circle with unitary radius
and center in the origin will be showed. Default is True.
:param tuple(int,int) figsize: tuple in inches defining the figure
size. Default is (8, 8).
:param str title: title of the plot.
:param narrow_view bool: if True, the plot will show only the smallest
rectangular area which contains all the eigenvalues, with a padding
of 0.05. Not compatible with `show_axes=True`. Default is False.
:param dpi int: If not None, the given value is passed to ``plt.figure``.
:param str filename: if specified, the plot is saved at `filename`.
"""
if self.eigs is None:
raise ValueError('The eigenvalues have not been computed.'
'You have to perform the fit method.')
if dpi is not None:
plt.figure(figsize=figsize, dpi=dpi)
else:
plt.figure(figsize=figsize)
plt.title(title)
plt.gcf()
ax = plt.gca()
points, = ax.plot(self.eigs.real,
self.eigs.imag,
'bo',
label='Eigenvalues')
if narrow_view:
supx, infx, supy, infy = self._plot_limits(narrow_view)
# set limits for axis
ax.set_xlim((infx, supx))
ax.set_ylim((infy, supy))
# x and y axes
if show_axes:
endx = np.min([supx, 1.])
ax.annotate('',
xy=(endx, 0.),
xytext=(np.max([infx, -1.]), 0.),
arrowprops=dict(arrowstyle=("->" if endx == 1. else '-')))
endy = np.min([supy, 1.])
ax.annotate('',
xy=(0., endy),
xytext=(0., np.max([infy, -1.])),
arrowprops=dict(arrowstyle=("->" if endy == 1. else '-')))
else:
# set limits for axis
limit = self._plot_limits(narrow_view)
ax.set_xlim((-limit, limit))
ax.set_ylim((-limit, limit))
# x and y axes
if show_axes:
ax.annotate('',
xy=(np.max([limit * 0.8, 1.]), 0.),
xytext=(np.min([-limit * 0.8, -1.]), 0.),
arrowprops=dict(arrowstyle="->"))
ax.annotate('',
xy=(0., np.max([limit * 0.8, 1.])),
xytext=(0., np.min([-limit * 0.8, -1.])),
arrowprops=dict(arrowstyle="->"))
plt.ylabel('Imaginary part')
plt.xlabel('Real part')
if show_unit_circle:
unit_circle = plt.Circle((0., 0.),
1.,
color='green',
fill=False,
label='Unit circle',
linestyle='--')
ax.add_artist(unit_circle)
# Dashed grid
gridlines = ax.get_xgridlines() + ax.get_ygridlines()
for line in gridlines:
line.set_linestyle('-.')
ax.grid(True)
# legend
if show_unit_circle:
ax.add_artist(
plt.legend([points, unit_circle],
['Eigenvalues', 'Unit circle'],
loc='best'))
else:
ax.add_artist(plt.legend([points], ['Eigenvalues'], loc='best'))
ax.set_aspect('equal')
if filename:
plt.savefig(filename)
else:
plt.show()
Comments