1

This question is in continuation of the solution provided by tcaswell (answer #2) for my question: Is there a way to convert pyplot.imshow() object to numpy array?

Consider the following python code:

import pylab
import numpy as np

a = np.array( ( 30, 129 ) , dtype = np.float32 )
b = np.array( ( 30, 129 ) , dtype = np.int32 )
my_cm = pylab.cm.get_cmap('jet')
a_mapped_data = my_cm( a )
b_mapped_data = my_cm( b )

I am using a small array to save space, but this is what is seen even when large arrays are used.

The results:

>>> a
array([  30.,  129.], dtype=float32)

>>> b
array([ 30, 129])

>>> a_mapped_data
array([[ 0.5,  0. ,  0. ,  1. ],
       [ 0.5,  0. ,  0. ,  1. ]])

>>> b_mapped_data
array([[ 0.        ,  0.        ,  1.        ,  1.        ],
       [ 0.5028463 ,  1.        ,  0.46489564,  1.        ]])

I don't seem to understand the behavior here. Even though the values are same, cm.get_map() instance is producing different results for numpy.int32 and numpy.float32 data types. Is there something wrong with the code above? Please help out with this. I need to plot 2D arrays of type numpy.float.

I am using python 2.7.3 32bit on Windows7 x64 Home Basic

vvvvv
  • 25,404
  • 19
  • 49
  • 81
Yash
  • 689
  • 4
  • 11
  • 26

2 Answers2

2

From the docstring of my_cm.__call__:

*X* is either a scalar or an array (of any dimension).
If scalar, a tuple of rgba values is returned, otherwise
an array with the new shape = oldshape+(4,). If the X-values
are integers, then they are used as indices into the array.
If they are floating point, then they must be in the
interval (0.0, 1.0).
Alpha must be a scalar between 0 and 1, or None.
If bytes is False, the rgba values will be floats on a
0-1 scale; if True, they will be uint8, 0-255.

Note the difference between how floats and ints are treated.

Warren Weckesser
  • 110,654
  • 19
  • 194
  • 214
  • So if have an array like `[12.02, 1.122][0.23, 7.543]` can i divide the entire array with the largest place value applicable (in this case 100) and plot it? It should produce right results, right? – Yash Feb 14 '13 at 17:54
  • Well, I tried dividing by the largest place value. It don't think it gives the right result..... – Yash Feb 14 '13 at 18:30
  • what do you mean place value? – tacaswell Feb 14 '13 at 18:39
  • 1
    Maybe `s = (a - a.min()) / a.ptp(); a_mapped = my_cm(s)`; that linearly maps the data to the interval [0,1]. – Warren Weckesser Feb 14 '13 at 18:40
  • 1
    @Yash gah, sorry I messed up. Fixed my other answer. – tacaswell Feb 14 '13 at 18:47
  • @tcaswell: i mean decimal place value – Yash Feb 14 '13 at 19:06
  • @tcaswell: i meant decimal place value. I just wanted to normalize the values which was later suggested by WarrenWeckesser in a better way. I saw your fix in the previous answer too. I am now getting exactly what wanted. Thank you for taking out your time to answer my questions. – Yash Feb 14 '13 at 19:13
  • @WarrenWeckesser: Thank you for your input. It worked. Thank you for taking your time to answer my question. – Yash Feb 14 '13 at 19:14
0

The script below performs a color map on the input data and the map is converted to image as is, without using pylab.imshow or pylab.pcolor and without any scales or borders.

import pylab
import numpy as np

a = np.random.random( (512, 512) )*100
# a is a 2D array of random data not in the range of 0.0 to 1.0

# normalize the data
normed_a = ( a - a.min() )/( a.max() - a.min() )

# now create an instance of pylab.cm.get_cmap()
my_cm = pylab.cm.get_cmap('jet_r')

# create the map
mapped_a = my_cm( normed_a )

# to display the map, opencv is being used
# import opencv
import cv2 as cv

# convert mapped data to 8 bit unsigned int
mapped_au8 = (255 * mapped_a).astype('uint8')

# show the image
cv.imshow( 'a', mapped_au8 )
cv.waitKey( 0 )
cv.destroyAllWindows()

EDIT : Return type cm.get_cmap instance is of RGBA format but OpenCV by default operates on BGR format. Hence before displaying any image obtained by converting return values of cm.get_cmap() instance as in the above code, convert it to BGR format ( The ALPHA channel is anyway stripped by default in opencv before the image is displayed so dont bother to convert it into BGRA unless necessary ). The code below gives a better explanation:

mapped_au8 = (255 * mapped_a).astype('uint8')

#convert mapped_au8 into BGR fromat before display
mapped_u8 = cv.cvtColor( mapped_au8, cv.COLOR_RGBA2BGR )

# show the image
cv.imshow( 'a', mapped_au8 )
cv.waitKey( 0 )
cv.destroyAllWindows()

This answer was posted as an edit to the question pyplot.cm instance is producing different results for same values but different data type by the OP Yash under CC BY-SA 3.0.

vvvvv
  • 25,404
  • 19
  • 49
  • 81