0

What I have

I am trying to create a 'heatmap' of values using python 3.
I'm stuck on the spacing between the y-ticks, and several SO questions could not help me out...

The code that I have so far is the following:

data = np.load('path\to\data\datafile.npy')

# plot using imshow (and use interpolation)
plt.imshow(data,
           cmap          = 'RdBu_r', 
           aspect        = 'auto', 
           vmin          = -.4,
           vmax          =  .4,
           origin        = 'lower',
           extent        = [-1000, 4500, 2, 48], 
           interpolation = 'hanning')

# plt parameters
plt.xlim(-750, 4250)
plt.colorbar()
plt.vlines(0, 
           frequencies[0], 
           frequencies[-1], 
           colors = 'black',
           label = 'Stimulus onset',
           linewidth = 2.5)
plt.legend(loc=(1,1.04))
plt.title('Time-frequency using Morlet wavelets\nSubject: {}'.format(SUB_ID))
plt.ylabel('Frequency (in Hz)')
plt.xlabel('Time (in ms)')
plt.show()

This gives me the following plot:

Plot with wrong y-axis scaling

What I want

The labels on the y-axis are wrong.
Specifically, the y-axis should have the following labels (which are spaced in a logarithmic fashion):

In [15]:
# parameters
min_freq = 2;
max_freq = 48;
num_frex = 20;

# define frequencies of interest
frequencies = np.logspace(np.log10(min_freq), 
                          np.log10(max_freq), 
                          num_frex)
frequencies

Out[15]: 
array([ 2.        ,  2.36413729,  2.79457255,  3.30337659,  3.90481788,
        4.61576277,  5.45614844,  6.44954198,  7.62380134,  9.01185651,
       10.652633  , 12.59214343, 14.8847779 , 17.59482922, 20.7982959 ,
       24.58501342, 29.06117345, 34.35230187, 40.60677887, 48.        ])

The resulting plot should look like this (when focusing on the y-axis):

Plot with correct y-label spacing

So:

  • The plot should not be altered
  • The y-axis labels should be converted from linear to log
  • The spacing between the labels should be as in the latter plot

datafile.npy can be found here

1 Answers1

0

You just need to provide the plot with a custom ytick list:

# parameters
min_freq = 2;
max_freq = 48;
num_frex = 20;

# define frequencies of interest
frequencies = np.logspace(np.log10(min_freq), 
                      np.log10(max_freq), 
                      num_frex)

plt.yticks(frequencies)

see https://matplotlib.org/3.1.0/api/_as_gen/matplotlib.pyplot.yticks.html#matplotlib.pyplot.yticks for more

  • Thank you, but I have tried this before. By doing so, the plot will have y-ticks and labels that are linearly separated. I need the spacing between the labels to be log scaled, like in the second plot. –  Aug 28 '19 at 11:34
  • Ah I see, you want https://stackoverflow.com/questions/14530113/set-ticks-with-logarithmic-scale then probably – Joseph Holland Aug 28 '19 at 11:49
  • Well, the spacing is ok now, but the plot itself has changed. It looks like the data is stretched out... Is there a way to make the plot itself unalterable, while still changing the axes? Thanks for the help! –  Aug 28 '19 at 12:03
  • In that case, I do not understand the issue with my original solution as by setting `plt.yticks` with the `np.logspace` they are logarithmically spaced on a linear scale. You cannot have a logarithmic scale with linear data as the values would not line up... – Joseph Holland Aug 28 '19 at 12:18
  • In short: this is eeg data. The data was preprocessed, then rescaled using a logratio (i.e. I divided the data by the mean of baseline values (the last second of each data epoch) and then took the log). After that, I tried to plot the data using ```imshow```. Now, Python does not know that the data was already log transformed, and using the code from the previous comment alters the data again although this is not needed. Only the axis needs to be different –  Aug 28 '19 at 12:31
  • I see. This is possible, I will edit my original answer to suit. There is not really a neat solution bear in mind – Joseph Holland Aug 28 '19 at 12:35