After a weekend of no replies I
managed to figure a way out myself
As this was “left to the reader
as an exercise” I will leave the integration or improvement of this solution as
an exercise to the next reader
What I have done is basically
cloned the plot surface function and replaced the avgz variable with a
reference to the “colors” parameter i have added to the function call.
This code doesn’t center things
perfectly with respect to the grid (for some reason a 40x40 grid turns into
39x39 grid in the function) again this is something else that could be improved,
however I am happy with it and a one pixel shift won’t be missed in my plots. I
also have no real clue as to what the following comments was about
# The
construction leaves the array with duplicate points, which
# are removed
here.
but it is probably related to
my non centered plots.
What follows is the modified function
:
def plot_surface2(self,
X, Y, Z, colors, *args, **kwargs):
'''
Create a surface plot.
By default it will be
colored in shades of a solid color,
but it also supports
color mapping by supplying the *cmap*
argument.
==========
================================================
Argument Description
==========
================================================
*X*, *Y*, Data values
as numpy.arrays
*Z*
*colors* an array
the same size as z that contains a separate color data
*rstride* Array row
stride (step size)
*cstride* Array column
stride (step size)
*color* Color of the
surface patches
*cmap* A colormap
for the surface patches.
==========
================================================
'''
had_data =
self.has_data()
rows, cols = Z.shape
tX, tY, tZ =
np.transpose(X), np.transpose(Y), np.transpose(Z)
rstride =
kwargs.pop('rstride', 10)
cstride =
kwargs.pop('cstride', 10)
color =
kwargs.pop('color', 'b')
color =
np.array(colorConverter.to_rgba(color))
cmap =
kwargs.get('cmap', None)
polys = []
normals = []
avgz = []
for rs in np.arange(0,
rows-1, rstride):
for cs in
np.arange(0, cols-1, cstride):
ps = []
corners = []
for a, ta in
[(X, tX), (Y, tY), (Z, tZ)]:
ztop =
a[rs][cs:min(cols, cs+cstride+1)]
zleft =
ta[min(cols-1, cs+cstride)][rs:min(rows, rs+rstride+1)]
zbase =
a[min(rows-1, rs+rstride)][cs:min(cols, cs+cstride+1):]
zbase =
zbase[::-1]
zright =
ta[cs][rs:min(rows, rs+rstride+1):]
zright =
zright[::-1]
corners.append([ztop[0], ztop[-1], zbase[0], zbase[-1]])
z =
np.concatenate((ztop, zleft, zbase, zright))
ps.append(z)
# The
construction leaves the array with duplicate points, which
# are removed
here.
ps = zip(*ps)
lastp =
np.array([])
ps2 = []
avgzsum = 0.0
for p in ps:
if p !=
lastp:
ps2.append(p)
lastp =
p
avgzsum
+= p[2]
polys.append(ps2)
##################################
Begin of changes
##################################
#avgz.append(avgzsum
/ len(ps2))
avgz.append(colors[rs][cs])
##################################
end of changes
##################################
v1 =
np.array(ps2[0]) - np.array(ps2[1])
v2 =
np.array(ps2[2]) - np.array(ps2[0])
normals.append(np.cross(v1, v2))
polyc =
art3d.Poly3DCollection(polys, *args, **kwargs)
if cmap is not None:
#
polyc.set_array(np.array(colors))
polyc.set_array(np.array(avgz))
polyc.set_linewidth(0)
else:
colors =
self._shade_colors(color, normals)
polyc.set_facecolors(colors)
self.add_collection(polyc)
self.auto_scale_xyz(X,
Y, Z, had_data)
return polyc
From: Mike Alger [mailto:malger-6s6ziW1YCwCw5LPnMra/2Q@public.gmane.org]
Sent: November-25-09 8:42 PM
To: matplotlib-users-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
Subject: Re: [Matplotlib-users] Color in 3d plots
I have been looking at this for the
past day and in am pretty sure I could replace the instance of polyc by the
“cmap if statements” my colour array and I should be able to get close to what
I want. However I am new to both python & mpl, and I am not entirely sure
in how I would go about testing my hypothesis. Furthermore I am also relatively
new to submitting fixes to open-source projects so I have lots of questions
about how I would go about suggesting a modification.
1.)
can I just modify
the file in the C:\python26\Lib\site-packages\mpl-toolkits\mplot3d\axes3d.py
file to do my tests?
a.
Also, where are
these files usually kept in a linux environment ?
b.
What do I do with
the. pyc files with the same name? are they re-complied automatically when I
call the function externally?
2.)
Is this capability
already built in with the colour argument ? if so how do I properly call it?
3.)
If I do make a
modification should it be as a separate function with the additional variable
or should I try to stuff the new capability into the old function
4.)
is there a clean
easy to follow tutorial for submitting changes via svn or can I rely on someone
else to do the final commit?
I have attached the function in
question for reference to save others from digging down into their python
directories
Again thanks for taking your
time to help me figure this out
Mike Alger
< Code>
def plot_surface(self, X,
Y, Z, *args, **kwargs):
'''
Create a surface plot.
By default it will be colored in shades of a solid color,
but it also supports color mapping by supplying the *cmap*
argument.
========== ================================================
Argument Description
========== ================================================
*X*, *Y*, Data values as numpy.arrays
*Z*
*rstride* Array row stride (step size)
*cstride* Array column stride (step size)
*color* Color of the surface patches
*cmap* A colormap for the surface patches.
========== ================================================
'''
had_data = self.has_data()
rows, cols = Z.shape
tX, tY, tZ = np.transpose(X), np.transpose(Y), np.transpose(Z)
rstride = kwargs.pop('rstride', 10)
cstride = kwargs.pop('cstride', 10)
color = kwargs.pop('color', 'b')
color = np.array(colorConverter.to_rgba(color))
cmap = kwargs.get('cmap', None)
polys = []
normals = []
avgz = []
for rs in np.arange(0, rows-1, rstride):
for cs in np.arange(0, cols-1, cstride):
ps = []
corners = []
for a, ta in [(X, tX), (Y, tY), (Z, tZ)]:
ztop = a[rs][cs:min(cols, cs+cstride+1)]
zleft = ta[min(cols-1, cs+cstride)][rs:min(rows, rs+rstride+1)]
zbase = a[min(rows-1, rs+rstride)][cs:min(cols, cs+cstride+1):]
zbase = zbase[::-1]
zright = ta[cs][rs:min(rows, rs+rstride+1):]
zright = zright[::-1]
corners.append([ztop[0], ztop[-1], zbase[0], zbase[-1]])
z = np.concatenate((ztop, zleft, zbase, zright))
ps.append(z)
# The construction leaves the array with duplicate points, which
# are removed here.
ps = zip(*ps)
lastp = np.array([])
ps2 = []
avgzsum = 0.0
for p in ps:
if p != lastp:
ps2.append(p)
lastp = p
avgzsum += p[2]
polys.append(ps2)
avgz.append(avgzsum / len(ps2))
v1 = np.array(ps2[0]) - np.array(ps2[1])
v2 = np.array(ps2[2]) - np.array(ps2[0])
normals.append(np.cross(v1, v2))
polyc = art3d.Poly3DCollection(polys, *args, **kwargs) ## this is where a
modification could be made to allow for a separate colour matrix
if cmap is not None:
polyc.set_array(np.array(avgz))
polyc.set_linewidth(0)
else:
colors = self._shade_colors(color, normals)
polyc.set_facecolors(colors)
self.add_collection(polyc)
self.auto_scale_xyz(X, Y, Z, had_data)
return polyc
</Code>
From: Mike Alger
[mailto:mike.alger-KC71EySklSc3nlPAGJ/kyg@public.gmane.org]
Sent: November-23-09 3:42 PM
To: matplotlib-users-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
Subject: [Matplotlib-users] Color in 3d plots
This may be a dumb question, however I have been scratching my head trying to figure out how to plot
a 3 dimensional plot with with a colour map different from the elevation(Z)
parameter.
An example of this done in Matlab would be
[X,Y,Z] = peaks(30);
C=Z'% could be anything other than Z
as long as it has the same dimensions
surf(X,Y,Z,C)
axis([-3 3 -3 3
-10 5])
Is this possible with matplotlib '0.99.1'
If so how do i go about doing this is there some
sample code?
Mike Alger, M.A.Sc
malger-6s6ziW1YCwCw5LPnMra/2Q@public.gmane.org