feat(styling): add ColorScaling.log for a plain-logarithmic colour scale - #330
Merged
Conversation
ColorScaling could express linear/power/sym-lognorm/boundary-norm/midpoint but not a plain matplotlib LogNorm, even though the string-keyed data-style path (styling.colors) already builds one. So a caller using the typed grouped colour object -- the API pyramids re-exports and Dataset.plot(color=) accepts -- could not ask for a log scale, and sym_log is not a substitute (it is linear within +/-linthresh, so it renders strictly-positive data's low end differently). - Add a LOGNORM member to ColorScale and a ColorScaling.log() variant constructor plus its build_norm branch, producing a LogNorm over the positive tick range. - Extract a shared build_log_norm(vmin, vmax, context=...) helper in styling.colors and route both the data-style norm='log' path and ColorScaling.log() through it, so the two agree on what a log scale requires: a strictly-positive, ascending range. Non-positive ranges raise a clear error steering the caller at a symmetric-log scale. - Tests for the constructor, build_norm, options round-trip, and the shared helper; docs and the norm-dispatch diagram updated. Closes #329
…nt data) A constant positive field yields a single tick, so vmin == vmax, and the LOGNORM branch called build_log_norm(v, v) which raised -- crashing ArrayGlyph.plot(color=ColorScaling.log()) on data every other scale kind renders, with a message that wrongly told the user their (strictly positive) data spans zero/negatives. Widen the zero-width range to [v, v+1], matching the data-style norm='log' path, so the two agree; the error now fires only for genuinely non-positive data. Passing floats also cleans the message.
…log_norm The shared log-range error rendered numpy scalars via !r (e.g. 'vmin=np.float64(5.0)') on the ColorScaling.log() path, and the unified message dropped the concrete keyword the old data-style message gave. Coerce vmin/vmax to plain floats in the message, and add a per-caller 'remedy' argument so the data-style path names norm='symlog' and the ColorScaling path names ColorScaling.sym_log().
The public docs were updated for the new lognorm scale but three in-source docstrings (glyph._create_norm_and_cbar_kw, array_glyph._plot_im_get_cbar_kw, mesh_glyph) still enumerated only the five original scales. Add lognorm.
…gNorm Assert that ArrayGlyph.plot(color=ColorScaling.log()) puts a LogNorm on the image with the expected vmin/vmax -- the render path the PR verified only by hand.
…Scaling.log() The degenerate-range widening ran before build_log_norm built its error, so a constant negative/zero field's message reported the widened vmax (e.g. -4.0 for all -5.0 data) rather than the real bound. Gate the widen on lo > 0 so a non-positive constant raises with its true value; positive constants still widen to [v, v+1].
Round 1 added lognorm to the in-source docstrings but two mesh docs still said 'all 5 color scale types': bump both to 6, add a lognorm row to the scale table, and add ColorScaling.log() to the factory list.
The new LOGNORM member broke test_member_names_and_values, which pins the exact enum value set (it expected the original five). Add lognorm to the set, bump the docstring 'five' -> 'six', and add a case-insensitive construction case for it.
… S5778) The two ColorScaling.log() error tests invoked ColorScaling.log(), build_norm and np.array inside the pytest.raises block. Build the scale and ticks first so only the throwing build_norm call sits in the block.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Description
ColorScalingcould expresslinear/power/sym-lognorm/boundary-norm/midpoint, but not a plainmatplotlib.colors.LogNorm— even though the string-keyed data-style path instyling/colors.pyalready buildsone (with a positive-data check). So a caller using the typed grouped colour object — the API
pyramidsre-exportsand
Dataset.plot(color=...)accepts — could not ask for a plain log scale, andsym_logis not a substitute (itis linear within
+/-linthresh, so it renders strictly-positive data's low end differently and cannot reproduce aLogNorm).This adds the missing variant and, per the issue, makes the two log paths share one validation so they agree on what
a log scale requires.
LOGNORMmember toColorScale("lognorm") and aColorScaling.log()variant constructor plus itsbuild_normbranch, producing aLogNormover the positive tick range (sameLogFormattercolorbar assym_log).build_log_norm(vmin, vmax, *, context=...)helper instyling.colorsand route both thedata-style
norm="log"path andColorScaling.log()through it, so the two agree on the requirement: astrictly-positive, ascending range. A non-positive range raises a clear error steering the caller at a
symmetric-log scale. The data-style path's positive-data fallback (clamping
vminwhen the data hits 0) ispreserved.
Verified end to end:
ArrayGlyph.plot(color=ColorScaling.log())renders aLogNorm; the issue's reproduction nowsucceeds.
Issues
Type of change
How Has This Been Tested?
tests/test_scaling.py—ColorScaling.log().build_norm(...)builds aLogNormover the tickrange, a non-positive range raises (steering at
sym_log), the options round-trip (color_scale="lognorm"->LOGNORM), andlog()emits the full six-key option dict.tests/test_colors.py— the 3 data-stylenorm='log'error tests updated to the unified message; thepositive-vmin-clamp fallback test still passes. The shared
build_log_normhelper carries a doctest.test_scaling.py/test_colors.py/test_glyph.py/test_array_glyph.pyall green(933 passed); doctests on
scaling.py/styles.py/colors.py— 57 passed.ArrayGlyph.plot(color=ColorScaling.log())yieldsim.normof typeLogNorm(vmin=1, vmax=1000).Checklist: