Skip to content

Commit

Permalink
Merge pull request #1988 from UV-CDAT/fix_vector_scale
Browse files Browse the repository at this point in the history
Compute vector scaling correctly
  • Loading branch information
aashish24 committed May 31, 2016
2 parents 7152d0c + 8c05ac4 commit 8a8c1e9
Show file tree
Hide file tree
Showing 8 changed files with 297 additions and 72 deletions.
10 changes: 6 additions & 4 deletions Packages/testing/regression.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,15 @@ def init(*args, **kwargs):
testingDir = os.path.join(os.path.dirname(__file__), "..")
sys.path.append(testingDir)

vcsinst = vcs.init(*args, **kwargs)
vcsinst.setantialiasing(0)
vcsinst.drawlogooff()

if ((('bg' in kwargs and kwargs['bg']) or ('bg' not in kwargs)) and
('geometry' not in kwargs)):
vcsinst = vcs.init(*args, **dict(kwargs, bg=1))
vcsinst.setbgoutputdimensions(1200, 1091, units="pixels")
else:
vcsinst = vcs.init(*args, **dict(kwargs, bg=0))

vcsinst.setantialiasing(0)
vcsinst.drawlogooff()
return vcsinst

def run(vcsinst, fname, baseline=sys.argv[1], threshold=defaultThreshold):
Expand Down
12 changes: 12 additions & 0 deletions Packages/vcs/vcs/VCS_validation_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,18 @@ def checkListOfNumbers(self, name, value, minvalue=None,
return list(value)


def checkInStringList(self, name, value, options):
checkName(self, name, value)
if value not in options:
self.checkedRaise(
self,
value,
ValueError,
'Invalid value ' + value + '. Valid options are: ' +
','.join(self.scaleoptions))
return value


def checkFont(self, name, value):
if (value is None):
pass
Expand Down
74 changes: 66 additions & 8 deletions Packages/vcs/vcs/vcsvtk/vectorpipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ def _plotInternal(self):
# Preserve time and z axis for plotting these inof in rendertemplate
projection = vcs.elements["projection"][self._gm.projection]
taxis = self._originalData1.getTime()
scaleFactor = 1.0

if self._originalData1.ndim > 2:
zaxis = self._originalData1.getAxis(-3)
else:
Expand Down Expand Up @@ -84,24 +86,80 @@ def _plotInternal(self):
arrow.SetOutputPointsPrecision(vtk.vtkAlgorithm.DOUBLE_PRECISION)
arrow.FilledOff()

polydata = self._vtkPolyDataFilter.GetOutput()
vectors = polydata.GetPointData().GetVectors()

if self._gm.scaletype == 'constant' or\
self._gm.scaletype == 'constantNNormalize' or\
self._gm.scaletype == 'constantNLinear':
scaleFactor = scale * 2.0 * self._gm.scale
else:
scaleFactor = 1.0

glyphFilter = vtk.vtkGlyph2D()
glyphFilter.SetInputConnection(self._vtkPolyDataFilter.GetOutputPort())
glyphFilter.SetInputData(polydata)
glyphFilter.SetInputArrayToProcess(1, 0, 0, 0, "vector")
glyphFilter.SetSourceConnection(arrow.GetOutputPort())
glyphFilter.SetVectorModeToUseVector()

# Rotate arrows to match vector data:
glyphFilter.OrientOn()
glyphFilter.ScalingOn()

# Scale to vector magnitude:
glyphFilter.SetScaleModeToScaleByVector()
glyphFilter.SetScaleFactor(scale * 2.0 * self._gm.scale)

# These are some unfortunately named methods. It does *not* clamp the
# scale range to [min, max], but rather remaps the range
# [min, max] --> [0, 1].
glyphFilter.ClampingOn()
glyphFilter.SetRange(0.01, 1.0)
if self._gm.scaletype == 'normalize' or self._gm.scaletype == 'linear' or\
self._gm.scaletype == 'constantNNormalize' or self._gm.scaletype == 'constantNLinear':

# Find the min and max vector magnitudes
maxNorm = vectors.GetMaxNorm()

if maxNorm == 0:
maxNorm = 1.0

if self._gm.scaletype == 'normalize' or self._gm.scaletype == 'constantNNormalize':
scaleFactor /= maxNorm

if self._gm.scaletype == 'linear' or self._gm.scaletype == 'constantNLinear':
minNorm = None
maxNorm = None

noOfComponents = vectors.GetNumberOfComponents()
for i in range(0, vectors.GetNumberOfTuples()):
norm = vtk.vtkMath.Norm(vectors.GetTuple(i), noOfComponents)

if (minNorm is None or norm < minNorm):
minNorm = norm
if (maxNorm is None or norm > maxNorm):
maxNorm = norm

if maxNorm == 0:
maxNorm = 1.0

scalarArray = vtk.vtkDoubleArray()
scalarArray.SetNumberOfComponents(1)
scalarArray.SetNumberOfValues(vectors.GetNumberOfTuples())

oldRange = maxNorm - minNorm
oldRange = 1.0 if oldRange == 0.0 else oldRange

# New range min, max.
newRangeValues = self._gm.scalerange
newRange = newRangeValues[1] - newRangeValues[0]

for i in range(0, vectors.GetNumberOfTuples()):
norm = vtk.vtkMath.Norm(vectors.GetTuple(i), noOfComponents)
newValue = (((norm - minNorm) * newRange) / oldRange) + newRangeValues[0]
scalarArray.SetValue(i, newValue)
polydata.GetPointData().SetScalars(scalarArray)

# Scale to vector magnitude:
# NOTE: Currently we compute our own scaling factor since VTK does
# it by clamping the values > max to max and values < min to min
# and not remap the range.
glyphFilter.SetScaleModeToScaleByScalar()

glyphFilter.SetScaleFactor(scaleFactor)

mapper = vtk.vtkPolyDataMapper()

Expand Down
110 changes: 75 additions & 35 deletions Packages/vcs/vcs/vector.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ def process_src(nm, code):
class Gv(object):

"""
Class: Gv # Vector
Class: Gv # Vector
Description of Gv Class:
The vector graphics method displays a vector plot of a 2D vector field. Vectors
Expand All @@ -145,76 +145,76 @@ class Gv(object):
entry.
Other Useful Functions:
a=vcs.init() # Constructor
a.show('vector') # Show predefined vector graphics methods
a.show('line') # Show predefined VCS line objects
a.setcolormap("AMIP") # Change the VCS color Map
a.vector(s1, s2, v,'default') # Plot data 's1', and 's2' with vector 'v'
a=vcs.init() # Constructor
a.show('vector') # Show predefined vector graphics methods
a.show('line') # Show predefined VCS line objects
a.setcolormap("AMIP") # Change the VCS color Map
a.vector(s1, s2, v,'default') # Plot data 's1', and 's2' with vector 'v'
and 'default' template
a.update() # Updates the VCS Canvas at user's request
a.mode=1, or 0 # If 1, then automatic update, else if
a.update() # Updates the VCS Canvas at user's request
a.mode=1, or 0 # If 1, then automatic update, else if
0, then use update function to
update the VCS Canvas.
Example of Use:
a=vcs.init()
To Create a new instance of vector use:
vc=a.createvector('new','quick') # Copies content of 'quick' to 'new'
vc=a.createvector('new') # Copies content of 'default' to 'new'
vc=a.createvector('new','quick') # Copies content of 'quick' to 'new'
vc=a.createvector('new') # Copies content of 'default' to 'new'
To Modify an existing vector use:
vc=a.getvector('AMIP_psl')
vc.list() # Will list all the vector attribute values
vc.projection='linear' # Can only be 'linear'
vc.list() # Will list all the vector attribute values
vc.projection='linear' # Can only be 'linear'
lon30={-180:'180W',-150:'150W',0:'Eq'}
vc.xticlabels1=lon30
vc.xticlabels2=lon30
vc.xticlabels(lon30, lon30) # Will set them both
vc.xticlabels(lon30, lon30) # Will set them both
vc.xmtics1=''
vc.xmtics2=''
vc.xmtics(lon30, lon30) # Will set them both
vc.xmtics(lon30, lon30) # Will set them both
vc.yticlabels1=lat10
vc.yticlabels2=lat10
vc.yticlabels(lat10, lat10) # Will set them both
vc.yticlabels(lat10, lat10) # Will set them both
vc.ymtics1=''
vc.ymtics2=''
vc.ymtics(lat10, lat10) # Will set them both
vc.ymtics(lat10, lat10) # Will set them both
vc.datawc_y1=-90.0
vc.datawc_y2=90.0
vc.datawc_x1=-180.0
vc.datawc_x2=180.0
vc.datawc(-90, 90, -180, 180) # Will set them all
vc.datawc(-90, 90, -180, 180) # Will set them all
xaxisconvert='linear'
yaxisconvert='linear'
vc.xyscale('linear', 'area_wt') # Will set them both
vc.xyscale('linear', 'area_wt') # Will set them both
Specify the line style:
vc.line=0 # Same as vc.line='solid'
vc.line=1 # Same as vc.line='dash'
vc.line=2 # Same as vc.line='dot'
vc.line=3 # Same as vc.line='dash-dot'
vc.line=4 # Same as vc.line='long-dot'
vc.line=0 # Same as vc.line='solid'
vc.line=1 # Same as vc.line='dash'
vc.line=2 # Same as vc.line='dot'
vc.line=3 # Same as vc.line='dash-dot'
vc.line=4 # Same as vc.line='long-dot'
Specify the line color of the vectors:
vc.linecolor=16 # Color range: 16 to 230, default line color is black
vc.linewidth=1 # Width range: 1 to 100, default size is 1
vc.linecolor=16 # Color range: 16 to 230, default line color is black
vc.linewidth=1 # Width range: 1 to 100, default size is 1
Specify the vector scale factor:
vc.scale=2.0 # Can be an integer or float
vc.scale=2.0 # Can be an integer or float
Specify the vector alignment:
vc.alignment=0 # Same as vc.alignment='head'
vc.alignment=1 # Same as vc.alignment='center'
vc.alignment=2 # Same as vc.alignment='tail'
vc.alignment=0 # Same as vc.alignment='head'
vc.alignment=1 # Same as vc.alignment='center'
vc.alignment=2 # Same as vc.alignment='tail'
Specify the vector type:
vc.type=0 # Same as vc.type='arrow head'
vc.type=1 # Same as vc.type='wind barbs'
vc.type=2 # Same as vc.type='solid arrow head'
vc.type=0 # Same as vc.type='arrow head'
vc.type=1 # Same as vc.type='wind barbs'
vc.type=2 # Same as vc.type='solid arrow head'
Specify the vector reference:
vc.reference=4 # Can be an integer or float
vc.reference=4 # Can be an integer or float
"""
__slots__ = [
'name',
Expand Down Expand Up @@ -244,6 +244,9 @@ class Gv(object):
'type',
'reference',
'colormap',
'scaleoptions',
'scaletype',
'scalerange',
'_name',
'_xaxisconvert',
'_yaxisconvert',
Expand All @@ -270,9 +273,13 @@ class Gv(object):
'_type',
'_reference',
'_colormap',
'_scaleoptions',
'_scaletype',
'_scalerange',
]

colormap = VCS_validation_functions.colormap
scaleoptions = ('off', 'constant', 'normalize', 'linear', 'constantNNormalize', 'constantNLinear')

def _getname(self):
return self._name
Expand Down Expand Up @@ -528,6 +535,30 @@ def _setalignment(self, value):
self._alignment = value
alignment = property(_getalignment, _setalignment)

def _getscaletype(self):
return self._scaletype

def _setscaletype(self, value):
value = VCS_validation_functions.checkInStringList(self,
'scaletype',
value,
self.scaleoptions)
self._scaletype = value
scaletype = property(_getscaletype, _setscaletype)

def _getscalerange(self):
return self._scalerange

def _setscalerange(self, value):
value = VCS_validation_functions.checkListOfNumbers(self,
'scalerange',
value,
minvalue=0.0,
minelements=2,
maxelements=2)
self._scalerange = value
scalerange = property(_getscalerange, _setscalerange)

def __init__(self, Gv_name, Gv_name_src='default'):
# #
###########################################################
Expand Down Expand Up @@ -568,6 +599,8 @@ def __init__(self, Gv_name, Gv_name_src='default'):
self._datawc_timeunits = "days since 2000"
self._datawc_calendar = 135441
self._colormap = None
self._scaletype = self.scaleoptions[4]
self._scalerange = [0.1, 1.0]
else:
if isinstance(Gv_name_src, Gv):
Gv_name_src = Gv_name_src.name
Expand All @@ -583,7 +616,9 @@ def __init__(self, Gv_name, Gv_name_src='default'):
'datawc_x2', 'xaxisconvert', 'yaxisconvert',
'line', 'linecolor', 'linewidth',
'datawc_timeunits', 'datawc_calendar', 'colormap',
'scale', 'alignment', 'type', 'reference']:
'scale', 'alignment', 'type', 'reference', 'scaletype',
'scalerange']:

setattr(self, att, getattr(src, att))
# Ok now we need to stick in the elements
vcs.elements["vector"][Gv_name] = self
Expand Down Expand Up @@ -660,6 +695,8 @@ def list(self):
print "alignment = ", self.alignment
print "type = ", self.type
print "reference = ", self.reference
print "scaletype = ", self.scaletype
print "scalerange = ", self.scalerange

##########################################################################
# #
Expand Down Expand Up @@ -798,6 +835,9 @@ def script(self, script_filename=None, mode=None):
fp.write("%s.linecolor = %s\n" % (unique_name, self.linecolor))
fp.write("%s.linewidth = %s\n" % (unique_name, self.linewidth))
fp.write("%s.scale = %s\n" % (unique_name, self.scale))
fp.write("%s.scaletype = %s\n" % (unique_name, self.scaletype))
fp.write("%s.scalerange = %s\n" % (unique_name, self.scalerange))
fp.write("%s.scaleoptions = %s\n" % (unique_name, self.scaleoptions))
fp.write("%s.alignment = '%s'\n" % (unique_name, self.alignment))
fp.write("%s.type = '%s'\n" % (unique_name, self.type))
fp.write("%s.reference = %s\n\n" % (unique_name, self.reference))
Expand All @@ -814,5 +854,5 @@ def script(self, script_filename=None, mode=None):


###############################################################################
# END OF FILE #
# END OF FILE #
###############################################################################
10 changes: 10 additions & 0 deletions testing/vcs/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -904,6 +904,16 @@ cdat_add_test(test_vcs_settings_color_name_rgba
${cdat_SOURCE_DIR}/testing/vcs/test_vcs_vectors_robinson_wrap.py
"${BASELINE_DIR}/test_vcs_vectors_robinson_wrap.png"
)
cdat_add_test(test_vcs_vectors_scale_options
"${PYTHON_EXECUTABLE}"
${cdat_SOURCE_DIR}/testing/vcs/test_vcs_vectors_scale_options.py
"${BASELINE_DIR}/test_vcs_vectors_scale_options_off.png"
"${BASELINE_DIR}/test_vcs_vectors_scale_options_constant.png"
"${BASELINE_DIR}/test_vcs_vectors_scale_options_linear.png"
"${BASELINE_DIR}/test_vcs_vectors_scale_options_normalize.png"
"${BASELINE_DIR}/test_vcs_vectors_scale_options_constantNLinear.png"
"${BASELINE_DIR}/test_vcs_vectors_scale_options_constantNNormalize.png"
)
endif()
endif()

Expand Down
Loading

0 comments on commit 8a8c1e9

Please sign in to comment.