|
From: <he...@us...> - 2010-03-19 17:12:49
|
Revision: 8199
http://matplotlib.svn.sourceforge.net/matplotlib/?rev=8199&view=rev
Author: heeres
Date: 2010-03-19 17:12:41 +0000 (Fri, 19 Mar 2010)
Log Message:
-----------
Some fixes
Modified Paths:
--------------
trunk/matplotlib/examples/mplot3d/hist3d_demo.py
trunk/matplotlib/examples/mplot3d/text3d_demo.py
trunk/matplotlib/lib/mpl_toolkits/mplot3d/art3d.py
trunk/matplotlib/lib/mpl_toolkits/mplot3d/axes3d.py
Modified: trunk/matplotlib/examples/mplot3d/hist3d_demo.py
===================================================================
--- trunk/matplotlib/examples/mplot3d/hist3d_demo.py 2010-03-19 16:50:37 UTC (rev 8198)
+++ trunk/matplotlib/examples/mplot3d/hist3d_demo.py 2010-03-19 17:12:41 UTC (rev 8199)
@@ -17,7 +17,7 @@
dy = dx.copy()
dz = hist.flatten()
-ax.bar3d(xpos, ypos, zpos, dx, dy, dz, color='b')
+ax.bar3d(xpos, ypos, zpos, dx, dy, dz, color='b', zsort='average')
plt.show()
Modified: trunk/matplotlib/examples/mplot3d/text3d_demo.py
===================================================================
--- trunk/matplotlib/examples/mplot3d/text3d_demo.py 2010-03-19 16:50:37 UTC (rev 8198)
+++ trunk/matplotlib/examples/mplot3d/text3d_demo.py 2010-03-19 17:12:41 UTC (rev 8199)
@@ -13,6 +13,9 @@
label = '(%d, %d, %d), dir=%s' % (x, y, z, zdir)
ax.text(x, y, z, label, zdir)
+ax.text(1, 1, 1, "red", color='red')
+ax.text2D(0.05, 0.95, "2D Text", transform=ax.transAxes)
+
ax.set_xlim3d(0, 10)
ax.set_ylim3d(0, 10)
ax.set_zlim3d(0, 10)
Modified: trunk/matplotlib/lib/mpl_toolkits/mplot3d/art3d.py
===================================================================
--- trunk/matplotlib/lib/mpl_toolkits/mplot3d/art3d.py 2010-03-19 16:50:37 UTC (rev 8198)
+++ trunk/matplotlib/lib/mpl_toolkits/mplot3d/art3d.py 2010-03-19 17:12:41 UTC (rev 8199)
@@ -1,6 +1,7 @@
#!/usr/bin/python
# art3d.py, original mplot3d version by John Porter
# Parts rewritten by Reinier Heeres <re...@he...>
+# Minor additions by Ben Axelrod <bax...@co...>
'''
Module containing 3D artist code and functions to convert 2D
@@ -15,6 +16,7 @@
from matplotlib.colors import Normalize
from matplotlib.cbook import iterable
+import warnings
import numpy as np
import math
import proj3d
@@ -52,8 +54,15 @@
Text object with 3D position and (in the future) direction.
'''
- def __init__(self, x=0, y=0, z=0, text='', zdir='z'):
- mtext.Text.__init__(self, x, y, text)
+ def __init__(self, x=0, y=0, z=0, text='', zdir='z', **kwargs):
+ '''
+ *x*, *y*, *z* Position of text
+ *text* Text string to display
+ *zdir* Direction of text
+
+ Keyword arguments are passed onto :func:`~matplotlib.text.Text`.
+ '''
+ mtext.Text.__init__(self, x, y, text, **kwargs)
self.set_3d_properties(z, zdir)
def set_3d_properties(self, z=0, zdir='z'):
@@ -86,6 +95,9 @@
'''
def __init__(self, xs, ys, zs, *args, **kwargs):
+ '''
+ Keyword arguments are passed onto :func:`~matplotlib.lines.Line2D`.
+ '''
lines.Line2D.__init__(self, [], [], *args, **kwargs)
self._verts3d = xs, ys, zs
@@ -145,6 +157,9 @@
'''
def __init__(self, segments, *args, **kwargs):
+ '''
+ Keyword arguments are passed onto :func:`~matplotlib.collections.LineCollection`.
+ '''
LineCollection.__init__(self, segments, *args, **kwargs)
def set_segments(self, segments):
@@ -317,13 +332,44 @@
*verts* should contain 3D coordinates.
+ Keyword arguments:
+ zsort, see set_zsort for options.
+
Note that this class does a bit of magic with the _facecolors
and _edgecolors properties.
'''
+ self.set_zsort(kwargs.pop('zsort', True))
+
PolyCollection.__init__(self, verts, *args, **kwargs)
- self._zsort = 1
+
+ _zsort_functions = {
+ 'average': np.average,
+ 'min': np.min,
+ 'max': np.max,
+ }
+
+ def set_zsort(self, zsort):
+ '''
+ Set z-sorting behaviour:
+ boolean: if True use default 'average'
+ string: 'average', 'min' or 'max'
+ '''
+
+ if zsort is True:
+ zsort = 'average'
+
+ if zsort is not False:
+ if zsort in self._zsort_functions:
+ zsortfunc = self._zsort_functions[zsort]
+ else:
+ return False
+ else:
+ zsortfunc = None
+
+ self._zsort = zsort
self._sort_zpos = None
+ self._zsortfunc = zsortfunc
def get_vector(self, segments3d):
"""Optimize points for projection"""
@@ -348,12 +394,13 @@
PolyCollection.set_verts(self, [], closed)
def set_3d_properties(self):
- self._zsort = 1
self._sort_zpos = None
+ self.set_zsort(True)
self._facecolors3d = PolyCollection.get_facecolors(self)
self._edgecolors3d = PolyCollection.get_edgecolors(self)
- def set_sort_zpos(self, val):
+ def set_sort_zpos(self,val):
+ '''Set the position to use for z-sorting.'''
self._sort_zpos = val
def do_3d_projection(self, renderer):
@@ -381,7 +428,7 @@
# if required sort by depth (furthest drawn first)
if self._zsort:
- z_segments_2d = [(np.average(zs), zip(xs, ys), fc, ec) for
+ z_segments_2d = [(self._zsortfunc(zs), zip(xs, ys), fc, ec) for
(xs, ys, zs), fc, ec in zip(xyzlist, cface, cedge)]
z_segments_2d.sort(cmp=lambda x, y: cmp(y[0], x[0]))
else:
@@ -468,9 +515,14 @@
def iscolor(c):
try:
- return (len(c) == 4 or len(c) == 3) and hasattr(c[0], '__float__')
- except (IndexError):
+ if len(c) == 4 or len(c) == 3:
+ if iterable(c[0]):
+ return False
+ if hasattr(c[0], '__float__'):
+ return True
+ except:
return False
+ return False
def get_colors(c, num):
"""Stretch the color argument to provide the required number num"""
@@ -484,6 +536,8 @@
return c
elif iscolor(c):
return [c] * num
+ elif len(c) == 0: #if edgecolor or facecolor is specified as 'none'
+ return [[0,0,0,0]] * num
elif iscolor(c[0]):
return [c[0]] * num
else:
Modified: trunk/matplotlib/lib/mpl_toolkits/mplot3d/axes3d.py
===================================================================
--- trunk/matplotlib/lib/mpl_toolkits/mplot3d/axes3d.py 2010-03-19 16:50:37 UTC (rev 8198)
+++ trunk/matplotlib/lib/mpl_toolkits/mplot3d/axes3d.py 2010-03-19 17:12:41 UTC (rev 8199)
@@ -2,12 +2,14 @@
# axes3d.py, original mplot3d version by John Porter
# Created: 23 Sep 2005
# Parts fixed by Reinier Heeres <re...@he...>
+# Minor additions by Ben Axelrod <bax...@co...>
"""
Module containing Axes3D, an object which can plot 3D objects on a
2D matplotlib figure.
"""
+import warnings
from matplotlib.axes import Axes, rcParams
from matplotlib import cbook
from matplotlib.transforms import Bbox
@@ -55,7 +57,7 @@
if rect is None:
rect = [0.0, 0.0, 1.0, 1.0]
self.fig = fig
- self.cids = []
+ self._cids = []
azim = kwargs.pop('azim', -60)
elev = kwargs.pop('elev', 30)
@@ -147,7 +149,7 @@
# Calculate projection of collections and zorder them
zlist = [(col.do_3d_projection(renderer), col) \
- for col in self.collections]
+ for col in self.collections]
zlist.sort()
zlist.reverse()
for i, (z, col) in enumerate(zlist):
@@ -322,23 +324,52 @@
M = np.dot(perspM, M0)
return M
- def mouse_init(self):
+ def mouse_init(self, rotate_btn=1, zoom_btn=3):
+ """Initializes mouse button callbacks to enable 3D rotation of
+ the axes. Also optionally sets the mouse buttons for 3D rotation
+ and zooming.
+
+ ============ ================================================
+ Argument Description
+ ============ ================================================
+ *rotate_btn* The integer or list of integers specifying which mouse
+ button or buttons to use for 3D rotation of the axes.
+ Default = 1.
+
+ *zoom_btn* The integer or list of integers specifying which mouse
+ button or buttons to use to zoom the 3D axes.
+ Default = 3.
+ ============ ================================================
+ """
self.button_pressed = None
canv = self.figure.canvas
if canv != None:
c1 = canv.mpl_connect('motion_notify_event', self._on_move)
c2 = canv.mpl_connect('button_press_event', self._button_press)
c3 = canv.mpl_connect('button_release_event', self._button_release)
- self.cids = [c1, c2, c3]
+ self._cids = [c1, c2, c3]
+ else:
+ warnings.warn('Axes3D.figure.canvas is \'None\', mouse rotation disabled. Set canvas then call Axes3D.mouse_init().')
+ self._rotate_btn = np.atleast_1d(rotate_btn)
+ self._zoom_btn = np.atleast_1d(zoom_btn)
+
def cla(self):
- # Disconnect the various events we set.
- for cid in self.cids:
- self.figure.canvas.mpl_disconnect(cid)
- self.cids = []
+ """Clear axes and disable mouse button callbacks.
+ """
+ self.disable_mouse_rotation()
Axes.cla(self)
self.grid(rcParams['axes3d.grid'])
+ def disable_mouse_rotation(self):
+ """Disable mouse button callbacks.
+ """
+ # Disconnect the various events we set.
+ for cid in self._cids:
+ self.figure.canvas.mpl_disconnect(cid)
+
+ self._cids = []
+
def _button_press(self, event):
if event.inaxes == self:
self.button_pressed = event.button
@@ -426,9 +457,10 @@
def _on_move(self, event):
"""Mouse moving
- button-1 rotates
- button-3 zooms
+ button-1 rotates by default. Can be set explicitly in mouse_init().
+ button-3 zooms by default. Can be set explicitly in mouse_init().
"""
+
if not self.button_pressed:
return
@@ -447,7 +479,8 @@
h = (y1-y0)
self.sx, self.sy = x, y
- if self.button_pressed == 1:
+ # Rotation
+ if self.button_pressed in self._rotate_btn:
# rotate viewing point
# get the x and y pixel coords
if dx == 0 and dy == 0:
@@ -456,12 +489,15 @@
self.azim = art3d.norm_angle(self.azim - (dx/w)*180)
self.get_proj()
self.figure.canvas.draw()
- elif self.button_pressed == 2:
+
+# elif self.button_pressed == 2:
# pan view
# project xv,yv,zv -> xw,yw,zw
# pan
- pass
- elif self.button_pressed == 3:
+# pass
+
+ # Zoom
+ elif self.button_pressed in self._zoom_btn:
# zoom view
# hmmm..this needs some help from clipping....
minx, maxx, miny, maxy, minz, maxz = self.get_w_lims()
@@ -476,7 +512,7 @@
self.figure.canvas.draw()
def set_xlabel(self, xlabel, fontdict=None, **kwargs):
- '''Set xlabel. '''
+ '''Set xlabel.'''
label = self.w_xaxis.get_label()
label.set_text(xlabel)
@@ -511,13 +547,18 @@
'''
self._draw_grid = on
- def text(self, x, y, z, s, zdir=None):
- '''Add text to the plot.'''
- text = Axes.text(self, x, y, s)
+ def text(self, x, y, z, s, zdir=None, **kwargs):
+ '''
+ Add text to the plot. kwargs will be passed on to Axes.text,
+ except for the `zdir` keyword, which sets the direction to be
+ used as the z direction.
+ '''
+ text = Axes.text(self, x, y, s, **kwargs)
art3d.text_2d_to_3d(text, z, zdir)
return text
text3D = text
+ text2D = Axes.text
def plot(self, xs, ys, *args, **kwargs):
'''
@@ -591,6 +632,9 @@
*shade* Whether to shade the facecolors, default:
false when cmap specified, true otherwise
========== ================================================
+
+ Other arguments are passed on to
+ :func:`~mpl_toolkits.mplot3d.art3d.Poly3DCollection.__init__`
'''
had_data = self.has_data()
@@ -822,8 +866,9 @@
colors = self._shade_colors(color, normals)
colors2 = self._shade_colors(color, normals)
- polycol = art3d.Poly3DCollection(polyverts, facecolors=colors,
- edgecolors=colors2)
+ polycol = art3d.Poly3DCollection(polyverts,
+ facecolors=colors,
+ edgecolors=colors2)
polycol.set_sort_zpos(z)
self.add_collection3d(polycol)
@@ -848,6 +893,8 @@
Other keyword arguments are passed on to
:func:`~matplotlib.axes.Axes.contour`
+
+ Returns a :class:`~matplotlib.axes.Axes.contour`
'''
extend3d = kwargs.pop('extend3d', False)
@@ -881,7 +928,9 @@
*X*, *Y*, *Z*: data points.
Keyword arguments are passed on to
- :func:`~matplotlib.axes.Axes.contour`
+ :func:`~matplotlib.axes.Axes.contourf`
+
+ Returns a :class:`~matplotlib.axes.Axes.contourf`
'''
had_data = self.has_data()
@@ -1005,25 +1054,61 @@
return patches
- def bar3d(self, x, y, z, dx, dy, dz, color='b'):
+ def bar3d(self, x, y, z, dx, dy, dz, color='b',
+ zsort='average', *args, **kwargs):
'''
Generate a 3D bar, or multiple bars.
When generating multiple bars, x, y, z have to be arrays.
- dx, dy, dz can still be scalars.
+ dx, dy, dz can be arrays or scalars.
+
+ *color* can be:
+ - A single color value, to color all bars the same color.
+ - An array of colors of length N bars, to color each bar
+ independently.
+ - An array of colors of length 6, to color the faces of the bars
+ similarly.
+ - An array of colors of length 6 * N bars, to color each face
+ independently.
+
+ When coloring the faces of the boxes specifically, this is the order
+ of the coloring:
+ 1. -Z (bottom of box)
+ 2. +Z (top of box)
+ 3. -Y
+ 4. +Y
+ 5. -X
+ 6. +X
+
+ Keyword arguments are passed onto
+ :func:`~mpl_toolkits.mplot3d.art3d.Poly3DCollection`
'''
-
had_data = self.has_data()
if not cbook.iterable(x):
- x, y, z = [x], [y], [z]
+ x = [x]
+ if not cbook.iterable(y):
+ y = [y]
+ if not cbook.iterable(z):
+ z = [z]
+
if not cbook.iterable(dx):
- dx, dy, dz = [dx], [dy], [dz]
+ dx = [dx]
+ if not cbook.iterable(dy):
+ dy = [dy]
+ if not cbook.iterable(dz):
+ dz = [dz]
+
if len(dx) == 1:
dx = dx * len(x)
- dy = dy * len(x)
- dz = dz * len(x)
+ if len(dy) == 1:
+ dy = dy * len(y)
+ if len(dz) == 1:
+ dz = dz * len(z)
+ if len(x) != len(y) or len(x) != len(z):
+ warnings.warn('x, y, and z must be the same length.')
+
minx, miny, minz = 1e20, 1e20, 1e20
maxx, maxy, maxz = -1e20, -1e20, -1e20
@@ -1053,15 +1138,35 @@
(xi + dxi, yi + dyi, zi + dzi), (xi + dxi, yi, zi + dzi)),
])
- color = np.array(colorConverter.to_rgba(color))
+ facecolors = []
+ if color is None:
+ # no color specified
+ facecolors = [None] * len(x)
+ elif len(color) == len(x):
+ # bar colors specified, need to expand to number of faces
+ for c in color:
+ facecolors.extend([c] * 6)
+ else:
+ # a single color specified, or face colors specified explicitly
+ facecolors = list(colorConverter.to_rgba_array(color))
+ if len(facecolors) < len(x):
+ facecolors *= (6 * len(x))
+
normals = self._generate_normals(polys)
- colors = self._shade_colors(color, normals)
-
- col = art3d.Poly3DCollection(polys, facecolor=colors)
+ sfacecolors = self._shade_colors(facecolors, normals)
+ col = art3d.Poly3DCollection(polys,
+ zsort=zsort,
+ facecolor=sfacecolors,
+ *args, **kwargs)
self.add_collection(col)
self.auto_scale_xyz((minx, maxx), (miny, maxy), (minz, maxz), had_data)
+ def set_title(self, label, fontdict=None, **kwargs):
+ Axes.set_title(self, label, fontdict, **kwargs)
+ (x, y) = self.title.get_position()
+ self.title.set_y(0.92 * y)
+
def get_test_data(delta=0.05):
'''
Return a tuple X, Y, Z with a test data set.
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|