8000 MPL 3 + Colorbar + PowerNorm bug · Issue #13228 · matplotlib/matplotlib · GitHub
[go: up one dir, main page]

Skip to content
MPL 3 + Colorbar + PowerNorm bug #13228
Closed
@LevN0

Description

@LevN0

Bug report

Bug summary

In MPL v3, when using Colorbar with a linear norm, then changing norm to PowerNorm, breaks the Colorbar under some circumstances. Worked fine in MPL v1 and v2.

Code for reproduction

Minimum necessary test case:

fig, ax = plt.subplots()

data = np.clip(randn(250, 250)*10, 0, 10)

cax = ax.imshow(data)
cbar = fig.colorbar(cax)

cax.norm = mpl.colors.PowerNorm(gamma=2, vmin=0, vmax=10)
cbar.set_norm(cax.norm)
cbar.update_normal(cax)

plt.show()

On matplotlib 3.0.2 the (bug?) result is:

mpl_3

On matplotlib 2.2.3 the (expected) result is:

mpl_2

Result when adding LogNorm to ColorbarBase._use_auto_colorbar_locator (see discussion below) on matplotlib 3.0.2

mpl_3_fixed

Discussion

Few points:

  1. If the image's norm is set prior to fig.colorbar, then the expected result is achieved on 3.0.2 as well.
  2. If vmin/vmax are not set, the result seems correct and matches between 3.0.2 and 2.2.3
  3. cbar.update_bruteforce instead of update_normal does not fix the issue

I looked into the colorbar code, and can see the following:

In ColorbarBase.update_ticks(), if the auto-colorbar is first used (i.e. first branch), then setting PowerNorm calls the second branch (i.e. what it calls the fixed locator branch) once Colorbar.update_normal runs. That exact sequence triggers the issue.

If things are forced to the first branch of ColorbarBase.update_ticks() (e.g. via adding to PowerNorm to ColorbarBase._use_auto_colorbar_locator() ), then a similar result to what one gets from MPL 3.0.2 LogNorm is achieved. If things are forced to the second branch, then the result from MPL 2.2.3 is achieved. However, when first one branch is hit and then PowerNorm hits the second branch, this triggers the issue.

Relevant code from ColorbarBase,

    def _use_auto_colorbar_locator(self):

        return (self.boundaries is None
                and self.values is None
                and ((type(self.norm) == colors.Normalize)
                    or (type(self.norm) == colors.LogNorm)))

    def update_ticks():

        # ... 

        if self._use_auto_colorbar_locator():
            _log.debug('Using auto colorbar locator on colorbar')
            _log.debug('locator: %r', locator)
            long_axis.set_major_locator(locator)
            long_axis.set_major_formatter(formatter)
        else:
            _log.debug('Using fixed locator on colorbar')
            ticks, ticklabels, offset_string = self._ticker(locator, formatter)
            long_axis.set_ticks(ticks)
            long_axis.set_ticklabels(ticklabels)
            long_axis.get_major_formatter().set_offset_string(offset_string)

Expected outcome

Either:

  1. functionality of MPL 2.2.3
  2. functionality of adding PowerNorm to ColorbarBase._use_auto_colorbar_locator.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions

    0