I am using Matplotlib to create an image based on some data. All of the data falls in the range of 0 through to 1 and I am trying to color the data based on its value using a colormap and this works perfectly in Matlab, however when converting the code across to Python I simply get a black square as the output. I believe this is because I’m plotting the image wrong and so it is plotting all the data as 0. I have tried searching this problem for several hours and I have tried plt.set_clim([0, 1]) however that didn’t seem to do anything. I am new to Python and Matplotlib, although I am not new to programming (Java, javascript, PHP, etc), but I cannot see where I am going wrong. If any body can see anything glaringly incorrect in my code then I would be extremely grateful.
Thank you
from numpy import *
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.colors as myColor
e1cx=[]
e1cy=[]
e1cz=[]
print("Reading files...")
in_file = open("eigenvector_1_component_x.txt", "rt")
for line in in_file.readlines():
e1cx.append([])
for i in line.split():
e1cx[-1].append(float(i))
in_file.close()
in_file = open("eigenvector_1_component_y.txt", "rt")
for line in in_file.readlines():
e1cy.append([])
for i in line.split():
e1cy[-1].append(float(i))
in_file.close()
in_file = open("eigenvector_1_component_z.txt", "rt")
for line in in_file.readlines():
e1cz.append([])
for i in line.split():
e1cz[-1].append(float(i))
in_file.close()
print("...done")
nx = 120
ny = 128
nz = 190
fx = zeros((nz,nx,ny))
fy = zeros((nz,nx,ny))
fz = zeros((nz,nx,ny))
z = 0
while z<nz-1:
x = 0
while x<nx:
y = 0
while y<ny:
fx[z][x][y]=e1cx[(z*128)+y][x]
fy[z][x][y]=e1cy[(z*128)+y][x]
fz[z][x][y]=e1cz[(z*128)+y][x]
y += 1
x += 1
z+=1
if((z % 10) == 0):
plt.figure(num=None)
plt.axis("off")
normals = myColor.Normalize(vmin=0,vmax=1)
plt.pcolor(fx[z][:][:],cmap='spectral', norm=normals)
filename = 'Imagex_%d' % z
plt.savefig(filename)
plt.colorbar(ticks=[0,2,4,6], format='%0.2f')
Although you have resolved your original issue and have code that works, I wanted to point out that both python and numpy provide several tools that make code like this much simpler to write. Here are a few examples:
Loading data
Instead of building up lists by appending to the end of an empty one, it is often easier to generate them from other lists. For example, instead of
you can simply write:
The syntax
[x(y) for y in l]is known as a list comprehension, and, in addition to being more concise will execute more quickly than aforloop.However, for loading tabular data from a text file, it is even simpler to use
numpy.loadtxt:for more information,
See also, its slightly more sophisticated cousin
numpy.genfromtxtReshaping data
Now that we have our data loaded, we need to reshape it. The while loops you use work fine, but
numpyprovides an easier way. First, if you prefer to use your method of loading the data, then convert your eigenvector arrays into proper numpy arrays usinge1cx = array(e1cx), etc.The
arrayclass provides methods for rearranging how the data in an array is indexed without requiring it to be copied. The simplest method isarray.reshape, which will do half of what yourwhileloops do:Here,
almost_fxis a rank-3 array indexed asalmost_fx[iz,iy,ix]. One important thing to be aware of is thate1cxandalmost_fxshare their data. So, if you changee1cx[0,0], you will also changealmost_fx[0,0,0].In your code, you swapped the x and y locations. If this is indeed what you wanted to do, you can accomplish this with
array.swapaxes:Of course, you could always combine this into one line
However, if you want the z-slices (
fx[z,:,:]) to plot with x horizontal and y vertical, you probably do not want to swap the axes above. Just reshape and plot.Slicing arrays
Finally, rather than looping over the z-index and testing for multiples of 10, you can loop directly over a slice of the array using:
This indexing syntax is
array[start:end:step]wherestartis included in the resultendis not. Leavingstartblank implies 0, while leavingendblank implies the end of the list.Summary
In summary your complete code (after introducing a few more python idioms like
enumerate) could look something like:Alternatively, if you want one pixel per element, you can replace the body of the
forloop with