diff --git a/.circleci/config.yml b/.circleci/config.yml index 4d1f34019..c558419a2 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -22,17 +22,16 @@ aliases: name: create_conda_env environment: CHANNELS: "-c cdat/label/nightly -c conda-forge -c cdat" - PKGS: "cdms2 cdat_info udunits2 testsrunner mesalib matplotlib image-compare genutil dv3d cdutil cdtime nbformat 'vtk-cdat<8.2.0.rc2.289.8.0.2019.01.28.16' 'proj4<5' 'numpy>1.14' ghostscript" + PKGS: "cdms2 cdat_info udunits2 testsrunner mesalib matplotlib image-compare genutil dv3d cdutil cdtime nbformat 'proj4<5' numpy ghostscript vtk-cdat" command: | export PATH=$WORKDIR/miniconda/bin:$PATH conda config --set always_yes yes --set changeps1 no conda update -y -q conda - conda install -n base "conda<4.6" conda config --set anaconda_upload no if [[ $PY_VER = "py2" ]]; then conda create -q -n $PY_VER $CUSTOM_CHANNELS $CHANNELS $PKGS $TEMP_PKGS "python<3" else - conda create -q -n $PY_VER $CUSTOM_CHANNELS $CHANNELS $PKGS $TEMP_PKGS "python>3" nbsphinx easydev $COVERAGE_PKGS + conda create -q -n $PY_VER $CUSTOM_CHANNELS $CHANNELS $PKGS $TEMP_PKGS "python=3.6" nbsphinx easydev $COVERAGE_PKGS fi - &setup_vcs @@ -71,14 +70,6 @@ aliases: fi exit $RESULT - - &templink - name: templink - command: | - export PATH=$WORKDIR/miniconda/bin:$PATH - source activate $PY_VER - rm ${WORKDIR}/miniconda/envs/$PY_VER/bin/python - ln -s $(pwd)/$WORKDIR/miniconda/envs/$PY_VER/bin/vtkpython $(pwd)/$WORKDIR/miniconda/envs/$PY_VER/bin/python - - &conda_upload name: conda_upload environment: @@ -129,7 +120,7 @@ jobs: OS: "osx-64" PY_VER: "py2" TEMP_PKGS: "'ffmpeg>4' 'libpng>1.6.34'" - CUSTOM_CHANNELS: "-c danlipsa" + CUSTOM_CHANNELS: "" steps: - checkout - run: *setup_miniconda @@ -146,19 +137,18 @@ jobs: macos_vcs_py3: macos: - xcode: "9.2.0" + xcode: "10.2.0" environment: WORKDIR: "workspace/test_macos_vcs_py3" OS: "osx-64" PY_VER: "py3" TEMP_PKGS: "'ffmpeg>4' 'libpng>1.6.34'" - CUSTOM_CHANNELS: "-c danlipsa" + CUSTOM_CHANNELS: "" steps: - checkout - run: *setup_miniconda - run: *get_testdata - run: *create_conda_env - - run: *templink - run: *setup_vcs - run: *run_vcs_tests - store_artifacts: diff --git a/recipe/meta.yaml.in b/recipe/meta.yaml.in index 1fc7c0190..2edfd2daa 100644 --- a/recipe/meta.yaml.in +++ b/recipe/meta.yaml.in @@ -23,6 +23,7 @@ requirements: - cdat_info - genutil - dv3d + - libcdms >=3.1.2 - vtk-cdat >8.1 - cdms2 - cdutil diff --git a/tests/test_vcs_vectors_scale.py b/tests/test_vcs_vectors_scale.py index 3ced33b3d..c7a0630da 100644 --- a/tests/test_vcs_vectors_scale.py +++ b/tests/test_vcs_vectors_scale.py @@ -6,7 +6,7 @@ class TestVCSVectorScale(basevcstest.VCSBaseTest): - def coreTest(self, scalingType, scale=None, scalerange=None): + def coreTest(self, scalingType, scale=None, scalerange=None, ref=None): u = cdms2.createAxis(np.array([[1, 1, 0, 1, 1, 1, 0, 1], [1, 1, 0, 1, 1, 1, 0, 1], [1, 1, 0, 1, 1, 1, 0, 1], @@ -32,11 +32,15 @@ def coreTest(self, scalingType, scale=None, scalerange=None): gv.scalerange = scalerange if scale is not None: gv.scale = scale + if ref is not None: + gv.reference = ref self.x.plot(u, v, gv, bg=self.bg, ratio=1) label = scalingType if (scalingType == "constant"): label += "_" + str(scale) outFilename = 'test_vcs_vectors_scale_%s.png' % label + if ref is not None: + outFilename = 'test_vcs_vectors_scale_%s_ref_%s.png' % (label, ref) self.checkImage(outFilename) self.x.clear() @@ -50,4 +54,8 @@ def testVCSVectorScalingOptions(self): # test clamping self.coreTest("constant", scale=0.1) self.coreTest("constant", scale=2) + # test reference + self.coreTest("constant", scale=0.5, ref=1) + self.coreTest("constant", scale=0.1, ref=5) + self.coreTest("constant", scale=2, ref=0.5) testVCSVectorScalingOptions.vectors = 1 diff --git a/vcs/utils.py b/vcs/utils.py index 30e9bb6c0..3a2c73c7d 100644 --- a/vcs/utils.py +++ b/vcs/utils.py @@ -2838,7 +2838,8 @@ def _createLegendString(value, unit): def drawVectorLegend(canvas, templateLegend, linecolor, linetype, linewidth, unitString, maxNormInVp=1., maxNorm=1., - minNormInVp=0., minNorm=0., bg=False, render=True): + minNormInVp=0., minNorm=0., bg=False, render=True, + reference=1e20): """Draws a legend with vector line/text inside a template legend box Auto adjust text size to make it fit inside the box @@ -2895,14 +2896,27 @@ def drawVectorLegend(canvas, templateLegend, :param render: Boolean value indicating whether or not to render the new lines. :type render: `bool`_ + + : param reference: Desired length of reference vector in plot legend. The + default is to choose a reasonable size for the max vector in the legend + based on the amount of space available. This behavior can be + overridden by providing the "reference" parameter, and then the size of + the arrow will be computed to match. Be aware this may cause the arrow + to be very large (not fitting nicely within the legend) or very small, + even invisible. + : type reference: `float`_ """ + useReferenceValue = not numpy.allclose(reference, 1e20) + # Figure out space length text = vcs.createtext(To_source=templateLegend.textorientation, Tt_source=templateLegend.texttable) text.x = .5 text.y = .5 maxLegendString = _createLegendString(maxNorm, unitString) + if useReferenceValue: + maxLegendString = _createLegendString(reference, unitString) text.string = maxLegendString maxExt = canvas.gettextextent(text)[0] @@ -2912,27 +2926,30 @@ def drawVectorLegend(canvas, templateLegend, # space between line and label - one character long spaceLength = (maxExt[1] - maxExt[0]) / len(maxLegendString) - # line vector - min 2 and max 15 characters long - minMaxNormLineLength = 2 * spaceLength - maxMaxNormLineLength = 15 * spaceLength - # clamp lineLegth between 2 and 15 spaceLength maxLineLength = maxNormInVp + if useReferenceValue: + maxLineLength = (maxNormInVp * reference) / maxNorm + else: + # line vector - min 2 and max 15 characters long + minMaxNormLineLength = 2 * spaceLength + maxMaxNormLineLength = 15 * spaceLength + # clamp lineLegth between 2 and 15 spaceLength + ratio = 1.0 + if (maxLineLength < minMaxNormLineLength): + while (maxLineLength < minMaxNormLineLength): + maxLineLength *= 2 + ratio *= 2 + elif (maxLineLength > maxMaxNormLineLength): + while (maxLineLength > maxMaxNormLineLength): + maxLineLength /= 2 + ratio /= 2 + + # update maxLegendString with the clamped value + if (ratio != 1): + maxLegendString = _createLegendString(maxNorm * ratio, unitString) + text.string = maxLegendString + maxExt = canvas.gettextextent(text)[0] minLineLength = minNormInVp - ratio = 1.0 - if (maxLineLength < minMaxNormLineLength): - while (maxLineLength < minMaxNormLineLength): - maxLineLength *= 2 - ratio *= 2 - elif (maxLineLength > maxMaxNormLineLength): - while (maxLineLength > maxMaxNormLineLength): - maxLineLength /= 2 - ratio /= 2 - - # update maxLegendString with the clamped value - if (ratio != 1): - maxLegendString = _createLegendString(maxNorm * ratio, unitString) - text.string = maxLegendString - maxExt = canvas.gettextextent(text)[0] maxLegendLength = maxExt[1] - maxExt[0] maxheight = maxExt[3] - maxExt[2] diff --git a/vcs/vcsvtk/vectorpipeline.py b/vcs/vcsvtk/vectorpipeline.py index e1133abbd..b9204406b 100644 --- a/vcs/vcsvtk/vectorpipeline.py +++ b/vcs/vcsvtk/vectorpipeline.py @@ -245,7 +245,7 @@ def _plotInternal(self): minNormInVp *= worldToViewportXScale vcs.utils.drawVectorLegend( self._context().canvas, self._template.legend, lcolor, lstyle, lwidth, - unitString, maxNormInVp, maxNorm, minNormInVp, minNorm) + unitString, maxNormInVp, maxNorm, minNormInVp, minNorm, reference=self._gm.reference) kwargs['xaxisconvert'] = self._gm.xaxisconvert kwargs['yaxisconvert'] = self._gm.yaxisconvert diff --git a/vcs/vector.py b/vcs/vector.py index d98ae4c67..0b0c80f58 100755 --- a/vcs/vector.py +++ b/vcs/vector.py @@ -308,7 +308,10 @@ class Gv(vcs.bestMatch): .. code-block:: python - # Can be an integer or float + # Can be an integer or float. Setting the reference attribute + # overrides the default behavior of picking a reasonable size + # for the vector legend arrow. This may result in a very large + # or very small arrow, depending on the value of vc.reference. vc.reference=4 """ __slots__ = [ @@ -772,7 +775,7 @@ def list(self): print("datawc_calendar = ", self.datawc_calendar) print("xaxisconvert = ", self.xaxisconvert) print("yaxisconvert = ", self.yaxisconvert) - print("line = ", self.line) + print("linetype = ", self.linetype) print("linecolor = ", self.linecolor) print("linewidth = ", self.linewidth) print("scale = ", self.scale)