Skip to content

Commit dd458fb

Browse files
committed
Merge remote-tracking branch 'origin/fix_vector_scale' into vector_graphics_text_as_object
2 parents ab65bdb + 8c05ac4 commit dd458fb

9 files changed

Lines changed: 300 additions & 75 deletions

File tree

Packages/testing/regression.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,15 @@ def init(*args, **kwargs):
2020
testingDir = os.path.join(os.path.dirname(__file__), "..")
2121
sys.path.append(testingDir)
2222

23-
vcsinst = vcs.init(*args, **kwargs)
24-
vcsinst.setantialiasing(0)
25-
vcsinst.drawlogooff()
26-
2723
if ((('bg' in kwargs and kwargs['bg']) or ('bg' not in kwargs)) and
2824
('geometry' not in kwargs)):
25+
vcsinst = vcs.init(*args, **dict(kwargs, bg=1))
2926
vcsinst.setbgoutputdimensions(1200, 1091, units="pixels")
27+
else:
28+
vcsinst = vcs.init(*args, **dict(kwargs, bg=0))
29+
30+
vcsinst.setantialiasing(0)
31+
vcsinst.drawlogooff()
3032
return vcsinst
3133

3234
def run(vcsinst, fname, baseline=sys.argv[1], threshold=defaultThreshold):

Packages/vcs/vcs/VCS_validation_functions.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,18 @@ def checkListOfNumbers(self, name, value, minvalue=None,
243243
return list(value)
244244

245245

246+
def checkInStringList(self, name, value, options):
247+
checkName(self, name, value)
248+
if value not in options:
249+
self.checkedRaise(
250+
self,
251+
value,
252+
ValueError,
253+
'Invalid value ' + value + '. Valid options are: ' +
254+
','.join(self.scaleoptions))
255+
return value
256+
257+
246258
def checkFont(self, name, value):
247259
if (value is None):
248260
pass

Packages/vcs/vcs/VTKPlots.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1138,15 +1138,15 @@ def vectorGraphics(self, output_type, file, width=None, height=None,
11381138
def postscript(self, file, width=None, height=None,
11391139
units=None, textAsPaths=True):
11401140
return self.vectorGraphics("ps", file, width, height,
1141-
units, textAsPaths)
1141+
units, textAsPaths)
11421142

11431143
def pdf(self, file, width=None, height=None, units=None, textAsPaths=True):
11441144
return self.vectorGraphics("pdf", file, width, height,
1145-
units, textAsPaths)
1145+
units, textAsPaths)
11461146

11471147
def svg(self, file, width=None, height=None, units=None, textAsPaths=True):
11481148
return self.vectorGraphics("svg", file, width,
1149-
height, units, textAsPaths)
1149+
height, units, textAsPaths)
11501150

11511151
def gif(self, filename='noname.gif', merge='r', orientation=None,
11521152
geometry='1600x1200'):

Packages/vcs/vcs/vcsvtk/vectorpipeline.py

Lines changed: 66 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ def _plotInternal(self):
1919
# Preserve time and z axis for plotting these inof in rendertemplate
2020
projection = vcs.elements["projection"][self._gm.projection]
2121
taxis = self._originalData1.getTime()
22+
scaleFactor = 1.0
23+
2224
if self._originalData1.ndim > 2:
2325
zaxis = self._originalData1.getAxis(-3)
2426
else:
@@ -84,24 +86,80 @@ def _plotInternal(self):
8486
arrow.SetOutputPointsPrecision(vtk.vtkAlgorithm.DOUBLE_PRECISION)
8587
arrow.FilledOff()
8688

89+
polydata = self._vtkPolyDataFilter.GetOutput()
90+
vectors = polydata.GetPointData().GetVectors()
91+
92+
if self._gm.scaletype == 'constant' or\
93+
self._gm.scaletype == 'constantNNormalize' or\
94+
self._gm.scaletype == 'constantNLinear':
95+
scaleFactor = scale * 2.0 * self._gm.scale
96+
else:
97+
scaleFactor = 1.0
98+
8799
glyphFilter = vtk.vtkGlyph2D()
88-
glyphFilter.SetInputConnection(self._vtkPolyDataFilter.GetOutputPort())
100+
glyphFilter.SetInputData(polydata)
89101
glyphFilter.SetInputArrayToProcess(1, 0, 0, 0, "vector")
90102
glyphFilter.SetSourceConnection(arrow.GetOutputPort())
91103
glyphFilter.SetVectorModeToUseVector()
92104

93105
# Rotate arrows to match vector data:
94106
glyphFilter.OrientOn()
107+
glyphFilter.ScalingOn()
95108

96-
# Scale to vector magnitude:
97109
glyphFilter.SetScaleModeToScaleByVector()
98-
glyphFilter.SetScaleFactor(scale * 2.0 * self._gm.scale)
99110

100-
# These are some unfortunately named methods. It does *not* clamp the
101-
# scale range to [min, max], but rather remaps the range
102-
# [min, max] --> [0, 1].
103-
glyphFilter.ClampingOn()
104-
glyphFilter.SetRange(0.01, 1.0)
111+
if self._gm.scaletype == 'normalize' or self._gm.scaletype == 'linear' or\
112+
self._gm.scaletype == 'constantNNormalize' or self._gm.scaletype == 'constantNLinear':
113+
114+
# Find the min and max vector magnitudes
115+
maxNorm = vectors.GetMaxNorm()
116+
117+
if maxNorm == 0:
118+
maxNorm = 1.0
119+
120+
if self._gm.scaletype == 'normalize' or self._gm.scaletype == 'constantNNormalize':
121+
scaleFactor /= maxNorm
122+
123+
if self._gm.scaletype == 'linear' or self._gm.scaletype == 'constantNLinear':
124+
minNorm = None
125+
maxNorm = None
126+
127+
noOfComponents = vectors.GetNumberOfComponents()
128+
for i in range(0, vectors.GetNumberOfTuples()):
129+
norm = vtk.vtkMath.Norm(vectors.GetTuple(i), noOfComponents)
130+
131+
if (minNorm is None or norm < minNorm):
132+
minNorm = norm
133+
if (maxNorm is None or norm > maxNorm):
134+
maxNorm = norm
135+
136+
if maxNorm == 0:
137+
maxNorm = 1.0
138+
139+
scalarArray = vtk.vtkDoubleArray()
140+
scalarArray.SetNumberOfComponents(1)
141+
scalarArray.SetNumberOfValues(vectors.GetNumberOfTuples())
142+
143+
oldRange = maxNorm - minNorm
144+
oldRange = 1.0 if oldRange == 0.0 else oldRange
145+
146+
# New range min, max.
147+
newRangeValues = self._gm.scalerange
148+
newRange = newRangeValues[1] - newRangeValues[0]
149+
150+
for i in range(0, vectors.GetNumberOfTuples()):
151+
norm = vtk.vtkMath.Norm(vectors.GetTuple(i), noOfComponents)
152+
newValue = (((norm - minNorm) * newRange) / oldRange) + newRangeValues[0]
153+
scalarArray.SetValue(i, newValue)
154+
polydata.GetPointData().SetScalars(scalarArray)
155+
156+
# Scale to vector magnitude:
157+
# NOTE: Currently we compute our own scaling factor since VTK does
158+
# it by clamping the values > max to max and values < min to min
159+
# and not remap the range.
160+
glyphFilter.SetScaleModeToScaleByScalar()
161+
162+
glyphFilter.SetScaleFactor(scaleFactor)
105163

106164
mapper = vtk.vtkPolyDataMapper()
107165

Packages/vcs/vcs/vector.py

Lines changed: 75 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ def process_src(nm, code):
131131
class Gv(object):
132132

133133
"""
134-
Class: Gv # Vector
134+
Class: Gv # Vector
135135
136136
Description of Gv Class:
137137
The vector graphics method displays a vector plot of a 2D vector field. Vectors
@@ -145,76 +145,76 @@ class Gv(object):
145145
entry.
146146
147147
Other Useful Functions:
148-
a=vcs.init() # Constructor
149-
a.show('vector') # Show predefined vector graphics methods
150-
a.show('line') # Show predefined VCS line objects
151-
a.setcolormap("AMIP") # Change the VCS color Map
152-
a.vector(s1, s2, v,'default') # Plot data 's1', and 's2' with vector 'v'
148+
a=vcs.init() # Constructor
149+
a.show('vector') # Show predefined vector graphics methods
150+
a.show('line') # Show predefined VCS line objects
151+
a.setcolormap("AMIP") # Change the VCS color Map
152+
a.vector(s1, s2, v,'default') # Plot data 's1', and 's2' with vector 'v'
153153
and 'default' template
154-
a.update() # Updates the VCS Canvas at user's request
155-
a.mode=1, or 0 # If 1, then automatic update, else if
154+
a.update() # Updates the VCS Canvas at user's request
155+
a.mode=1, or 0 # If 1, then automatic update, else if
156156
0, then use update function to
157157
update the VCS Canvas.
158158
159159
Example of Use:
160160
a=vcs.init()
161161
To Create a new instance of vector use:
162-
vc=a.createvector('new','quick') # Copies content of 'quick' to 'new'
163-
vc=a.createvector('new') # Copies content of 'default' to 'new'
162+
vc=a.createvector('new','quick') # Copies content of 'quick' to 'new'
163+
vc=a.createvector('new') # Copies content of 'default' to 'new'
164164
165165
To Modify an existing vector use:
166166
vc=a.getvector('AMIP_psl')
167167
168-
vc.list() # Will list all the vector attribute values
169-
vc.projection='linear' # Can only be 'linear'
168+
vc.list() # Will list all the vector attribute values
169+
vc.projection='linear' # Can only be 'linear'
170170
lon30={-180:'180W',-150:'150W',0:'Eq'}
171171
vc.xticlabels1=lon30
172172
vc.xticlabels2=lon30
173-
vc.xticlabels(lon30, lon30) # Will set them both
173+
vc.xticlabels(lon30, lon30) # Will set them both
174174
vc.xmtics1=''
175175
vc.xmtics2=''
176-
vc.xmtics(lon30, lon30) # Will set them both
176+
vc.xmtics(lon30, lon30) # Will set them both
177177
vc.yticlabels1=lat10
178178
vc.yticlabels2=lat10
179-
vc.yticlabels(lat10, lat10) # Will set them both
179+
vc.yticlabels(lat10, lat10) # Will set them both
180180
vc.ymtics1=''
181181
vc.ymtics2=''
182-
vc.ymtics(lat10, lat10) # Will set them both
182+
vc.ymtics(lat10, lat10) # Will set them both
183183
vc.datawc_y1=-90.0
184184
vc.datawc_y2=90.0
185185
vc.datawc_x1=-180.0
186186
vc.datawc_x2=180.0
187-
vc.datawc(-90, 90, -180, 180) # Will set them all
187+
vc.datawc(-90, 90, -180, 180) # Will set them all
188188
xaxisconvert='linear'
189189
yaxisconvert='linear'
190-
vc.xyscale('linear', 'area_wt') # Will set them both
190+
vc.xyscale('linear', 'area_wt') # Will set them both
191191
192192
Specify the line style:
193-
vc.line=0 # Same as vc.line='solid'
194-
vc.line=1 # Same as vc.line='dash'
195-
vc.line=2 # Same as vc.line='dot'
196-
vc.line=3 # Same as vc.line='dash-dot'
197-
vc.line=4 # Same as vc.line='long-dot'
193+
vc.line=0 # Same as vc.line='solid'
194+
vc.line=1 # Same as vc.line='dash'
195+
vc.line=2 # Same as vc.line='dot'
196+
vc.line=3 # Same as vc.line='dash-dot'
197+
vc.line=4 # Same as vc.line='long-dot'
198198
199199
Specify the line color of the vectors:
200-
vc.linecolor=16 # Color range: 16 to 230, default line color is black
201-
vc.linewidth=1 # Width range: 1 to 100, default size is 1
200+
vc.linecolor=16 # Color range: 16 to 230, default line color is black
201+
vc.linewidth=1 # Width range: 1 to 100, default size is 1
202202
203203
Specify the vector scale factor:
204-
vc.scale=2.0 # Can be an integer or float
204+
vc.scale=2.0 # Can be an integer or float
205205
206206
Specify the vector alignment:
207-
vc.alignment=0 # Same as vc.alignment='head'
208-
vc.alignment=1 # Same as vc.alignment='center'
209-
vc.alignment=2 # Same as vc.alignment='tail'
207+
vc.alignment=0 # Same as vc.alignment='head'
208+
vc.alignment=1 # Same as vc.alignment='center'
209+
vc.alignment=2 # Same as vc.alignment='tail'
210210
211211
Specify the vector type:
212-
vc.type=0 # Same as vc.type='arrow head'
213-
vc.type=1 # Same as vc.type='wind barbs'
214-
vc.type=2 # Same as vc.type='solid arrow head'
212+
vc.type=0 # Same as vc.type='arrow head'
213+
vc.type=1 # Same as vc.type='wind barbs'
214+
vc.type=2 # Same as vc.type='solid arrow head'
215215
216216
Specify the vector reference:
217-
vc.reference=4 # Can be an integer or float
217+
vc.reference=4 # Can be an integer or float
218218
"""
219219
__slots__ = [
220220
'name',
@@ -244,6 +244,9 @@ class Gv(object):
244244
'type',
245245
'reference',
246246
'colormap',
247+
'scaleoptions',
248+
'scaletype',
249+
'scalerange',
247250
'_name',
248251
'_xaxisconvert',
249252
'_yaxisconvert',
@@ -270,9 +273,13 @@ class Gv(object):
270273
'_type',
271274
'_reference',
272275
'_colormap',
276+
'_scaleoptions',
277+
'_scaletype',
278+
'_scalerange',
273279
]
274280

275281
colormap = VCS_validation_functions.colormap
282+
scaleoptions = ('off', 'constant', 'normalize', 'linear', 'constantNNormalize', 'constantNLinear')
276283

277284
def _getname(self):
278285
return self._name
@@ -528,6 +535,30 @@ def _setalignment(self, value):
528535
self._alignment = value
529536
alignment = property(_getalignment, _setalignment)
530537

538+
def _getscaletype(self):
539+
return self._scaletype
540+
541+
def _setscaletype(self, value):
542+
value = VCS_validation_functions.checkInStringList(self,
543+
'scaletype',
544+
value,
545+
self.scaleoptions)
546+
self._scaletype = value
547+
scaletype = property(_getscaletype, _setscaletype)
548+
549+
def _getscalerange(self):
550+
return self._scalerange
551+
552+
def _setscalerange(self, value):
553+
value = VCS_validation_functions.checkListOfNumbers(self,
554+
'scalerange',
555+
value,
556+
minvalue=0.0,
557+
minelements=2,
558+
maxelements=2)
559+
self._scalerange = value
560+
scalerange = property(_getscalerange, _setscalerange)
561+
531562
def __init__(self, Gv_name, Gv_name_src='default'):
532563
# #
533564
###########################################################
@@ -568,6 +599,8 @@ def __init__(self, Gv_name, Gv_name_src='default'):
568599
self._datawc_timeunits = "days since 2000"
569600
self._datawc_calendar = 135441
570601
self._colormap = None
602+
self._scaletype = self.scaleoptions[4]
603+
self._scalerange = [0.1, 1.0]
571604
else:
572605
if isinstance(Gv_name_src, Gv):
573606
Gv_name_src = Gv_name_src.name
@@ -583,7 +616,9 @@ def __init__(self, Gv_name, Gv_name_src='default'):
583616
'datawc_x2', 'xaxisconvert', 'yaxisconvert',
584617
'line', 'linecolor', 'linewidth',
585618
'datawc_timeunits', 'datawc_calendar', 'colormap',
586-
'scale', 'alignment', 'type', 'reference']:
619+
'scale', 'alignment', 'type', 'reference', 'scaletype',
620+
'scalerange']:
621+
587622
setattr(self, att, getattr(src, att))
588623
# Ok now we need to stick in the elements
589624
vcs.elements["vector"][Gv_name] = self
@@ -660,6 +695,8 @@ def list(self):
660695
print "alignment = ", self.alignment
661696
print "type = ", self.type
662697
print "reference = ", self.reference
698+
print "scaletype = ", self.scaletype
699+
print "scalerange = ", self.scalerange
663700

664701
##########################################################################
665702
# #
@@ -798,6 +835,9 @@ def script(self, script_filename=None, mode=None):
798835
fp.write("%s.linecolor = %s\n" % (unique_name, self.linecolor))
799836
fp.write("%s.linewidth = %s\n" % (unique_name, self.linewidth))
800837
fp.write("%s.scale = %s\n" % (unique_name, self.scale))
838+
fp.write("%s.scaletype = %s\n" % (unique_name, self.scaletype))
839+
fp.write("%s.scalerange = %s\n" % (unique_name, self.scalerange))
840+
fp.write("%s.scaleoptions = %s\n" % (unique_name, self.scaleoptions))
801841
fp.write("%s.alignment = '%s'\n" % (unique_name, self.alignment))
802842
fp.write("%s.type = '%s'\n" % (unique_name, self.type))
803843
fp.write("%s.reference = %s\n\n" % (unique_name, self.reference))
@@ -814,5 +854,5 @@ def script(self, script_filename=None, mode=None):
814854

815855

816856
###############################################################################
817-
# END OF FILE #
857+
# END OF FILE #
818858
###############################################################################

testing/vcs/CMakeLists.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -908,6 +908,16 @@ cdat_add_test(test_vcs_settings_color_name_rgba
908908
${cdat_SOURCE_DIR}/testing/vcs/test_vcs_vectors_robinson_wrap.py
909909
"${BASELINE_DIR}/test_vcs_vectors_robinson_wrap.png"
910910
)
911+
cdat_add_test(test_vcs_vectors_scale_options
912+
"${PYTHON_EXECUTABLE}"
913+
${cdat_SOURCE_DIR}/testing/vcs/test_vcs_vectors_scale_options.py
914+
"${BASELINE_DIR}/test_vcs_vectors_scale_options_off.png"
915+
"${BASELINE_DIR}/test_vcs_vectors_scale_options_constant.png"
916+
"${BASELINE_DIR}/test_vcs_vectors_scale_options_linear.png"
917+
"${BASELINE_DIR}/test_vcs_vectors_scale_options_normalize.png"
918+
"${BASELINE_DIR}/test_vcs_vectors_scale_options_constantNLinear.png"
919+
"${BASELINE_DIR}/test_vcs_vectors_scale_options_constantNNormalize.png"
920+
)
911921
endif()
912922
endif()
913923

0 commit comments

Comments
 (0)