Overlapping text when saving multiple Matplotlib images with text in a loop - python

I created this randomly-valued/coloured 'chessboard':
with the code:
rndm = np.random.rand(8,8)
my_cmap = plt.get_cmap('gray')
plt.figure(figsize=(5,4))
plt.imshow(rndm, cmap=my_cmap, interpolation = 'none')
plt.axis('off')
plt.show()
I wanted to apply a function to the values in a loop, for example raising all values in the array to an increasing power, and then show all in different subplots. Here's the code:
fig, axs = plt.subplots(2,2, figsize=(10, 10))
axs = axs.ravel()
for i, n in zip(np.arange(4), np.arange(2,6)):
axs[i].imshow(np.power(rndm, n), cmap=my_cmap, interpolation = 'none')
axs[i].axis('off')
axs[i].text(1, 1, str(n), fontsize=14, color = 'y')
and the result:
But what I would really like is to cycle through 4 colormaps, for example:
cmaps = ['viridis', 'inferno', 'plasma', 'magma']
fig, axs = plt.subplots(2,2, figsize=(10, 10))
axs = axs.ravel()
for i, n in zip(np.arange(4), np.arange(2,6)):
axs[i].imshow(np.power(rndm, n), cmap=cmaps[i], interpolation = 'none')
axs[i].axis('off')
axs[i].text(1, 1, str(n), fontsize=14, color = 'y')
Good. But here's where my code breaks. I want to save these as individual images.
I wrote this, which is fine except for the fact that the text numbers end up superimposed:
for i, n in zip(np.arange(4), np.arange(2,6)):
plt.imshow(np.power(rndm, n), cmap=cmaps[i], interpolation = 'none')
plt.axis('off')
plt.text(1, 1, str(n), fontsize=14, color = 'y')
plt.savefig("test_n = " + str(n) +".png", dpi=300, bbox_inches='tight', pad_inches=0)
How do I clear them each time?

Shouldn't you use cmaps[i] instead of cmap=my_cmap?
Create a figure in each loop using plt.figure() and it'll work correctly (tested).
for i, n in zip(np.arange(4), np.arange(2,6)):
plt.figure()
plt.imshow(np.power(rndm, n), cmap=cmaps[i], interpolation = 'none')
plt.axis('off')
plt.text(1, 1, str(n), fontsize=14, color = 'y')
plt.savefig("test_n = " + str(n) +".png", dpi=300, bbox_inches='tight', pad_inches=0)
result:
The main image (not saved) :
-Saved images:
Note that the labels starts from 2 because of this line :
plt.text(1, 1, str(n), fontsize=14, color = 'y')
If you want it start from 1 , change str(n) to str(i).

Related

Adding a stacked plot as a subplot in python

Please I need help with a plot. I am making a 3x3 dimension figure containing 7 subplots. I want two(2) of the subplots (ax6 and ax7) to be stacked plots. Does anyone have an idea how I can make this work? I used the code below to make the grid.
fig = plt.figure()
fig.set_figheight(8)
fig.set_figwidth(10)
gs = gridspec.GridSpec(3, 3)
ax1 = plt.subplot(gs[0, 0])
ax2 = plt.subplot(gs[0, -2])
ax3 = plt.subplot(gs[0, -1])
ax4 = plt.subplot(gs[1, 0])
ax5 = plt.subplot(gs[-1, 0])
ax6 = plt.subplot(gs[1:, -2])
ax7 = plt.subplot(gs[1:, -1])
I tried making the stacked plot for ax6 using the code below
ax6[0].plot(s[['xa']], s[['ac1']], label = "Data")
ax6[0].plot(s[['xa']], s[['ac2']], label = "C-C")
ax6[0].plot(s[['xa']], s[['ac3']], label = "C-O")
ax6[0].plot(s[['xa']], s[['ac4']], label = "C=C")
ax6[0].plot(s[['xa']], s[['ea1']], label = "Envelope")
ax6[0].text(0.08, 0.70, 'C', ha='center', va='baseline', wrap=True, fontsize= 10, fontweight='bold', color='darkgreen', transform=ax6[0].transAxes)
ax6[1].plot(s[['xb']], s[['bc1']], label = "Data")
ax6[1].plot(s[['xb']], s[['bc2']], label = "C-C")
ax6[1].plot(s[['xb']], s[['bc3']], label = "C-O")
ax6[1].plot(s[['xb']], s[['bc4']], label = "C=C")
ax6[1].plot(s[['xb']], s[['be1']], label = "Envelope")
ax6[1].text(0.08, 0.70, 'm.C', ha='center', va='baseline', wrap=True, fontsize= 10, fontweight='bold', color='darkgreen', transform=ax6[1].transAxes)
Please look at the comments in the code:
import matplotlib.pyplot as plt
from matplotlib import gridspec
import numpy as np
fig = plt.figure(figsize=(10, 8))
g = gridspec.GridSpec(3, 3)
ax1 = plt.subplot(g[0, 0])
ax2 = plt.subplot(g[0, 1])
ax3 = plt.subplot(g[0, 2])
ax4 = plt.subplot(g[1, 0])
ax5 = plt.subplot(g[2, 0])
# Create another grid
g2 = gridspec.GridSpec(3, 3)
g2.update(hspace=0.00)
# Generate data for three subplots in g2
x = np.linspace(0, 2 * np.pi, 400)
ya = np.sin(x)
yb = np.cos(x)
y7 = np.sin(x) ** 2
# Get three different Axes objects
ax6a = plt.subplot(g2[1, 1])
ax6b = plt.subplot(g2[2, 1], sharex=ax6a)
ax7 = plt.subplot(g2[1:, -1])
# Hide the xticklabels of top subplot in the shared plots
plt.setp(ax6a.get_xticklabels(), visible=False)
# Set xticks for lower subplots in the shared plots
ax6b.set_xticks(np.pi * np.array([0, 1/2, 1, 3/2, 2]))
# Try plotting
ax6a.plot(x, ya)
ax6b.plot(x, yb, 'g')
ax7.plot(x, y7, 'r')
plt.tight_layout()
plt.show()
This gives:
This answer was motivated by this answer and examples from older documentation of matplotlib.
If you want ax7 (red color subplot here) represented in to two separate subplots, either create a new Gridspec or use g depending on attributes you want to assign them e.g. in the code above:
# ax7 = plt.subplot(g2[1:, -1])
# ax7.plot(x, y7, 'r')
ax7a = plt.subplot(g[1, 2])
ax7b = plt.subplot(g[2, 2])
ax7a.plot(x, y7, 'r')
ax7b.plot(x, y7, 'r')
This gives:

Set size of matplotlib subplots

I created two subplots on a MPL figure, but i'm having an hard time setting the size on them. I want the space to be splitted between the two charts, so each chart needs to have 50% of the total width of the figure, and i want them to have the same height of the figure, here is how i initialized the subplots:
fig = plt.figure(facecolor='#131722',dpi=155, figsize=(10, 3))
ax1 = plt.subplot2grid((3,3), (2,0), facecolor='#131722')
ax2 = plt.subplot2grid((5,3), (2,2), colspan=5, rowspan=4, facecolor='#131722')
Colors = [['#0400ff', '#FF0000'], ['#09ff00', '#ff8c00']]
for x in List:
Index = List.index(x)
rate_buy = []
total_buy = []
rate_sell = []
total_sell = []
for y in x['data']['asks']:
rate_sell.append(y[0])
total_sell.append(y[1])
for y in x['data']['bids']:
rate_buy.append(y[0])
total_buy.append(y[1])
rBuys = pd.DataFrame({'buy': rate_buy})
rSells = pd.DataFrame({'sell': rate_sell})
tBuys = pd.DataFrame({'total': total_buy})
tSells = pd.DataFrame({'total': total_sell})
ax1.plot(rBuys.buy, tBuys.total, color=Colors[Index][0], linewidth=0.5, alpha=1, label='test')
ax2.plot(rSells.sell, tSells.total, color=Colors[Index][1],alpha=0.5, linewidth=1, label=x['exchange'])
ax1.fill_between(rBuys.buy, 0, tBuys.total, facecolor=Colors[Index][0], alpha=0.4)
ax2.fill_between(rSells.sell, 0, tSells.total, facecolor=Colors[Index][1], alpha=0.4)
And this is what i'm getting:
use plt.tight_layout() before calling plt.show().

For loop to create multiple histogram png files

I am not sure as to why this happens. Maybe it is just a simple mistake that I cannot see, but by using this code:
for filename in glob.glob('/Users/jacob/Desktop/MERS/new/NOT COAL/gensets/statistics_per_lgu/per_lgu_files/*.csv'):
base = os.path.basename(filename)
name = os.path.splitext(base)[0]
df = pd.read_csv(filename)
# Show 4 different binwidths
for i, binwidth in enumerate([10, 20, 30, 40]):
# Set up the plot
ax = plt.subplot(2, 2, i + 1)
plt.subplots_adjust( wspace=0.5, hspace=0.5)
# Draw the plot
ax.hist(df['New Capacity based on 0.8 PF'], bins=binwidth,
color='red', edgecolor='black',alpha=0.5)
# Title and labels
ax.set_title('Histogram with Binwidth = %d' % binwidth, size=10)
ax.set_xlabel('Capacity', size=11)
ax.set_ylabel('Frequency count', size=11)
ax.axvline(x=df['New Capacity based on 0.8 PF'].median(), linestyle='dashed', alpha=0.3, color='blue')
min_ylim, max_ylim = plt.ylim()
ax.text(x=df['New Capacity based on 0.8 PF'].median(),y= max_ylim*0.9, s='Median', alpha=0.7, color='blue',fontsize = 12)
ax.axvline(x=df['New Capacity based on 0.8 PF'].mean(), linestyle='dashed', alpha=0.9, color='green')
min_ylim, max_ylim = plt.ylim()
ax.text(x=df['New Capacity based on 0.8 PF'].mean(),y= max_ylim*0.5, s='Mean', alpha=0.9, color='green',fontsize = 12)
plt.tight_layout()
plt.grid(True)
plt.savefig('/Users/jacob/Documents/Gensets_gis/historgrams/per_lgu_files/{}.png'.format(name))
I get all files created like this attached photo here.
Any ideas as to what I've done wrong?
Thanks in advance.
attached photo of one histogram output
My desired result would be something like this.
Desired output
It doesn't create new subplots but it use previous ones and then it draw new plots on old plots so you have to use clear subplot before you draw new histogram.
ax = plt.subplot(2, 2, i + 1)
ax.clear()
Example code. It gives desired output but if you remove `ax.clear() then first image will be OK but you get new plot with old plots on second and third image.
import os
import pandas as pd
import matplotlib.pyplot as plt
import random
for n in range(3):
filename = f'example_data_{n}.csv'
base = os.path.basename(filename)
name = os.path.splitext(base)[0]
df = pd.DataFrame({'New Capacity based on 0.8 PF': random.choices(list(range(1000)), k=100)})
data = df['New Capacity based on 0.8 PF']
median = data.median()
mean = data.mean()
# Show 4 different binwidths
for i, binwidth in enumerate([10, 20, 30, 40]):
# Set up the plot
ax = plt.subplot(2,2,i+1)
ax.clear() # <--- it removes previous histogram
plt.subplots_adjust( wspace=0.5, hspace=0.5)
# Draw the plot
ax.hist(data , bins=binwidth, color='red', edgecolor='black',alpha=0.5)
# Title and labels
ax.set_title('Histogram with Binwidth = %d' % binwidth, size=10)
ax.set_xlabel('Capacity', size=11)
ax.set_ylabel('Frequency count', size=11)
min_ylim, max_ylim = plt.ylim()
ax.axvline(x=median, linestyle='dashed', alpha=0.3, color='blue')
ax.text(x=median, y= max_ylim*0.9, s='Median', alpha=0.7, color='blue',fontsize = 12)
ax.axvline(x=mean, linestyle='dashed', alpha=0.9, color='green')
ax.text(x=mean, y= max_ylim*0.5, s='Mean', alpha=0.9, color='green',fontsize = 12)
plt.tight_layout()
plt.grid(True)
plt.savefig('{}.png'.format(name))

Would like to use makeaxes to plot 3 plots with 1 colorbar in matplotlib

Edit - I hope this clarifies. Below is code from this post that is very similar to what I'm trying to do.
fig, axes = plt.subplots(nrows=2, ncols=2, sharex=True, sharey=True)
for ax in axes.flat:
im = ax.imshow(np.random.random((10,10)), vmin=0, vmax=1)
cax,kw = mpl.colorbar.make_axes([ax for ax in axes.flat])
plt.colorbar(im, cax=cax, **kw)
plt.show()
Vs.
fig, axes = plt.subplots(nrows = 1, ncols = 3, sharex = True, sharey = True)
for ax, z_val, unif, rangenum in zip(axes.flat, z_vals, UI, ranges):
plot = plt.scatter(x_vals, y_vals, s = 5.5 * max(x_vals), c = z_val, cmap = 'rainbow')
if efficiency_or_not:
plot.vmin = 0
plot.vmax = 1
plot.xlabel = 'Uniformity: ' + unif
else:
plot.xlabel = 'Uniformity: ' + unif + ' ' + rangenum + ' ppm'
cax, kw = mpl.colorbar.make_axes([ax for ax in axes.flat])
plt.colorbar(plot, cax = cax, **kw)
plt.savefig('./'+ figname + '.jpg', dpi = 100)
plt.close()
What I want is 3 plots horizontally tiled and to add the colorbar below.
Original post below
I found this and I would like to use this technique....I'm having trouble translating it for my situation, though.
I have 3 separate runs that are the same type of data. I would like to take those 3 plots and turn them into one figure with one colorbar. I need to do this 5 times per report, and there is one set that I want to force the vmin and vmax on.
My current function is below...the errors I'm getting are:
plot_that_2(x_vals, y_vals, plots_list[j], plots_list[j+1], plots_list[j+2],plots_names_list[j], Plots_dictionary[plot_strings_list[i]][0],Plots_dictionary[plot_strings_list[i]][1])
cax, kw = mpl.colorbar.make_axes([ax for ax in axes.flat])
pb = parent.get_position(original=True).frozen() AttributeError: 'list' object has no attribute 'get_position'
The first objection is listed in module, the second in the program and the third in make_axes. The x, y, and z values are all lists from numpy arrays. figname is a string, units is a string, and efficiency_or_not is a Boolean.
def plot_that_2(x_vals, y_vals, z_1_vals, z_2_vals, z_3_vals, figname, units, efficiency_or_not):
UI = [uniformity_calc(z_1_vals), uniformity_calc(z_2_vals), uniformity_calc(z_3_vals)]
ranges = [ str(int(np.max(z_1_vals) - np.min(z_1_vals))), str(int(np.max(z_2_vals) - np.min(z_2_vals))), str(int(np.max(z_3_vals) - np.min(z_3_vals)))]
z_vals = [z_1_vals, z_2_vals, z_3_vals]
fig, axes = plt.subplots(nrows = 1, ncols = 3, sharex = True, sharey = True)
for ax, z_val, unif, rangenum in zip(axes.flat, z_vals, UI, ranges):
plot = plt.scatter(x_vals, y_vals, s = 5.5 * max(x_vals), c = z_val, cmap = 'rainbow')
if efficiency_or_not:
plot.vmin = 0
plot.vmax = 1
plot.xlabel = 'Uniformity: ' + unif
else:
plot.xlabel = 'Uniformity: ' + unif + ' ' + rangenum + ' ppm'
cax, kw = mpl.colorbar.make_axes([ax for ax in axes.flat])
plt.colorbar(plot, cax = cax, **kw)
plt.savefig('./'+ figname + '.jpg', dpi = 100)
plt.close()
To move the colorbar to the bottom you only have to add orientation="horizontal" or location='bottom'. By taking user1442911's example:
fig, axes = plt.subplots(nrows=1, ncols=3)
for ax in axes.flat:
im = ax.imshow(np.random.random((10,10)), vmin=0, vmax=1)
cax, kw = mpl.colorbar.make_axes([ax for ax in axes.flat], location='bottom')
plt.colorbar(im, cax=cax, **kw)
plt.show()

Drawing grid pattern in matplotlib

I would like to draw a sketch like the one below, using python with matplotlib. I guess making a grid is not so hard, but what about coloring certain squares in a specific way?
N = 15
# make an empty data set
data = np.ones((N, N)) * np.nan
# fill in some fake data
for j in range(3)[::-1]:
data[N//2 - j : N//2 + j +1, N//2 - j : N//2 + j +1] = j
# make a figure + axes
fig, ax = plt.subplots(1, 1, tight_layout=True)
# make color map
my_cmap = matplotlib.colors.ListedColormap(['r', 'g', 'b'])
# set the 'bad' values (nan) to be white and transparent
my_cmap.set_bad(color='w', alpha=0)
# draw the grid
for x in range(N + 1):
ax.axhline(x, lw=2, color='k', zorder=5)
ax.axvline(x, lw=2, color='k', zorder=5)
# draw the boxes
ax.imshow(data, interpolation='none', cmap=my_cmap, extent=[0, N, 0, N], zorder=0)
# turn off the axis labels
ax.axis('off')

Categories