CF84 CF84 - 5 months ago 53
Python Question

Python: How to nest plt.imshow() in a For loop?

I am a Pythonic newbie. I have a code which produces a 256x256 matrix and plots it by means of

pyplot
and
plt.imshow()
. Now, I want to produce n subplots of the same 256x256 matrix by using a smaller matrix, this time 101x101, which serves as a moving window. Visually, I would like to get something like this (after having decided the number of subplots and the locations of their origins.

In the end, I would like to have a set of n+1 images plotted in separate figures: one for the 256x256 matrix, and n for the moving windows.
The code I have right now boils all images down to one. As you can see here, in an attempt to plot n+1=3 matrices, there is just one matrix plotted, the last one, all my colorbars are stacked up, and my text strings are not readable.

How can I nest the
plt.imshow()
call inside a for loop, so that Python gives me n+1 figures? I hope to have made things clear here. Thank you to anyone who will provide guidance!

This is my current code:

from __future__ import division #Avoids the floor of the mathematical result of division if the args are ints or longs
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors as mc
import SSFM2D
import random


#Parameter assignments
max_level=8 #This is the exponent controlling the grid size. In this case N=2^8=256. Use only integers.
N=2**max_level
sigma=1 #Variation for random Gauss generation (standardised normal distribution)
H=0.8 #Hurst exponent (0.8 is a recommended value for natural phenomena)
seed = random.random() #Setting the seed for random Gauss generation
print ('The lattice size is '+str(N)+'x'+str(N))


#Lattice initialization
Lattice=np.zeros((256,256))


#Calling Spectral fBm function
Lattice=SSFM2D.SpectralSynthesisFM2D(max_level, sigma, H, seed, normalise=True, bounds=[0,1])


#Plotting the original 256x256 lattice
M=np.zeros((257,257))
for i in range(0,256):
for j in range(0,256):
M[i][j]=Lattice[i][j]


#Normalizing the output matrix
print ('Original sum: '+str(round(M[-257:,-257:].sum(),3)))
M = M/M[-257:, -257:].max() #Matrix normalization with respect to max


#Lattice statistics
print ('Normalized sum: '+str(round(M[-257:,-257:].sum(),3)))
print ('Normalized max: '+str(round(M[-257:,-257:].max(),3)))
print ('Normalized min: '+str(round(M[-257:,-257:].min(),3)))
print ('Normalized avg: '+str(round(M[-257:,-257:].mean(),3)))


#Determining the footprint
footprint=0 #Initializing the footprint count variable
for i in range(M.shape[0]):
for j in range(M.shape[1]):
if M[i][j]>0.15: # Change here to set the failure threshold
footprint=footprint+1
print ('Event footprint: '+str(round(footprint*100/(256*256),2))+'%')


#Plotting the 256x256 "mother" matrix
plt.imshow(M[-257:,-257:].T, origin='lower',interpolation='nearest',cmap='Reds', norm=mc.Normalize(vmin=0,vmax=M.max()))
title_string=('Spatial Loading of a Generic Natural Hazard')
subtitle_string=('Inverse FFT on Spectral Synthesis')
plt.suptitle(title_string, y=0.99, fontsize=17)
plt.title(subtitle_string, fontsize=8)
plt.show()
#Making a custom list of tick mark intervals for color bar (assumes minimum is always zero)
numberOfTicks = 5
ticksListIncrement = M.max()/(numberOfTicks)
ticksList = []
for i in range((numberOfTicks+1)):
ticksList.append(ticksListIncrement * i)
plt.tick_params(axis='x', labelsize=8)
plt.tick_params(axis='y', labelsize=8)
cb=plt.colorbar(orientation='horizontal', format='%0.2f', ticks=ticksList)
cb.ax.tick_params(labelsize=8)
cb.set_label('Loading',fontsize=12)
plt.show()
plt.xlim(0, 255)
plt.xlabel('Easting (Cells)',fontsize=12)
plt.ylim(255, 0)
plt.ylabel('Northing (Cells)',fontsize=12)
plt.annotate('fractional Brownian motion on a 256x256 lattice | H=0.8 | Dim(f)= '+str(3-H), xy=(0.5,0), xycoords=('axes fraction', 'figure fraction'), xytext=(0, 0.5), textcoords='offset points', size=10, ha='center', va='bottom')
plt.annotate('Max: '+str(round(M[-257:,-257:].max(),3))+' | Min: '+str(round(M[-257:,-257:].min(),3))+' | Avg: '+str(round(M[-257:,-257:].mean(),3))+' | Footprint: '+str(round(footprint*100/(256*256),2))+'%', xy=(0.5,0), xycoords=('axes fraction', 'figure fraction'), xytext=(0, 15), textcoords='offset points', size=10, ha='center', va='bottom')


#Producing the 101x101 image(s)
numfig=int(raw_input('Insert the number of 101x101 windows to produce: '))
N=np.zeros((101,101))
x=0 #Counts the iterations towards the chosen number of images
for x in range (1,numfig+1):
print('Image no. '+str(x)+' of '+str(numfig))
north=int(raw_input('Northing coordinate (0 thru 155, integer): '))
east=int(raw_input('Easting coordinate (0 thru 155, integer): '))
for i in range(101):
for j in range(101):
N[i][j]=M[north+i][east+j]
#Writing X, Y and values to a .csv file from scratch
import numpy
import csv
with open('C:\\Users\\Francesco\\Desktop\\Python_files\\csv\\fBm_101x101_'+str(x)+'of'+str(numfig)+'.csv', 'w') as f: #Change directory if necessary
writer = csv.writer(f)
writer.writerow(['X', 'Y', 'Value'])
for (x, y), val in numpy.ndenumerate(M):
writer.writerow([x, y, val])

#Plotting the 101x101 "offspring" matrices
plt.imshow(N[-101:,-101:].T, origin='lower',interpolation='nearest',cmap='Reds', norm=mc.Normalize(vmin=0,vmax=M.max()))
title_string=('Spatial Loading of a Generic Natural Hazard')
subtitle_string=('Inverse FFT on Spectral Synthesis | Origin in the 256x256 matrix: '+str(east)+' East; '+str(north)+' North')
plt.suptitle(title_string, y=0.99, fontsize=17)
plt.title(subtitle_string, fontsize=8)
plt.show()
#Making a custom list of tick mark intervals for color bar (assumes minimum is always zero)
numberOfTicks = 5
ticksListIncrement = M.max()/(numberOfTicks)
ticksList = []
for i in range((numberOfTicks+1)):
ticksList.append(ticksListIncrement * i)
plt.tick_params(axis='x', labelsize=8)
plt.tick_params(axis='y', labelsize=8)
cb=plt.colorbar(orientation='horizontal', format='%0.2f', ticks=ticksList)
cb.ax.tick_params(labelsize=8)
cb.set_label('Loading',fontsize=12)
plt.show()
plt.xlim(0, 100)
plt.xlabel('Easting (Cells)',fontsize=12)
plt.ylim(100, 0)
plt.ylabel('Northing (Cells)',fontsize=12)
plt.annotate('fractional Brownian motion on a 101x101 lattice | H=0.8 | Dim(f)= '+str(3-H), xy=(0.5,0), xycoords=('axes fraction', 'figure fraction'), xytext=(0, 0.5), textcoords='offset points', size=10, ha='center', va='bottom')
plt.annotate('Max: '+str(round(N[-101:,-101:].max(),3))+' | Min: '+str(round(N[-101:,-101:].min(),3))+' | Avg: '+str(round(N[-101:,-101:].mean(),3))+' | Footprint: '+str(round(footprint*100/(101*101),2))+'%', xy=(0.5,0), xycoords=('axes fraction', 'figure fraction'), xytext=(0, 15), textcoords='offset points', size=10, ha='center', va='bottom')

Answer

The following code shows the main figure, and then it shows different "zoom" windows, according to the values of nx and ny.

import numpy as np
import matplotlib.pyplot as plt
import random

Lattice = np.random.normal(size=(256,256))

f = plt.imshow( Lattice )
plt.show()

nx = 4
ny = 2

for i in range(nx):
    for j in range(ny):
        f = plt.imshow( Lattice )
        f.axes.set_xlim( [ i*256/nx, (i+1)*256/nx ] )
        f.axes.set_ylim( [ j*256/ny, (j+1)*256/ny ] )
        plt.show()