3

How to plot, with Python, a 2D matrix A[i,j] like this:

  • i is the x-axis
  • j is the y-axis
  • A[i,j] is a value between 0 and 100 that has to be drawn by a colour (ex: 0=blue, 100=red)

Is there a Python function for that?

(NB: I don't want a function that does the spectrogram for me, such as specgram, because I want to compute the FFT of the signal myself; thus I only need a function that plots a matrix with colors)

Spectrogram sample

Basj
  • 41,386
  • 99
  • 383
  • 673
  • 1
    The `imshow` function is dedicated to this task. You'll find several examples in the matplotlib gallery. – David Zwicker Nov 19 '13 at 10:56
  • 1
    Thanks for `imshow` but `pcolormesh` is more what I was looking for : http://www.courspython.com/v3/visualisation_couleur.html – Basj Nov 19 '13 at 11:01
  • 2
    You shouldnt use `pcolormesh` if you have a regular grid, why dont you use `imshow`? – Rutger Kassies Nov 19 '13 at 11:10
  • well I have to admit I don't know the difference between `pcolor`, `pcolormesh`, and `imshow`, but it worked with `pcolormesh`... What is the difference between `pcolor` and `pcolormesh` by the way ? – Basj Nov 19 '13 at 11:15
  • 1
    `pcolor` and `pcolormesh` are very similar, but with performance differences. They are meant for irregular grids. You provide the corner coordinates and mpl draws a polygon between them. If you have a regular grid, with a constant resolution along the axis `imshow` is a much better choice, more robust and much faster. – Rutger Kassies Nov 19 '13 at 11:39
  • thanks @Rutger Kassies and @David Zwicker, you're right, it's better with `imshow`. Just one question : if my array is 100 x 200, the axis limits of this imshow will be [0,100] and [0,200]. How to set that the limits for x and y are [0,1.5] and [0,3.78] for example ? I found some things here : http://stackoverflow.com/questions/13704373/how-to-limit-the-range-of-the-x-axis-with-imshow but I can't believe there's 15 lines of code for redoing the ticks, the axis, etc. ;) – Basj Nov 19 '13 at 11:51
  • 1
    Read the documentation! The `extent` keyword is what you're probably looking for. – David Zwicker Nov 19 '13 at 12:02
  • 1
    @RutgerKassies - `pcolormesh` is explicitly for regular meshes. It's `pcolor` that's very inefficient for a regular mesh. The OP likely really does want `pcolormesh`, particularly if they want vector output. `imshow` is generally faster for large arrays, but in a lot of cases where'd you specify no interpolation `pcolormesh` is a better choice. – Joe Kington Nov 19 '13 at 16:35
  • @Basj Now that you have solved your problem can you write an answer to your own question demonstrating how you solved it? – tacaswell Nov 19 '13 at 16:41
  • @Joe Kington, maybe im using the word irregular wrong but i would also call this irregular: http://stackoverflow.com/questions/17441914/matplotlib-matshow-how-to-change-each-row-height-based-on-a-scaling-vector/17443778 Excellent point though about wanting vector output, thats certainly true. – Rutger Kassies Nov 19 '13 at 19:10
  • @RutgerKassies - It's still rectilinear. That's the whole point of `pcolormesh`. It's a faster version of `pcolor` for rectilinear grids. `pcolor` handles arbitrary shapes, as well. I probably should have said "rectilinear" instead of "regular", though. – Joe Kington Nov 19 '13 at 19:11
  • @RutgerKassies - Actually, nevermind, I thought `pcolor` handled non-rectilinear meshes, while `pcolormesh` didn't. Actually they both do. Now I'm a bit confused as to what `pcolor` can do that `pcolormesh` can't... – Joe Kington Nov 19 '13 at 19:19
  • 1
    @Joe Kington, i dont know about that. But one other difference relevant to this thread is that with the 'imshow' approach you specify (implicit usually) center coordinates as apposed to corner coordinates for 'pcolor'. So x and y should contain one value more then z, or else the last row/col is truncated. – Rutger Kassies Nov 19 '13 at 19:37

1 Answers1

9

Let Z be the array, here is what I finally use:

plt.imshow(np.transpose(Z), extent=[0,4.2,0,48000], cmap='jet',
           vmin=-100, vmax=0, origin='lowest', aspect='auto')
plt.colorbar()
plt.show()

Notes:

  • 'jet' is the colormap that is seen in the question's image, see also these colormaps

  • setting origin='lowest' has the same effect than replacing np.transpose(Z) by np.transpose(Z)[::-1,]

  • vmin, vmax give the scale (here from 0 to -100 dB in the example)

  • extent gives the limits of the x-axis (here 0 to 4.2 seconds) and y-axis (0 to 48000 Hz) (in this example I'm plotting the spectrogram of a 4.2 second-long audio file of samplerate 96Khz)

  • if aspect='auto' is not set, the plot would be very thin and very high (due to 4.2 vs. 48000 !)

Basj
  • 41,386
  • 99
  • 383
  • 673
  • 1
    Just FYI: There's nothing wrong with using `pcolormesh` in this case. It's slighly less efficient than `imshow`, but for a moderately sized array, you won't have problems. The difference is that `pcolor` and `pcolormesh` produce _vector_ output. (i.e. each pixel is a polygon) If you save to pdf or svg and edit the output, you'll see the difference. `pcolor` is for irregular grids, and `pcolormesh` is an efficient version of `pcolor` for regular grids. The advantage over `imshow` is you don't have to override the aspect ratio and it's easier to specify the x and y coordinates in some cases. – Joe Kington Nov 19 '13 at 16:54
  • 2
    Also there's nothing wrong with using `imshow` for this either. The big difference is raster vs. vector output. If you're saving to a raster format, you won't notice a difference. – Joe Kington Nov 19 '13 at 16:56