Search code examples
imagepython-2.7matplotlibpython-imaging-librarygrayscale

Greyscale in python - incorect colors changing from dark grey to light grey to dark grey


I am plotting a greyscale version of this image: a busy cat

SOURCE: http://matplotlib.org/examples/pylab_examples/griddata_demo.html

I have used the following code:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cm
from PIL import Image

file_name = 'griddata_demo.png'
def func_grey(fname):
    image = Image.open(fname).convert("L")
    arr = np.asarray(image)
    plt.imshow(arr, cmap = cm.Greys_r)
    plt.show()

func_grey(file_name)

Display image as grayscale using matplotlib

The setup I am working is has python 2.7 and Pandas and I have installed Pillow with easy install.

Background information about the image and the requirements:

  1. The image come from data found here. Ideally, the greyscale version of this image should be generated directly from this raw data.i.e. do not save it as a colored image and then try to convert to greyscale - rather just produce a greyscale version of the plot.
  2. I do not know the colors that correspond to the z-values - these colors can be set arbitrarily.
  3. The color map of the image can also be chosen arbitrarily - there is no preference. It is the greyscale version that is of concern.

My question is related to the color scheme shown in the colorbar. I need to display a color scheme where the color bar has colors from light grey (lowest intensity) to dark grey (highest intensity).

After running the above code, a greyscale image is produced. In the color bar of the greyscale image, the intensity level -0.36 is dark grey. At 0.00, it is light grey. But then 0.48 is also dark grey.

Question: Is is possible to change the colormap such that -0.36 is light grey and 0.48 is dark grey? I mean, is it possible to display to colorbar from light to dark?


Solution

  • I think this question may be about how to use a grayscale colormap in matplotlib. If so, then it's straightforward. Here's an example using different colormaps (based on the code for the op image):

    enter image description here

    from numpy.random import uniform, seed
    from matplotlib.mlab import griddata
    import matplotlib.pyplot as plt
    import numpy as np
    # make up data.
    #npts = int(raw_input('enter # of random points to plot:'))
    
    def f(spi, the_colormap):
        plt.subplot(spi)
        seed(0)
        npts = 200
        x = uniform(-2, 2, npts)
        y = uniform(-2, 2, npts)
        z = x*np.exp(-x**2 - y**2)
        xi = np.linspace(-2.1, 2.1, 100)
        yi = np.linspace(-2.1, 2.1, 200)
        zi = griddata(x, y, z, xi, yi, interp='linear')
    
        CS = plt.contour(xi, yi, zi, 15, linewidths=0.5, colors='k')
        CS = plt.contourf(xi, yi, zi, 15, cmap=the_colormap,
                          vmax=abs(zi).max(), vmin=-abs(zi).max())
        plt.colorbar()  # draw colorbar
        # plot data points.
        plt.scatter(x, y, marker='o', c='b', s=5, zorder=10)
        plt.xlim(-2, 2)
        plt.ylim(-2, 2)
        plt.title('griddata test (%d points)' % npts)
    
    f(131, plt.cm.rainbow)
    f(132, plt.cm.gray)
    f(133, plt.cm.hot)
    
    plt.show()
    

    If one actually wants to convert to grayscale using PIL (a far less favorable, but sometimes necessary task), it's best to start with a colormap that has monotonic brightness, like hot above, but not rainbow. Also, in the comments I suggested using cubehelix but that's not standard with matplotlib, instead see here. See here for an image of the available matplotlib colormaps.