I'm having a really hard time attempting to properly size a figure with a variable number of subplots (between 3 and 8) and 2 legends that should appear glued to each other.
I also checked every related issue here in stack overflow, but couldn't get any answer to this specific case, due to my need for 2 legends.
The important to me is to get an optimal figure that I save as pdf to include in a report. I tried everything, and in the end the closes I got was with using tight: fig.savefig(f'variations{len(list_variations)}_B.pdf', bbox_inches='tight').
Here is a fully reproducible example (that emulates my code and figures):
list_variations = [0, 1, 2, 3, 4, 5, 6, 7, 8] # Does not work for any option
list_variations = [0, 1, 2] # Works Fine for Option A
n_subplots = len(list_variations)
fig_size = (5.457, n_subplots*3.5/3)
fig, axs = plt.subplots(n_subplots, 1, figsize=fig_size, sharex=True, sharey=True)
labels_upp = ('abdications', 'liner wint.ol.:$\\pm$0.19e', 'liner wint.ol.:$\\pm$0.1e')
labels_low = ('apportions', 'bisections', 'ablations', 'saktis')
for idx in list_variations:
for i, lab_upp in enumerate(labels_upp):
axs[idx].plot(60+i, 0.2, label=lab_upp)
for lab_low in labels_low:
axs[idx].plot(60+i, -0.2, label=lab_low)
axs[idx].set_title(f'Variation {idx}', fontsize=8)
axs[-1].set_xlim((60, 80))
axs[-1].set(ylim=(-1, 1))
axs[-1].set(xlabel='elasticity (e)')
plt.subplots_adjust(hspace=0.25)
# Make Legends (PROBLEM IS HERE)
# Option A - relative to fig
props_leg_upp = dict(facecolor='white', bbox_to_anchor=(0, -0.102, 1, 0.1), mode='expand', loc='upper center')
props_leg_low = dict(facecolor='lightgrey', bbox_to_anchor=(0, -0.172, 1, 0.1), mode='expand', loc='upper center')
upper_leg = fig.legend(labels_upp, ncol=len(labels_upp), **props_leg_upp)
lower_leg = fig.legend(labels_low, ncol=len(labels_low), **props_leg_low)
axs[-1].add_artist(upper_leg)
# Option B - relative to axs[-1]
props_leg_upp = dict(facecolor='white', bbox_to_anchor=(0, -0.262, 1, 0.1), mode='expand', loc='upper center')
props_leg_low = dict(facecolor='lightgrey', bbox_to_anchor=(0, -0.322, 1, 0.1), mode='expand', loc='upper center')
upper_leg = axs[-1].legend(labels_upp, ncol=len(labels_upp), **props_leg_upp)
lower_leg = axs[-1].legend(labels_low, ncol=len(labels_low), **props_leg_low)
axs[-1].add_artist(upper_leg)
I tried every combination of matplotlib.legend properties that I could think of, and in the end I got to these 2 options: A-apply the legend to figure; B-apply the legend to the last axis.
Option A works pretty well for 3 subplots:
In Option B (adding the legend to last axis), that I tried to force the legend to be the same width of the axis, the legends appear on top of each other (although I tried to finetune the bbox_to_anchor properties).
Yet, the biggest problem is when I use a greater number of subplots (e.g. 9 which is the maximum). For these case none of the options work.
Option A:
Option B:
Is there any way that I can make it work for different numbers of subplots, while (ideally) keeping the width of the legends the same as the width of the axis?
To align the legend in the subplot, I would need to set the transform coordinate axis of the legend box. In this case, the settings are added to match the last axis of the subplot. The box values were adjusted manually.
Since the box value parameters are bbox_to_anchor=(x0,y0,x1,y1), in this case y0,y1 are the same value.
import matplotlib.pyplot as plt
list_variations = [0, 1, 2, 3, 4, 5, 6, 7, 8] # Does not work for any option
#list_variations = [0, 1, 2] # Works Fine for Option A
n_subplots = len(list_variations)
fig_size = (5.457, n_subplots*3.5/3)
fig, axs = plt.subplots(n_subplots, 1, figsize=fig_size, sharex=True, sharey=True)
labels_upp = ('abdications', 'liner wint.ol.:$\\pm$0.19e', 'liner wint.ol.:$\\pm$0.1e')
labels_low = ('apportions', 'bisections', 'ablations', 'saktis')
for idx in list_variations:
for i, lab_upp in enumerate(labels_upp):
axs[idx].plot(60+i, 0.2, label=lab_upp)
for lab_low in labels_low:
axs[idx].plot(60+i, -0.2, label=lab_low)
axs[idx].set_title(f'Variation {idx}', fontsize=8)
axs[-1].set_xlim((60, 80))
axs[-1].set(ylim=(-1, 1))
axs[-1].set(xlabel='elasticity (e)')
plt.subplots_adjust(hspace=0.25)
# Make Legends (PROBLEM IS HERE)
# # Option A - relative to fig
props_leg_upp = dict(facecolor='white', bbox_to_anchor=(-0.1, -0.350, 1.2, 0.-0.350), mode='expand', loc='upper center')
props_leg_low = dict(facecolor='lightgrey', bbox_to_anchor=(-0.1, -0.650, 1.2, -0.650), mode='expand', loc='upper center')
upper_leg = fig.legend(labels_upp, ncol=len(labels_upp), bbox_transform=axs[-1].transAxes, **props_leg_upp)
lower_leg = fig.legend(labels_low, ncol=len(labels_low), bbox_transform=axs[-1].transAxes, **props_leg_low)
axs[-1].add_artist(upper_leg)
plt.show()
If you enable the following: list_variations = [0, 1, 2]
Related
I am currently trying to create a heatmap to represent a set of data that is currently stored in a matrix of numerial values. However each row of the matrix is also tied to a specific date value, which I would like to represent on the y-axis tick labels. I currently have some code to do this that looks a little like this:
matrix = [[5, 9, 0, 4],
[0, 8, 3, 6],
[9, 1, 0, 4],
[0, 0, 3, 1]]
dates = [datetime.today() - timedelta(weeks=x * random.getrandbits(2)) for x in range(4)]
x_labels = ['Y29K', 'D950N', 'D142G', 'T95I']
title = 'Example Heatmap'
cbtitle = 'Mutation Count'
fig, ax = plt.subplots()
im = ax.imshow(matrix)
# Implement colorbar
max_val = round(int(np.max(matrix))/10)*10
color_bar_rnge = np.linspace(0,max_val,10, endpoint=False)
cb = fig.colorbar(im, ticks=color_bar_rnge)
cb.ax.set_title(cbtitle)
# Show all x axis ticks and label them with the respective list entries
ax.set_xticks(np.arange(len(x_labels)), labels=x_labels)
m_dates = mdates.date2num(dates)
ax.set_yticks(np.arange(len(m_dates)), labels=m_dates)
ax.yaxis_date()
# Rotate the tick labels and set their alignment.
plt.setp(ax.get_xticklabels(), rotation=90, ha="right",
rotation_mode="anchor")
dx, dy = -6, 0
offset = ScaledTranslation(dx / fig.dpi, dy / fig.dpi, fig.dpi_scale_trans)
for label in ax.xaxis.get_majorticklabels():
label.set_transform(label.get_transform() + offset)
ax.yaxis.set_major_formatter(mdates.DateFormatter('%Y-%m'))
ax.set_title(title)
fig.tight_layout()
fig.show()
However for some reason the resulting output seems to label dates on the y-axis as being in the 1970s. This issue only arrises when I implement:
ax.yaxis.set_major_formatter(mdates.DateFormatter('%Y-%m'))
However I would like to format my dates in this way as my real data set contains hundreds of dates (with multiple dates per month) and so labelling each tick with an individual date value creates an extremely overcrowded set of labels on the y-axis. Is there anyway to format just the date y_tick labels to be annotated in monthly increments, or does anyone know a potentially better solution to plot this sort of data?
Many thanks
One way to get rid of the 1970 year is to convert the randomly generated dates to string list and use that as the labels using set_yticklabels(). After you create the dates, you can convert the list of dates to string using dateLabels = [date.strftime('%Y-%m') for date in dates]. But, do note that all months are likely to be close or same. You can add -%d to see the date as well. Add ax.set_yticklabels(dateLabels) at the end to replace labels with this list.
Note that I have had to make a couple of other changes like set_xticks(), set_yticks() and split them to include set_xticklables(), set_yticklabels() as your code was not running on my version. Please do check if all your code is required, as some might not be required anymore.
Full code below.
import matplotlib.transforms as transforms
matrix = [[5, 9, 0, 4],
[0, 8, 3, 6],
[9, 1, 0, 4],
[0, 0, 3, 1]]
dates = [datetime.today() - timedelta(weeks=x * random.getrandbits(2)) for x in range(4)]
dateLabels = [date.strftime('%Y-%m') for date in dates]
print(dateLabels)
x_labels = ['Y29K', 'D950N', 'D142G', 'T95I']
title = 'Example Heatmap'
cbtitle = 'Mutation Count'
fig, ax = plt.subplots()
im = ax.imshow(matrix)
# Implement colorbar
max_val = round(int(np.max(matrix))/10)*10
color_bar_rnge = np.linspace(0,max_val,10, endpoint=False)
cb = fig.colorbar(im, ticks=color_bar_rnge)
cb.ax.set_title(cbtitle)
# Show all x axis ticks and label them with the respective list entries
ax.set_xticks(np.arange(len(x_labels)))
ax.set_xticklabels(x_labels)
m_dates = mdates.date2num(dates)
ax.set_yticks(np.arange(len(m_dates)))
ax.yaxis_date()
# Rotate the tick labels and set their alignment.
plt.setp(ax.get_xticklabels(), rotation=90, ha="right",
rotation_mode="anchor")
dx, dy = -6, 0
offset = transforms.ScaledTranslation(dx / fig.dpi, dy / fig.dpi, fig.dpi_scale_trans)
for label in ax.xaxis.get_majorticklabels():
label.set_transform(label.get_transform() + offset)
#ax.yaxis.set_major_formatter(mdates.DateFormatter('%Y-%m'))
ax.set_yticklabels(dateLabels)
ax.set_title(title)
fig.tight_layout()
fig.show()
Output
['2022-07', '2022-07', '2022-06', '2022-06']
I'm trying to use a custom colorbar in matplotlib with irregular intervals.
But when following the tutorial and using the colorbar, it gets used as a regular interval colorbar.
How do I construct/use a colorbar with irregular intervals?
MWE below:
I'm plotting various data with plt.matshow(), like this:
testdf = pd.DataFrame([
(7, 7.1, 8 , 9),
(0, 1, 1.5, 2),
(2.001, 3, 3.5, 4),
(4.001, 5, 6, 6.9999),
], index=[0, 1, 2, 3], columns=('A', 'B', 'C', 'D'),)
and
plt.matshow(testdf)
However, I want only certain numbers highlighted and I want to group others, i.e. I want a discrete, custom colorbar, instead of the default continuous one.
Luckily, the matplotlib documentation has just what I need.
So, lets set up this colorbar:
fig, ax = plt.subplots(figsize=(6, 1))
fig.subplots_adjust(bottom=0.5)
cmap = (mpl.colors.ListedColormap(['red', 'green', 'blue', 'cyan'])
.with_extremes(over='0.25', under='0.75'))
bounds = [1, 2, 4, 7, 8]
norm = mpl.colors.BoundaryNorm(bounds, cmap.N)
fig.colorbar(
mpl.cm.ScalarMappable(cmap=cmap, norm=norm),
cax=ax,
boundaries=[0] + bounds + [13], # Adding values for extensions.
extend='both',
ticks=bounds,
spacing='proportional',
orientation='horizontal',
label='Discrete intervals, some other units',
)
Looks great! Numbers from 1 to 2 in red and 7 to 8 in blue and two large groups for all the uninteresting stuff between 2 and 7.
So, let's use it.
plt.matshow(testdf, cmap=cmap)
plt.colorbar()
...and that's not what I expected.
The colorbar should look like the one I just constructed before, not regularly spaced and thus lines 0 and 1 should contain a black/grey box for over/under, line 2 should be all green and line 3 all blue.
How do I fix this? What am I missing?
As Jody Klymak and JohanC have pointed out in the comments, norm also needs to be passed into matshow, i.e. plt.matshow(testdf, cmap=cmap, norm=norm).
However, this doesn't work for stuff where I can't pass further arguments with my colormap (or where I can't figure out how to do so…), e.g. in sns.clustermap.
A possible workaround is to define a colormap with regular intervals, with many following intervals being of the same color:
fig, ax = plt.subplots(figsize=(6, 1))
fig.subplots_adjust(bottom=0.5)
cmap = (mpl.colors.ListedColormap(['red',
'green', 'green',
'blue', 'blue', 'blue', 'blue',
'cyan'])
.with_extremes(over='0.25', under='0.75'))
bounds = [1, 2, 3, 4, 5, 6, 7, 8]
norm = mpl.colors.BoundaryNorm(bounds, cmap.N)
fig.colorbar(
mpl.cm.ScalarMappable(cmap=cmap, norm=norm),
cax=ax,
boundaries=[0] + bounds + [13], # Adding values for extensions.
extend='both',
ticks=bounds,
spacing='proportional',
orientation='horizontal',
label='Discrete intervals, some other units',
)
Results in
and following that
As you can see, it's still different from what I expected in the question, but turns out that the limits are different from what I expected them to be, i.e. the interval 1, 2 means >1, <2which is easily fixable, if you know/expect this behaviour.
I'm trying to dynamically append axes to a matplotlib figure. In my case, I don't know beforehand how many rows must be drawn/generated. So, In my case, I have a generator method that generates a row number, each call plot_history suppose to generate a row with two columns.
So it should incrementally append a row for each call. show() called later in the code
when all N sub_plot generated.
The logic in code that intended.
add ax1/ax2
ax1 = fig.add_subplot(row_num, 1, 1). ( row = 1, col 1 , pos 1)
ax2 = fig.add_subplot(row_num, 2, 2). ( row = 1, col 2, pos 2)
next call
ax1 = fig.add_subplot(row_num, 1, 1). ( row = 2, col 1 , pos 1)
ax2 = fig.add_subplot(row_num, 2, 2). ( row = 2, col 2, pos 2)
Question. I'm not sure maybe it is my misinterpretation of matplotlib doc. It looks like the code is correct but matplotlib show() doesn't render anything. (my understanding show() method generally blocking call so it should block at the end and render and add_subplot suppose append each ax_n to the same figure object). Can someone please explain?
Code below.
def plot_history(fig: matplotlib.figure.Figure, hs: History):
"""
:param fig: is matplotlib.figure.Figure
:param hs: Keras history
:return:
"""
# generator generate from 1 to infinity
row_num = next(row_num_generator)
ax1 = fig.add_subplot(row_num, 1, 1)
try:
ax1.plot(hs.history['accuracy'])
ax1.plot(hs.history['val_accuracy'])
except KeyError:
ax1.plot(hs.history['acc'])
ax1.plot(hs.history['val_acc'])
ax1.title.set_text('Accuracy vs. epochs')
ax1.set_ylabel('Loss')
ax1.set_xlabel('Epoch')
ax1.legend(['Training', 'Validation'], loc='lower right')
ax2 = fig.add_subplot(row_num, 2, 2)
ax2.title.set_text('Loss vs. epochs')
ax2.plot(hs.history['loss'])
ax2.plot(hs.history['val_loss'])
ax2.set_ylabel('Loss')
ax2.set_xlabel('Epoch')
ax2.legend(['Training', 'Validation'], loc='upper right')
def main():
main_figure = plt.figure()
# compute01 will do a work, call plot_history,
# it will add History and call it.
compute01(main_figure)
# compute02 will do a work, call plot_history,
# it will add History and call it.
compute02(main_figure)
...
...
compute0_N(main_figure)
main_figure.show()
Thank you very much.
I am trying to recreate the look of figure below using matplotlib (source).
However, I am having issues with the placement of the ylabel. I want it at the top of the y-axis, as it is on the figure. I have tried setting its position with ax.yaxis.set_label_position(), but this only accepts left or right for the y-axis. Is there an option to control the position of the ylabel, or should I just use ax.text and set the text's position manually?
EDIT: As it turns out, the ax.set_ylabel(position=(x,y)) sets the position of the label relative to the graph coordinates. However, because of its horizontal rotation, the label is a little too much to the right, and position(x,y) does not seem to accept negative inputs. Is there a way to move the label a little to the left?
I include the code used to generate the skeleton of the figure here, even though it's rather messy.
import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np
mpl.rcParams['text.usetex'] = True
mpl.rcParams['text.latex.preamble'] = [r"\usepackage[charter]{mathdesign}"]
mpl.rcParams['font.family'] = ['serif']
mpl.rcParams['font.size'] = 10
nb_procs = np.array([1, 2, 4, 12, 24, 48, 96, 192, 384])
def adjust_spines(ax, spines):
for loc, spine in ax.spines.items():
if loc in spines:
spine.set_position(('outward', 10)) # outward by 10 points
spine.set_smart_bounds(True)
else:
spine.set_color('none') # don't draw spine
# turn off ticks where there is no spine
if 'left' in spines:
ax.yaxis.set_ticks_position('left')
else:
# no yaxis ticks
ax.yaxis.set_ticks([])
if 'bottom' in spines:
ax.xaxis.set_ticks_position('bottom')
else:
# no xaxis ticks
ax.xaxis.set_ticks([])
# -- We create the figure.
figPres = plt.figure(figsize=(3,1.75))
axPres = figPres.add_subplot(111)
# -- We remove any superfluous decoration.
# Remove the axis decorations on the right and on the top.
axPres.spines['top'].set_visible(False)
axPres.spines['right'].set_visible(False)
# Make the remaining spines a light gray.
axPres.spines['bottom'].set_color('gray')
axPres.spines['left'].set_color('gray')
adjust_spines(axPres, ['left', 'bottom'])
# -- Set the x ticks.
axPres.set_xscale('log')
axPres.set_xlim((0.75,500))
axPres.set_xticks((nb_procs))
axPres.set_xticklabels( (r'1', r'2', r'4', r'12', r'24', r'48', r'96', r'192', r'384'), color='gray' )
axPres.xaxis.set_ticks_position('bottom')
for tic in axPres.xaxis.get_major_ticks():
tic.tick1On = tic.tick2On = False
# -- Set the y ticks.
axPres.set_ylim((0,1))
axPres.set_yticks((0.0,0.5,1.0))
axPres.set_yticklabels((r'0', '', r'1'))
axPres.yaxis.set_ticks_position('left')
axPres.tick_params(axis='y', colors='gray')
#for tac in axPres.yaxis.get_major_ticks():
# tac.tick1On = tac.tick2On = False
for toc in axPres.xaxis.get_minor_ticks():
toc.tick1On = toc.tick2On = False
# -- Set the titles of the axes.
axPres.set_ylabel(r"Efficacit\'e", color='gray', rotation='horizontal')
axPres.yaxis.set_label_position('right')
axPres.set_xlabel(r"Nombre de processeurs", color='gray')
plt.show()
You can move the ylabel using ax.yaxis.set_label_coords, which does accept negative numbers. For your example, I removed the line with set_label_position, and added:
axPres.yaxis.set_label_coords(-0.1,1.02)
It seems like the 3.5 version of matplotlib doesn't support the yaxis any more. I have found a workaround that gives similar result
axPres.set_ylabel(r"Efficacit\'e", loc="top", rotation="horizontal")
Some methods have meanwhile been deprecated. Here is a more recent approach.
I moved most of the style-options to the global style parameters.
You can find a list of available parameters with descriptions here.
I hope the rest is self-explanatory.
import matplotlib.pyplot as plt
import numpy as np
# Alternative: plt.rc_context()
plt.rcParams.update({
'figure.constrained_layout.use': True,
'font.size': 12,
'axes.edgecolor': 'gray',
'xtick.color': 'gray',
'ytick.color': 'gray',
'axes.labelcolor':'gray',
'axes.spines.right':False,
'axes.spines.top': False,
'xtick.direction': 'in',
'ytick.direction': 'in',
'xtick.major.size': 6,
'xtick.minor.size': 4,
'ytick.major.size': 6,
'ytick.minor.size': 4,
'xtick.major.pad': 15,
'xtick.minor.pad': 15,
'ytick.major.pad': 15,
'ytick.minor.pad': 15,
})
X = np.linspace(-2,2,500)
Y = np.exp(-X**2)
# Generate Sample Points
Sx = np.random.choice(X, 31)
Sy = np.exp(-Sx**2) + np.random.normal(scale=.02, size=31)
fig, ax = plt.subplots( figsize=(6,4) )
# Disjoin bottom / left spines by moving them outwards
ax.spines[['bottom', 'left']].set_position(('outward', 20))
# Set axis / spine lengths
ax.spines['bottom'].set_bounds(Sx.min(), Sx.max())
ax.spines['left'].set_bounds(0, Sy.max())
ax.set_yticks( ticks=[0, Sy.max()], labels=['0', '650 mW'])
ax.set_yticks( ticks=[(Sy.max()+Sy.min())/2], labels=[''], minor=True )
ax.set_xticks( ticks=[Sx.min(), Sx.max()], labels=['16', '19'])
ax.set_xticks( ticks=[0], labels=['17.2 GHz'], minor=True)
ax.set_ylabel('Output power', ha='left', y=1, rotation=0, labelpad=0)
ax.plot(X,Y, color='orange')
ax.plot(Sx, Sy, marker='o', markersize=3, linestyle='', color='black')
fig.savefig('so.png', dpi=300, bbox_inches='tight')
I'd like to have four plots with images. All channels, and one for Red, Green and Blue channel. For RGB I'd like to plot a color profile across columns and rows. I would like to have the profile plots aligned exactly to the corresponding image. I mean their width and length should match to width and length, of an image. Their heights should be equal.
For now I achieved this effect using GridSpec. I know I can manipualte by changing fig size proportions, but it is not the solution. I need exact fit.
Here is my code.
def show_signal_across_image(self):
fig = plt.figure(figsize=(8, 9), dpi=109)
gs = GridSpec(4, 4,
height_ratios=[10, 2, 10, 2],
width_ratios=[10, 2, 10, 2],
left=0.05,
right=1 - 0.03,
top=0.95,
bottom=0.06,
hspace=0.3,
wspace=0.4)
ax_all = fig.add_subplot(gs[0])
ax_red_img = fig.add_subplot(gs[2])
ax_green_img = fig.add_subplot(gs[8])
ax_blue_img = fig.add_subplot(gs[10])
ax_red_signal_horizontal = fig.add_subplot(gs[6], sharex=ax_red_img)
ax_red_signal_vertical = fig.add_subplot(gs[3], sharey=ax_red_img)
ax_green_signal_horizontal = fig.add_subplot(gs[12], sharex=ax_green_img)
ax_green_signal_vertical = fig.add_subplot(gs[9], sharey=ax_green_img)
ax_blue_signal_horizontal = fig.add_subplot(gs[14], sharex=ax_blue_img)
ax_blue_signal_vertical = fig.add_subplot(gs[11], sharey=ax_blue_img)
signals = self.get_signal_values()
red_horizontal, red_vertical, green_horizontal, green_vertical, blue_horizontal, blue_vertical = signals
horizontal_signals = [red_horizontal, green_horizontal, blue_horizontal]
vertical_signals = [red_vertical, green_vertical, blue_vertical]
max_value_horizontal = max([item for sublist in horizontal_signals for item in sublist])
max_value_vertical = max([item for sublist in vertical_signals for item in sublist])
ax_red_signal_horizontal.plot(red_horizontal)
ax_green_signal_horizontal.plot(green_horizontal)
ax_blue_signal_horizontal.plot(blue_horizontal)
ax_red_signal_vertical.plot(red_vertical, np.arange(len(red_vertical)))
ax_green_signal_vertical.plot(green_vertical, np.arange(len(green_vertical)))
ax_blue_signal_vertical.plot(blue_vertical, np.arange(len(blue_vertical)))
ax_red_signal_vertical.invert_xaxis()
ax_green_signal_vertical.invert_xaxis()
ax_blue_signal_vertical.invert_xaxis()
for ax in [ax_red_signal_horizontal, ax_green_signal_horizontal, ax_blue_signal_horizontal]:
ax.set_ylim(0, max_value_horizontal * 1.1)
for ax in [ax_red_signal_vertical, ax_green_signal_vertical, ax_blue_signal_vertical]:
ax.set_xlim(max_value_vertical * 1.1, 0)
imshow_args = dict(vmin=0, vmax=1, cmap='gray')
plt.subplot(ax_all)
plt.title('All channels')
plt.imshow(self.img, **imshow_args)
plt.subplot(ax_red_img)
plt.title('Red')
plt.imshow(self.red, **imshow_args)
plt.subplot(ax_green_img)
plt.title('Green')
plt.imshow(self.green, **imshow_args)
plt.subplot(ax_blue_img)
plt.title('Blue')
plt.imshow(self.blue, **imshow_args)
plt.show()
I'm using matplotlib 3.1.1 and python 3.7.1.