32
32
If U and V are 2-D arrays but X and Y are 1-D, and if
33
33
len(X) and len(Y) match the column and row dimensions
34
34
of U, then X and Y will be expanded with meshgrid.
35
+ U, V, C may be masked arrays, but masked X, Y are not
36
+ supported at present.
35
37
36
38
Keyword arguments (default given first):
37
39
@@ -298,8 +300,7 @@ def _parse_args(self, *args):
298
300
X , Y , U , V , C = [None ]* 5
299
301
args = list (args )
300
302
if len (args ) == 3 or len (args ) == 5 :
301
- C = npy .ravel (args .pop (- 1 ))
302
- #print 'in parse_args, C:', C
303
+ C = ma .asarray (args .pop (- 1 )).ravel ()
303
304
V = ma .asarray (args .pop (- 1 ))
304
305
U = ma .asarray (args .pop (- 1 ))
305
306
nn = npy .shape (U )
@@ -308,9 +309,9 @@ def _parse_args(self, *args):
308
309
if len (nn ) > 1 :
309
310
nr = nn [1 ]
310
311
if len (args ) == 2 :
311
- X , Y = [npy .ravel ( a ) for a in args ]
312
+ X , Y = [npy .array ( a ). ravel ( ) for a in args ]
312
313
if len (X ) == nc and len (Y ) == nr :
313
- X , Y = [npy .ravel (a ) for a in npy .meshgrid (X , Y )]
314
+ X , Y = [a .ravel () for a in npy .meshgrid (X , Y )]
314
315
else :
315
316
indexgrid = npy .meshgrid (npy .arange (nc ), npy .arange (nr ))
316
317
X , Y = [npy .ravel (a ) for a in indexgrid ]
@@ -333,15 +334,20 @@ def draw(self, renderer):
333
334
self ._init ()
334
335
if self ._new_UV :
335
336
verts = self ._make_verts (self .U , self .V )
336
- self .set_verts (verts )
337
+ # Using nan internally here is the easiest
338
+ # way to support masked inputs; it doesn't
339
+ # require adding mask support to PolyCollection,
340
+ # and it keeps all array dimensions (X, Y, U, V, C)
341
+ # intact.
342
+ self .set_verts (verts .filled (npy .nan ))
337
343
self ._new_UV = False
338
344
collections .PolyCollection .draw (self , renderer )
339
345
340
346
def set_UVC (self , U , V , C = None ):
341
- self .U = ma .ravel (U )
342
- self .V = ma .ravel (V )
347
+ self .U = U .ravel ()
348
+ self .V = V .ravel ()
343
349
if C is not None :
344
- self .set_array (npy .ravel (C ))
350
+ self .set_array (C .ravel ())
345
351
self ._new_UV = True
346
352
347
353
def _set_transform (self ):
@@ -371,75 +377,74 @@ def _set_transform(self):
371
377
return trans
372
378
373
379
def _make_verts (self , U , V ):
374
- uv = U + V * 1j
375
- uv = npy .ravel (ma .filled (uv ,npy .nan ))
376
- a = npy .absolute (uv )
380
+ uv = ma .asarray (U + V * 1j )
381
+ a = ma .absolute (uv )
377
382
if self .scale is None :
378
383
sn = max (10 , math .sqrt (self .N ))
379
-
380
- # get valid values for average
381
- # (complicated by support for 3 array packages)
382
- a_valid_cond = ~ npy .isnan (a )
383
- a_valid_idx = npy .nonzero (a_valid_cond )
384
- if isinstance (a_valid_idx ,tuple ):
385
- # numpy.nonzero returns tuple
386
- a_valid_idx = a_valid_idx [0 ]
387
- valid_a = npy .take (a ,a_valid_idx )
388
-
389
- scale = 1.8 * npy .average (valid_a ) * sn # crude auto-scaling
390
- scale = scale / self .span
384
+ scale = 1.8 * a .mean () * sn / self .span # crude auto-scaling
391
385
self .scale = scale
392
386
length = a / (self .scale * self .width )
393
387
X , Y = self ._h_arrows (length )
394
- xy = (X + Y * 1j ) * npy .exp (1j * npy .angle (uv [...,npy .newaxis ]))* self .width
388
+ # There seems to be a ma bug such that indexing
389
+ # a masked array with one element converts it to
390
+ # an ndarray.
391
+ theta = npy .angle (ma .asarray (uv [..., npy .newaxis ]).filled (0 ))
392
+ xy = (X + Y * 1j ) * npy .exp (1j * theta )* self .width
395
393
xy = xy [:,:,npy .newaxis ]
396
- XY = npy .concatenate ((xy .real , xy .imag ), axis = 2 )
394
+ XY = ma .concatenate ((xy .real , xy .imag ), axis = 2 )
397
395
return XY
398
396
399
397
400
398
def _h_arrows (self , length ):
401
399
""" length is in arrow width units """
400
+ # It might be possible to streamline the code
401
+ # and speed it up a bit by using complex (x,y)
402
+ # instead of separate arrays; but any gain would be slight.
402
403
minsh = self .minshaft * self .headlength
403
404
N = len (length )
404
- length = npy .reshape (length , (N ,1 ))
405
+ length = length .reshape (N , 1 )
406
+ # x, y: normal horizontal arrow
405
407
x = npy .array ([0 , - self .headaxislength ,
406
408
- self .headlength , 0 ], npy .float64 )
407
409
x = x + npy .array ([0 ,1 ,1 ,1 ]) * length
408
410
y = 0.5 * npy .array ([1 , 1 , self .headwidth , 0 ], npy .float64 )
409
411
y = npy .repeat (y [npy .newaxis ,:], N , axis = 0 )
412
+ # x0, y0: arrow without shaft, for short vectors
410
413
x0 = npy .array ([0 , minsh - self .headaxislength ,
411
414
minsh - self .headlength , minsh ], npy .float64 )
412
415
y0 = 0.5 * npy .array ([1 , 1 , self .headwidth , 0 ], npy .float64 )
413
416
ii = [0 ,1 ,2 ,3 ,2 ,1 ,0 ]
414
- X = npy .take (x , ii , 1 )
415
- Y = npy .take (y , ii , 1 )
417
+ X = x .take (ii , 1 )
418
+ Y = y .take (ii , 1 )
416
419
Y [:, 3 :] *= - 1
417
- X0 = npy .take (x0 , ii )
418
- Y0 = npy .take (y0 , ii )
420
+ X0 = x0 .take (ii )
421
+ Y0 = y0 .take (ii )
419
422
Y0 [3 :] *= - 1
420
423
shrink = length / minsh
421
424
X0 = shrink * X0 [npy .newaxis ,:]
422
425
Y0 = shrink * Y0 [npy .newaxis ,:]
423
426
short = npy .repeat (length < minsh , 7 , axis = 1 )
424
427
#print 'short', length < minsh
425
- X = npy .where (short , X0 , X )
426
- Y = npy .where (short , Y0 , Y )
428
+ # Now select X0, Y0 if short, otherwise X, Y
429
+ X = ma .where (short , X0 , X )
430
+ Y = ma .where (short , Y0 , Y )
427
431
if self .pivot [:3 ] == 'mid' :
428
432
X -= 0.5 * X [:,3 , npy .newaxis ]
429
433
elif self .pivot [:3 ] == 'tip' :
430
434
X = X - X [:,3 , npy .newaxis ] #numpy bug? using -= does not
431
435
# work here unless we multiply
432
436
# by a float first, as with 'mid'.
433
437
tooshort = length < self .minlength
434
- if npy .any (tooshort ):
438
+ if tooshort .any ():
439
+ # Use a heptagonal dot:
435
440
th = npy .arange (0 ,7 ,1 , npy .float64 ) * (npy .pi / 3.0 )
436
441
x1 = npy .cos (th ) * self .minlength * 0.5
437
442
y1 = npy .sin (th ) * self .minlength * 0.5
438
443
X1 = npy .repeat (x1 [npy .newaxis , :], N , axis = 0 )
439
444
Y1 = npy .repeat (y1 [npy .newaxis , :], N , axis = 0 )
440
- tooshort = npy .repeat (tooshort , 7 , 1 )
441
- X = npy .where (tooshort , X1 , X )
442
- Y = npy .where (tooshort , Y1 , Y )
445
+ tooshort = ma .repeat (tooshort , 7 , 1 )
446
+ X = ma .where (tooshort , X1 , X )
447
+ Y = ma .where (tooshort , Y1 , Y )
443
448
return X , Y
444
449
445
450
quiver_doc = _quiver_doc
0 commit comments