I'm drawing the following plot using Matplotlib
:
import matplotlib.pyplot as mlp
import numpy.linalg as npl
def ploteig(self, erg:bool) -> None:
theta = np.arange(start=0, stop=2.0*np.pi, step=0.01)
r = np.ones(len(theta))
values, _ = npl.eig(self._p)
values = values.astype(complex)
x_unit_circle = r * np.cos(theta)
y_unit_circle = r * np.sin(theta)
x_eigenvalues = np.unique(np.append(values, np.complex(1.0)))
y_eigenvalues = np.zeros(len(x_eigenvalues))
has_slem = False
if erg:
values_abs = np.sort(np.abs(values))
values_ct1 = np.isclose(values_abs, 1.0)
if not np.all(values_ct1):
mu = values_abs[~values_ct1][-1]
if not np.isclose(mu, 0.0):
r *= mu;
x_slem_circle = r * np.cos(theta)
y_slem_circle = r * np.sin(theta)
has_slem = True
fig, ax = mlp.subplots()
ax.plot(x_unit_circle, y_unit_circle, color='red', linestyle='-', linewidth=3)
ax.plot(x_eigenvalues, y_eigenvalues, color='blue', linestyle='None', marker='*', markersize=10)
if has_slem:
ax.plot(x_slem_circle, y_slem_circle, color='red', linestyle='--', linewidth=1)
ax.grid(True)
ax.set_aspect('equal', 'datalim')
mlp.show()
When has_slem
is True
, then the slem circle is always smaller than the unit circle, hence the plot produces two concentric circles where the outer circle is given by (x_unit_circle,y_unit_circle)
and the inner circle is given by (x_slem_circle,y_slem_circle)
.
What I would like to do is to fill the area between the two circles with a light red color. This is what I tried so far:
if has_slem:
ax.plot(x_slem_circle, y_slem_circle, color='red', linestyle='--', linewidth=1)
ax.fill_between(x_unit_circle, y_unit_circle, -y_unit_circle, color="red", alpha=0.2)
ax.fill_between(x_slem_circle, y_slem_circle, -y_slem_circle, color="white")
But this approach has two problems:
- If the axes color is changed, the second
fill_between
call would produce a wrong fill based onwhite
color. - The filled area looks a little bit misaligned with respect to the inner circle (there is a small white gap), as you can see on the screenshot below.
So, here comes my question: is there a better and more precise approach for filling the area between the two circles that allows me to bypass both problems?
On a totally unrelated note: is it ok to call mlp.show()
inside the function? I don't know what are the best practices here... maybe it's better to return the figure handle and let the consumer decide when to pop it up?