color in plot3d

Hello!
I wonder if there is a way to make 3d plots specifying arbitrary
colors, instead of having the color be a function of the height. I was
able to achieve this making minimal changes to the plot_surface method
of Axes3D, adding as an optional keyword argument a function cfun
which specifies the color (it specifies a real number that is mapped
into a color by the color map cmap). But is there a standard
way?

Regard

Pablo Angulo

from matplotlib.colors import Normalize, colorConverter
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.
*cfun*      The function giving the color
==========  ================================================
'''
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)
**cfun = kwargs.pop('cfun', None)**
polys = []
normals = []
avgz = []
**if not cfun:**
**cfun = lambda p:p[2]**
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 += cfun(p)**
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)
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

First what version of mpl are you using? if it is recent this
colour word already exists, I asked about this a couple months ago and i
should point you first to the example in the svn it does a checkerboard, but i
cannot remember the exact name. Although i know it plots a checkerboard effect
on one of the example plots.

The way that color keyword is set up, it is dedsigned to take a
color word or rgba tuple , (Reinier will know this better than me), however if
you want to just assign colors based on a colour map you can take you color
array and reshape the same way the plot surface command does then use surf.set_array()

here is a snippet of the code I use to do this I am pretty sure
it won’t run the way it is right now but the idea is buried in there

note that regmap xyz and costmapz are all the same size and are
nxm matrices costmapout is a 2x(m.n) if i can do the math correctly

from mpl_toolkits.mplot3d import Axes3D

from matplotlib import cm

import numpy as np

···

#--------------------------------------------------

ax = Axes3D(fig)

scale= 3

surf = ax.plot_surface(regMAPx ,regMAPy,-regMAPz ,
rstride=scale,cstride=scale, cmap=cm.jet, linewidth=.250 )

to reshape the cost map to match grid used in plot surf

rows, cols = costMAPz.shape

costmapout = []

for rs in np.arange(0, rows-1, scale):

for cs in np.arange(0, cols-1, scale):

costmapout.append(costMAPz[rs][cs])

costmapout=np.array(costmapout)

surf.set_array(costmapout)

do your show plot stuff here!!

Mike Alger

From:
Pablo Angulo [mailto:pablo.angulo@…3156…]
Sent: June-11-10 7:04 AM
To: matplotlib-users@lists.sourceforge.net
Subject: [Matplotlib-users] color in plot3d

Hello!
I wonder if there is a way to make 3d plots specifying arbitrary
colors, instead of having the color be a function of the height. I was able to
achieve this making minimal changes to the plot_surface method of Axes3D,
adding as an optional keyword argument a function cfun which specifies
the color (it specifies a real number that is mapped into a color by the color
map cmap). But is there a standard way?
Regard
Pablo Angulo

from matplotlib.colors import Normalize, colorConverter

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.

*cfun*      The function giving the color

========== ================================================

'''

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)

**cfun = kwargs.pop('cfun', None)**

polys = []

normals = []

avgz = []

**if not cfun:**

cfun = lambda p:p[2]


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 += cfun(p)**

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)

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

No
virus found in this incoming message.

Checked by AVG - www.avg.com

Version: 9.0.829 / Virus Database: 271.1.1/2933 - Release Date: 06/12/10
14:35:00

The
way that color keyword is set up, it is dedsigned to take a
color word or rgba tuple , (Reinier will know this better than me),
however if
you want to just assign colors based on a colour map you can take you
color
array and reshape the same way the plot surface command does then
use surf.set_array()

Pablo,

I found the example on the svn http://matplotlib.svn.sourceforge.net/viewvc/matplotlib/trunk/matplotlib/examples/mplot3d/surface3d_demo3.py?view=log
it will demonstrate the face colour thing but personally I found getting the rgb
tuple data into an array a bit too complicated for my needs.

Regarding that little SNAFU about the matrix size, I was half
asleep and in a rush when I wrote the reply to your email, so I knew if I made
a mistake it was in the interpretation there :smiley:

A slice, reshape function may be more efficient/ easier to
read but I took the loop structure right from the plot surface command to make
sure it was done exactly the same way as the 3d surface. It may be interesting
to see which is more efficient computationally and see if there is an
improvement to be made in the plot surface command

From:
Pablo Angulo [mailto:pablo.angulo@…3156…]

···

Sent: June-16-10 9:07 AM
To: Mike Alger
Cc: matplotlib-users@lists.sourceforge.net
Subject: Re: [Matplotlib-users] color in plot3d

El 15/06/10 01:22, Mike Alger escribió:

The
way that color keyword is set up, it is dedsigned to take a color word
or rgba tuple , (Reinier will know this better than me), however if you
want to just assign colors based on a colour map you can take you color array
and reshape the same way the plot surface command does then
use surf.set_array()

If I understand you correctly, you mean there is a way to use directly a map
from two or three spatial coordinates into the three or four components of the
color space?

That’s interesting. It might be limiting that this map has to factor as the
composition of an scalar map and a color map, even for 2d plots.

here
is a snippet of the code I use to do this I am pretty sure it won’t run the way
it is right now but the idea is buried in there

Thanks, I got the idea!

note
that regmap xyz and costmapz are all the same size and are nxm matrices
costmapout is a 2x(m.n) if i can do the math correctly

One comment: from your code it seems that costmapout is a 1D array of lenght
roughly equal (m*n)/scale**2 with the data coming from costmapz. Why don’t you
use a slice followed by a reshape command?

No
virus found in this incoming message.

Checked by AVG - www.avg.com

Version: 9.0.829 / Virus Database: 271.1.1/2942 - Release Date: 06/16/10
14:35:00

Pablo,

I
found the example on the svn http://matplotlib.svn.sourceforge.net/viewvc/matplotlib/trunk/matplotlib/examples/mplot3d/surface3d_demo3.py?view=log
it will demonstrate the face colour thing but personally I found
getting the rgb
tuple data into an array a bit too complicated for my needs.

Regarding
that little SNAFU about the matrix size, I was half
asleep and in a rush when I wrote the reply to your email, so I knew if
I made
a mistake it was in the interpretation there :smiley:

A
slice, reshape function may be more efficient/ easier to
read but I took the loop structure right from the plot surface command
to make
sure it was done exactly the same way as the 3d surface. It may be
interesting
to see which is more efficient computationally and see if there is an
improvement to be made in the plot surface command

···

From:
Pablo Angulo [mailto:pablo.angulo@…3156…]
Sent: June-16-10 9:07 AM
To: Mike Alger
Cc: matplotlib-users@lists.sourceforge.net
Subject: Re: [Matplotlib-users] color in plot3d

El 15/06/10 01:22, Mike Alger escribió:

The
way
that color keyword is set up, it is dedsigned to take a color word
or rgba tuple , (Reinier will know this better than me), however if
you
want to just assign colors based on a colour map you can take you color
array
and reshape the same way the plot surface command does then
use surf.set_array()

If I understand you correctly, you mean there is a way to use directly
a map
from two or three spatial coordinates into the three or four components
of the
color space?

That’s interesting. It might be limiting that this map has to factor as
the
composition of an scalar map and a color map, even for 2d plots.

here
is
a snippet of the code I use to do this I am pretty sure it won’t run
the way
it is right now but the idea is buried in there

Thanks, I got the idea!

note
that
regmap xyz and costmapz are all the same size and are nxm matrices
costmapout is a 2x(m.n) if i can do the math correctly

One comment: from your code it seems that costmapout is a 1D array of
lenght
roughly equal (m*n)/scale**2 with the data coming from costmapz. Why
don’t you
use a slice followed by a reshape command?

No
virus
found in this incoming message.

Checked by AVG - www.avg.com

Version: 9.0.829 / Virus Database: 271.1.1/2942 - Release Date:
06/16/10
14:35:00