Interactive Matplotlib colorbar "stretchable" like DS9 or QFitsView colorbar

59 Views Asked by At

If you open any image in DS9 or QFitsView, you can change the colorbar when you click and drag the mouse in two directions:

  • In the vertical direction, you stretch the colormap of the colorbar. If you stretch it too much, you'll have just one color, if you compress too much, you'll have just the min and max colors (black and white).
  • In the horizontal direction, you choose the central value of the colormap. If you drag the mouse to the right, the colormap's central value will be near the min value. If you drag to the left, will be near the max value, both min and max values fixed.

I think I got the result for the image quite right, with my code below, but the colormap doesn't strech, just the ticks/values. I would like to know if I can make a colorbar identical to the qfitsview one, seeing the colormap stretching an not just the ticks/values using matplotlib colorbar. I also don't know if PowerNorm is the right norm to use, because I want the stretch around a central value, and not all the colormap colapsing in the min or max value.

Here's my attempt: The code runs in a jupyter notebook.

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import LogNorm, PowerNorm, SymLogNorm
from ipywidgets import interact, FloatSlider
from matplotlib.ticker import MaxNLocator

data = np.random.rand(10,10)
def update_plot(gamma,vmin,vmax):
    # Create a PowerNorm with the current gamma value and fixed vmin/vmax
    norm = PowerNorm(gamma=gamma, vmin=vmin, vmax=vmax)

    plt.imshow(data, cmap='viridis', norm=norm)
    # Get the current axes and create a ScalarMappable to set the number of levels for the colorbar
    ax = plt.gca()
    sm = plt.cm.ScalarMappable(cmap='viridis', norm=norm)
    sm.set_array(data)  # Set the data to determine colorbar levels

    # Adjust the colorbar to show more levels for stretching effect
    plt.colorbar(sm, ax=ax, extend='both', ticks=MaxNLocator(nbins=10))  # You can adjust nbins as needed
    plt.title(f'Colormap: Viridis, PowerNorm (Gamma: {gamma}, vmin: {vmin}, vmax: {vmax})')
    plt.show()


# Use interact to create the interactive plot with sliders for gamma, vmin, and vmax
interact(update_plot,
         gamma=FloatSlider(value=0.5, min=0.01, max=2.0, step=0.01, description='Gamma'),
         vmin=FloatSlider(value=np.min(data), min=np.min(data), max=np.max(data), step=0.01, description='vmin'),
         vmax=FloatSlider(value=np.max(data), min=np.min(data), max=np.max(data), step=0.01, description='vmax'));
plt.show()
0

There are 0 best solutions below