Skip to content

2D Normalization & Colormapping for ScalerMappables #8738

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 35 commits into from

Conversation

patniharshit
Copy link
Contributor

@patniharshit patniharshit commented Jun 9, 2017

PR Summary

This PR is in referance to GSoC project '2D colormaps'.
(Project proposal is here)

  • The BivariateColormap class subclasses Colormap class. After generation it is flattened to 1d look up table.

  • The implementation of BivariateColormap is not perfect yet and just something has been generated to show proof of concept.

  • The bivariate data is identified by ndim == 3 and if an instance of either Bivariate Colormap or Norm has been passed in. This data is normalized and mapped to univariate integer index so as to directly index flattened BivariateColormap.

  • Plotting some air temperature and surface pressure data:
    bivariate

Feel free to review.

@story645 @tacaswell

PR Checklist

  • Has Pytest style unit tests
  • Code is PEP 8 compliant
  • New features are documented, with examples if plot related
  • Documentation is sphinx and numpydoc compliant
  • Added an entry to doc/users/whats_new.rst if major new feature
  • Documented in doc/api/api_changes.rst if API changed in a backward-incompatible way

@@ -1346,6 +1346,60 @@ def __call__(self, value, clip=None):
def inverse(self, value):
return value

class Norm2d:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"BivariateNorm" just so that it can follow the mpl convention of "Xnorm"?

"""
Normalize a list of two values corresponding to two 1D normalizers
"""
def __init__(self, norm_instances=None):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there are a reason norm_instances = none and is not:

def __init__(self, norm1 = None, norm2 = None):

Copy link
Contributor Author

@patniharshit patniharshit Jun 9, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No reason. I think what you are proposing is more convenient from user's perspective.

norm_instances :
A list of length two having instances of 1D normalizers
"""
if norm_instances is None:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do you handle the use case [BoundaryNorm(), None] or [None, BoundaryNorm]?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes this should be handled.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is being handled now.

@anntzer
Copy link
Contributor

anntzer commented Jun 10, 2017

How would this relate to actual plotting functions?

@patniharshit
Copy link
Contributor Author

@anntzer Currently, functions like imshow, pcolormesh, scalar mappable etc expects 1D normalizer. To extend their support for bivariate colormaps there is a need for bivariate norm also.

@anntzer
Copy link
Contributor

anntzer commented Jun 10, 2017

I understand, but right now all I see this PR implements is some trivial way of combining to normalizers. If there's no bigger example usage, it's hard to judge whether that's sufficient, or too simple, or too complex.
For example, would it be better to just have a generic n-dimensional normalizer?

@story645
Copy link
Member

story645 commented Jun 11, 2017

This should stay in its own PR for reviewing ease, but what about postponing the decision on whether to merge this until the whole set of 2d coloring PRs come in?

The issue with an N-color normalizer (I like it in theory/kinda agree on creating it and then sub classing to this) is that past 3 variables it's not really implementable.

@anntzer
Copy link
Contributor

anntzer commented Jun 11, 2017

I agree with keeping the PR open for now.

Not sure why you cannot have more three dimensions, at the end we're just writing a mapping from R^n -> {colors}.

@story645
Copy link
Member

story645 commented Jun 11, 2017

Yes, you can technically have N dimensions, but:
1 dim = colorbar
2 dim - color wheel/ color square
3 dim - color triangle
1 free dim - alph
More dims - open research problem

@anntzer
Copy link
Contributor

anntzer commented Jun 11, 2017

Well a color triangle really is only two dimensional (the third variable is determined by the first two).
Again, as this PR does not discuss how to plot the "colorbar" at all it's hard to judge...

Copy link
Contributor

@anntzer anntzer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Further PRs on nonscalar normalizers need to come in before we can judge whether this design makes sense.

@story645 story645 changed the title 2D normalizer [WIP] 2D normalizer Jun 11, 2017
@patniharshit patniharshit force-pushed the norm2d branch 2 times, most recently from 1a3d16b to 8e93d20 Compare July 7, 2017 12:51
@patniharshit patniharshit force-pushed the norm2d branch 2 times, most recently from 13627d3 to 2f8b5bf Compare July 23, 2017 17:22

if len(args) == 1:
C = np.asanyarray(args[0])
isBivari = (isinstance(norm, mcolors.BivariateNorm) or
Copy link
Contributor

@anntzer anntzer Jul 23, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

try to stick to pep8 (is_bivar)
also this can br written as isinstance(norm, (mcolors.BivariateNorm, mcolors.BivariateColormap))
(similarly below)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated.

Copy link
Contributor Author

@patniharshit patniharshit Jul 29, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The previous change was reverted because two different variables norm and cmap are being checked for their respective instances.

xlabel='',
ylabel='',
):
#: The axes that this colorbar lives in.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unless there is a strong reason to expose them, attributes should be private (start with an underscore) by default. Otherwise, they all become part of the public API, which is very difficult to change while maintaining back-compatibility.
(Same comment throughout the PR.)

Copy link
Contributor Author

@patniharshit patniharshit Jul 27, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any specific attribute you are pointing to? I tried to keep it similar to ColorbarBase class.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ax is probably fine to stay public (it is public on every Artist), but the xvalues, xboundaries, etc can probably be made private.

isNorm = isinstance(norm, (mcolors.Normalize, mcolors.BivariateNorm))
if norm is not None and not isNorm:
msg = "'norm' must be an instance of 'mcolors.Normalize' " \
"or 'mcolors.BivariateNorm'"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't BivariateNorm subclass Normalize? 'specially since now it's normalizing down to a 1d space?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BivariateNorm does not inherit anything from Normalize so I thought it should not subclass it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the new design, BivariateNorm should havel all the same classes as Normalize...and I think subclassing it so it's registered generically as a Norm is preferable to having to treat it as a special case when it doesn't need to be.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be done with an ABC https://docs.python.org/3/library/abc.html#abc.ABCMeta.register which both Normalize and BivariateNorm register with.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, but I don't see a reason why BivariateNorm shouldn't be subclassing Norm as it has the same architecture as any other norm...take data (scaler or vector)->map to 1D lut value ->get color, and color ->lut->scaler/vector.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the code paths are completely different, why force the sub-class? In general, sub-classing is only worth it when you can share significant amounts of implementation details, otherwise duck-typing is better.

Copy link
Member

@story645 story645 Jul 28, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My point is mostly that the code paths shouldn't end up being all that different and more to the point in mpl land there's probably a ton of code that checks if things are norms and if this code works in those instances it doesn't make sense to change all that code to cover both cases when this is still fundamentally a norm. But I think I'm on the same page as you on the solution maybe being a "Norm" metaclass.

temp[0] = temp[0] * (256)
temp[1] = temp[1] * (256)
temp = temp.astype(int)
return temp[0] + temp[1] * 256
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you guarantee that this scheme always yields uniqueness?
(I'm confused about what's going on here and sort of have been thinking about a more general mapping between nd arrays and numbers wherein you get a sorted unique list of the nd tuples in the dataset so that the lookup/map is just the index of the value in the sorted list.

Copy link
Contributor Author

@patniharshit patniharshit Jul 27, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since after normalization every variable ends up between 0 to 1. So here I am changing it to index flattened 1d lut of BivariateColormap by mapping 0-1 to 1 to 256*256. Here I am currently hardcoding 256 as number of rows and columns in lut of 2d colormap. But this should be changed somehow to use N attribute of BivariateColormap.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is column major indexing (row * num_cols + col is c / numpy style, col * num_rows + row).

I am more concerned that the descritization is happening here rather than in the color map (which is done https://github.com/matplotlib/matplotlib/blob/master/lib/matplotlib/colors.py#L483) which prevents the size of the colormap from having to be known by the norm.

Why can't this return a Nd array? I think the most important places the norm and color map are called is https://github.com/matplotlib/matplotlib/blob/master/lib/matplotlib/cm.py#L209 and
https://github.com/matplotlib/matplotlib/blob/master/lib/matplotlib/image.py#L365 . In the first case it can be blindly passed through and in the second that resampling needs to happen over each plane.

In the case of the color bar, that already needs to be heavily special cased.

20:11 $ git grep '\.norm[ (]' | grep -v linalg
lib/matplotlib/cm.py:        self.norm = norm
lib/matplotlib/cm.py:            x = self.norm(x)
lib/matplotlib/cm.py:        self.norm = norm
lib/matplotlib/collections.py:        self.norm = other.norm
lib/matplotlib/colorbar.py:            y = self.norm(self._boundaries.copy())
lib/matplotlib/colorbar.py:            b = self.norm(self._boundaries, clip=False).filled()
lib/matplotlib/colorbar.py:            xn = self.norm(x, clip=False).filled()
lib/matplotlib/colorbar.py:        self.norm = mappable.norm
lib/matplotlib/colorbar.py:                                       facecolor=self.cmap(self.norm(val)),
lib/matplotlib/image.py:                A = self.norm(A)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am still a bit concerned that the descritization is being done here rather than in the color map. Won't this break for any colormap which is not 256 by 256?

@story645 story645 changed the title [WIP] 2D normalizer [WIP] 2D Normalization & Colormapping for ScalerMappables Jul 24, 2017
isNorm = isinstance(norm, (mcolors.Normalize, mcolors.BivariateNorm))
if norm is not None and not isNorm:
msg = "'norm' must be an instance of 'mcolors.Normalize' " \
"or 'mcolors.BivariateNorm'"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be done with an ABC https://docs.python.org/3/library/abc.html#abc.ABCMeta.register which both Normalize and BivariateNorm register with.

temp = np.asarray(X)
if temp.ndim == 3 and isinstance(norm, mcolors.BivariateNorm):
temp = norm(temp)
X = cmap(temp, alpha=self.get_alpha(), bytes=True)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doing this here means you can not change anything about the color map or norm later.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed this.


if len(args) == 1:
C = np.asanyarray(args[0])
isBivari = isinstance(norm, (mcolors.BivariateNorm,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why would the norm ever be a colormap?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for pointing this out. Fixed now.

cmap = mcolors.BivariateColormap()
if norm is None:
norm = mcolors.BivariateNorm()
C = norm(C)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do this up-front? defering all of this to _make_image means the colormap and norm and be updated.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check now.

linthresh=norm.linthresh,
base=10)
else:
if mpl.rcParams['_internal.classic_mode']:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't need any of the classic shims as there is no back-compatibility to maintain.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed.

or len(self._x) >= self.n_rasterize):
self.solids.set_rasterized(True)

def _ticker(self, norm):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably better to factor this as def _make_ticker(norm, values, boundaries, locator, formatter): as a local function in update_ticks.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean local/private function of class or nested function?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nested function

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

temp[0] = temp[0] * (256)
temp[1] = temp[1] * (256)
temp = temp.astype(int)
return temp[0] + temp[1] * 256
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is column major indexing (row * num_cols + col is c / numpy style, col * num_rows + row).

I am more concerned that the descritization is happening here rather than in the color map (which is done https://github.com/matplotlib/matplotlib/blob/master/lib/matplotlib/colors.py#L483) which prevents the size of the colormap from having to be known by the norm.

Why can't this return a Nd array? I think the most important places the norm and color map are called is https://github.com/matplotlib/matplotlib/blob/master/lib/matplotlib/cm.py#L209 and
https://github.com/matplotlib/matplotlib/blob/master/lib/matplotlib/image.py#L365 . In the first case it can be blindly passed through and in the second that resampling needs to happen over each plane.

In the case of the color bar, that already needs to be heavily special cased.

20:11 $ git grep '\.norm[ (]' | grep -v linalg
lib/matplotlib/cm.py:        self.norm = norm
lib/matplotlib/cm.py:            x = self.norm(x)
lib/matplotlib/cm.py:        self.norm = norm
lib/matplotlib/collections.py:        self.norm = other.norm
lib/matplotlib/colorbar.py:            y = self.norm(self._boundaries.copy())
lib/matplotlib/colorbar.py:            b = self.norm(self._boundaries, clip=False).filled()
lib/matplotlib/colorbar.py:            xn = self.norm(x, clip=False).filled()
lib/matplotlib/colorbar.py:        self.norm = mappable.norm
lib/matplotlib/colorbar.py:                                       facecolor=self.cmap(self.norm(val)),
lib/matplotlib/image.py:                A = self.norm(A)

self.ax.set_xlabel(self._xlabel, **self._labelkw)
self.stale = True

def set_label(self, xlabel, ylabel, **kw):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The different signature from the ColorBar base class is a bit problematic, but not sure what to do about it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

perhaps set_labels(self, xylabel) (where xylabel=(xlabel, ylabel)); set_xlabel; set_ylabel?
let set_label raise an error
this likely would play better with traitlets

@story645 story645 changed the title [WIP] 2D Normalization & Colormapping for ScalerMappables 2D Normalization & Colormapping for ScalerMappables Aug 20, 2017
@patniharshit
Copy link
Contributor Author

@anntzer can you have a look at this PR again? Some things have changed since your last review.

C = C.ravel()
# convert to one dimensional arrays if univariate
if isinstance(norm, mcolors.BivariateNorm):
C = np.asarray([C[0].ravel(), C[1].ravel()])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This may be better done as np.asarray([c.ravel() for c in C]) to be a bit future proof.

msg = "'norm' must be an instance of 'mcolors.Normalize'"

if norm is not None and not isinstance(norm, mcolors.Norms):
msg = "'norm' must be an instance of 'mcolors.Normalize' " \
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have a style preference for using () for continuation rather than \ so

msg = ('...' +
       '...')

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The + is not needed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.


if len(args) == 1:
C = np.asanyarray(args[0])
numRows, numCols = C.shape
isBivari = (isinstance(norm, mcolors.BivariateNorm)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use_underscores_notCapsForVariables

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed isBivari to is_bivari.

@@ -730,7 +730,8 @@ def update_scalarmappable(self):
"""
if self._A is None:
return
if self._A.ndim > 1:
if (self._A.ndim > 1 and
not isinstance(self.norm, mcolors.BivariateNorm)):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should check ndim == 2 in this case?

"""
Label the axes of the colorbar
"""
self._xlabel = '%s' % (xlabel, )
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just self._xlabel = xlabel should be enough (unless we explicitly want to support any object via conversion to string, and even then str(xlabel) is clearer.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just imitating how it is done in ColorbarBase.set_label.

"""
Abstract Base Class to group `Normalize` and `BivariateNorm`
"""
__metaclass__ = ABCMeta
Copy link
Contributor

@anntzer anntzer Aug 20, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

definitely wrong on Py3
use six
should have been caught by pycodestyle perhaps?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed now.

@tacaswell
Copy link
Member

Appveyor seems to be having issues with connectivity the last day or so. It is failing on almost all PRs.

The circle / docs failures do need to be fixed though.

# Bivariate plotting demo
# -----------------------

air_temp = np.load(get_sample_data('air_temperature.npy'))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How big are these data files? I have a slight preference for 'generated' data for examples (to keep the repository size small).

Copy link
Contributor Author

@patniharshit patniharshit Aug 27, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

84.2 kB each.
Couldn't come up with generated data so used these.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That isn't too bad, suspect that is smaller than the test images.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One argument in favour of this can be that the user seeing the example might relate to use case of bivariate plotting better with a real world example than with some mathematical function.

to colors based on the `norm` (mapping scalar to scalar)
and the `cmap` (mapping the normed scalar to a color).

cmap : `~matplotlib.colors.Colormap`, optional, default: None
cmap : `~matplotlib.colors.Colormap`,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the one exception to the () over \ rule so that numpydoc correctly grabs this as a single lin.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These might be the source of the docs failures?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added \ but still failing.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is probably fastest to build the docs locally. That also lets you get access to the full traceback.

pip install -r doc-requirements.txt
cd docs
python make.py html

should work.

@tacaswell tacaswell added this to the 2.2 (next next feature release) milestone Aug 27, 2017
@tacaswell
Copy link
Member

This is looking good 👍

@tacaswell
Copy link
Member

Can you build the docs locally?

@patniharshit
Copy link
Contributor Author

@tacaswell doc build is passing now.

@tacaswell
Copy link
Member

@patniharshit I broke your branch via #8966 this needs to be rebased (sorry).

I think it is ok to either just update the shim around the resampling code or to move it all into a loop (I think clearer now) to resample each plane.

@patniharshit
Copy link
Contributor Author

I don't have access to my laptop for two days. Will resolve the conflicts by Wednesday.

- MxNx3 -- RGB (float or uint8)
- MxNx4 -- RGBA (float or uint8)
- 2xMxN -- bivariate values to be mapped (float or int)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens when the input is shape (2, 3, 4)?

This sort of ambiguity should be avoided (and indicates that this API is probably not the right design choice).

Copy link
Member

@jklymak jklymak left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR came up in #14168.

I'm not sure the status of this, but in case someone comes back to it...

This looks technically well done. However, I'm not a fan of this API (see @shoyer comment as well). Its very complex from a documentation point of view. There is no way from the dosctrings that someone who didn't know what this PR did would understand what is meant by "2xMxN -- bivariate values to be mapped (float or int)". Further propagating support for two norms across all the 2-D plotting functions is going to be a maintenance nightmare. I'd far prefer this just got its own methods, i.e.: ax.bivariate_pcolormesh(x, y, Z1, Z1, norm1, norm2) etc.

I'm also very concerned about adding a whole new colorbar implementation. Maybe its unavoidable, but given that its so different, I wonder if it should also get its own method...

@shoyer
Copy link

shoyer commented May 8, 2019

I agree with putting this into a separate API. imshow is already pretty overloaded.

In shaping this API, I think it would be helping to identify clear use-cases / critical user journeys and make sure they are well supported and documented. For example, one good use case is visualizing complex-valued functions with luminosity and (perceptually uniform?) hue.

My concern is that in general this isn't a terribly effective visualization technique. That's not to say matplotlib shouldn't have this functionality, but let's try to limit its impact on the rest of the API.

@jklymak
Copy link
Member

jklymak commented May 8, 2019

My concern is that in general this isn't a terribly effective visualization technique. That's not to say matplotlib shouldn't have this functionality, but let's try to limit its impact on the rest of the API.

My use case is shading a quantity based on gradient strength... If you'll forgive the sacrilege of linking to mathworks. The API for this was just:

shadedpcolor(x,z,U,(dU),[-1 1]/4,[-1 1]/300,0.7,cmp,0); 
axis ij; 
shadedcolorbar('v',[-1 1]/4,0.7,cmp);

https://www.mathworks.com/matlabcentral/fileexchange/14157-shaded-pseudo-color

@github-actions
Copy link

Since this Pull Request has not been updated in 60 days, it has been marked "inactive." This does not mean that it will be closed, though it may be moved to a "Draft" state. This helps maintainers prioritize their reviewing efforts. You can pick the PR back up anytime - please ping us if you need a review or guidance to move the PR forward! If you do not plan on continuing the work, please let us know so that we can either find someone to take the PR over, or close it.

@github-actions github-actions bot added the status: inactive Marked by the “Stale” Github Action label Apr 13, 2023
@story645 story645 mentioned this pull request Aug 24, 2023
@timhoffm
Copy link
Member

This is superseeded. Tracked in #14168, and worked on in #28658, #28454, #29221.

@timhoffm timhoffm closed this Dec 13, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: inactive Marked by the “Stale” Github Action status: needs rebase
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants