0

I am having some problems saving the image I am displaying as numpy ndarays.

Example:

This code:

librosa.display.specshow(static.T,sr=16000,x_axis='frames',y_axis='mel',hop_length=160,cmap=cm.jet)
plt.title("log mel power spectrum of " + name)
plt.colorbar(format='%+02.0f dB')
plt.tight_layout()
plt.savefig(plot+"/"+name+"_plot_static_conv.png")
plt.show()

Will show an image like this:

enter image description here

But when i store the image into a numpy ndarray, and then tries to plot it, I get something like this..

convert = plt.get_cmap(cm.jet)
numpy_output_static = convert(static.T)
plt.imshow(numpy_output_static)
plt.show()
raw_input("sadas")

Show me an image:

enter image description here

what is going on?.. why cant i store the same image, and view it the same way?

Minimal working example:

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


fig = plt.figure(figsize=(12,4))
min = -1.828067
max = 22.70058
data =  np.random.uniform(low=min, high=max, size=(474,40))
librosa.display.specshow(data.T,sr=16000,x_axis='frames',y_axis='mel',hop_length=160,cmap=cm.jet)
plt.show()
raw_input("sadas")

convert = plt.get_cmap(cm.jet)
numpy_output_static = convert(data.T)
plt.imshow(numpy_output_static, aspect = 'auto')
plt.show()
raw_input("asds")

First plot being :

enter image description here

Second plot being:

enter image description here

Normalizing the dataset doesn't fix the second image.

Fixining_ranges
  • 223
  • 1
  • 13
  • 2
    Please try to come up with a [minimal working example](https://stackoverflow.com/help/mcve). It most likely has something to do with the limits of the color-axis... You can add a colorbar to find out. See [this answer](http://stackoverflow.com/questions/43715813/how-to-show-numpy-nxm-array-with-dtype-float-as-plain-gray-scale-image/43716106#43716106) – Tom de Geus May 13 '17 at 09:51
  • 1
    Also dB is a logarithmic axis. We can only guess in which units `static` is????? – Tom de Geus May 13 '17 at 09:53
  • 1
    Can you please modify your post such that it can be reproduced. I.e. generate static, and modify the images accordingly? Also, have you looked into the color-scale? – Tom de Geus May 13 '17 at 10:08
  • 1
    I currently working out an example using the real data.. I tried random values, which it seem to work correctly on.. but on `static` dataset it seem to mess up.. – Fixining_ranges May 13 '17 at 10:26
  • 1
    @TomdeGeus I've added the exampe.. I tried with added limits.. same results – Fixining_ranges May 13 '17 at 10:40
  • 1
    Input data is filter energies of 40 filterbanks. – Fixining_ranges May 13 '17 at 10:41
  • Thanks. If I were you I'd remove the first half of your question. To be more precise. The horizontal and vertical axes you'll be able with matplotlib (use `extent` for `imshow` and then the usual commands). For the color-index you'll really have to clarify what unit `data` is in, and what conversion `librosa.display.specshow` does. From the documentation it seems that many units can be supplied, so I'm quite sure there is some conversion... – Tom de Geus May 13 '17 at 12:31
  • @TomdeGeus I tried this http://stackoverflow.com/questions/7821518/matplotlib-save-plot-to-numpy-array Which seemed make it possible to save the plot... but the shape of the `numpy.ndarray` don't matches with the original dataset. – Fixining_ranges May 13 '17 at 12:35
  • @TomdeGeus According to https://github.com/librosa/librosa/blob/master/librosa/display.py#L459 Is nothing being done to the data.. only the axis is being adjusted for.. – Fixining_ranges May 13 '17 at 12:38
  • @TomdeGeus Its just a colormesh.. https://github.com/librosa/librosa/blob/master/librosa/display.py#L678 – Fixining_ranges May 13 '17 at 12:40

1 Answers1

0

Your issues are related to how you use imshow (see below for explanation).

Solution

I have converted your input data from something random to something regular such that the comparison is more straightforward. I get a nicely matching result using the implementation below:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
import librosa
import librosa.display

data = np.linspace(-1.828067,22.70058,474*40).reshape(474,40)

fig = plt.figure(figsize=(12,8))

ax1 = fig.add_subplot(2,1,1)
librosa.display.specshow(data.T,sr=16000,x_axis='frames',y_axis='mel',hop_length=160,cmap=cm.jet)

ax2 = fig.add_subplot(2,1,2)
extent = (0,474,0,9325.7)
plt.imshow(data.T,cmap='jet',extent=extent)
ax2.set_aspect(abs((extent[1]-extent[0])/(extent[3]-extent[2]))/4.)

plt.show()

Result:

enter image description here

Explanation

Now, what went wrong? You used

convert = plt.get_cmap(cm.jet)

The result convert can best be thought of as a list with 256 RGBA color-entries:

>>> convert(0)
(0.0, 0.0, 0.5, 1.0)

>>> convert(1)
(0.0, 0.0, 0.517825311942959, 1.0)

>>> convert(2)
(0.0, 0.0, 0.535650623885918, 1.0)

...

>>> convert(254)
(0.517825311942959, 0.0, 0.0, 1.0)

>>> convert(255)
(0.5, 0.0, 0.0, 1.0)

Now the trick is that it's a 'special' list, which will just return the maximum when going out of bounds:

>>> convert(256)
(0.5, 0.0, 0.0, 1.0)

>>> convert(257)
(0.5, 0.0, 0.0, 1.0)

... 

>>> convert(1000)
(0.5, 0.0, 0.0, 1.0)

This is exactly what happened to you. Your diagram was therefore almost entirely red (the last color of "jet").

Instead, in the code I provided the data is mapped on to the 256 colors (the minimum gets assigned convert(0), the maximum convert(255), or more generally: (value-min_val)*255/(max_val-min_val).

References

Community
  • 1
  • 1
Tom de Geus
  • 5,625
  • 2
  • 33
  • 77
  • i am not sure what the answer here is... ? are you saying I should convert the random data into a range of 0 - 255 then cmaps it, and when I then plot the cmapped data it all should be ok? – Fixining_ranges May 13 '17 at 17:15
  • I am not sure if this fixes things?.. I don't seem to be able to replicate your results in my usecase. I still get the a red image, even if I normalize it.. besides that.. What you state could not be the case, as the max value is 22 and not above 255.. so.. – Fixining_ranges May 13 '17 at 18:41
  • I'm saying that you should have matplotlib do the color mapping, and you shouldn't try to do it manually. So put in the raw data together with the name of the colormap and optionally the limits in `imshow` and let it do its magic. This is the first part of my answer. The second part is just an explanation why your manual mapping was unsuccessful. But again let the library do its thing, that's where is there for. – Tom de Geus May 13 '17 at 20:41
  • Problem is that that the image stored as numpy ndarray is used as a input to a nn, which means representation is important... i need to store the plot as a numpy arrays with each pixel corresponding to pixels in the plot.. – Fixining_ranges May 14 '17 at 00:07
  • Now I'm really getting confused... Your input is a numpy array and the most accurate representation!? All we've been talking about is repenting visually using colors, for us humans to do something with it. – Tom de Geus May 14 '17 at 06:20
  • Using the colormap was a way of representing the data in a different way such that certain pattern would occur, and could be seen by a neural network. Numpy array I save doesn't resemble the plot i make, causing a problem when i use it as an input for a neural network (not part of this question but related to), as the desired patterns aren't shown in there.. – Fixining_ranges May 14 '17 at 06:36