joe kid
joe kid

Reputation: 23

subplots, how to set the xlabel and xlim, but removing axis

I'd like to plot EEG data and get this result:

reference figure

But I am stuck on how to display the x axis label and its xlim.

After reading other questions, which use set_visible(False), I cannot resolve my issue.

I write my code in order to be reproducible:

sfreq = 256
raw_data = np.random.rand(14, 1000 * sfreq)

duration = 10 # duration of the signal
start = 200 * sfreq
final = start + int(sfreq * duration)  

channels = list(np.arange(1, len(channels) + 1 ))

fig, ax = plt.subplots(len(channels), 1, sharex=True, figsize=(10, 10))
for idx, node in enumerate(channels):
    data = raw_data[idx, start:final]
    times = np.arange(1, data.size + 1) / sfreq
    ax[idx].plot(times, data, lw=1., ls='-', c='k')
    
    ax[idx].axis('off') # to remove bounding subplot    
    ax[idx].set_yticks([]) # to remove values from y axis   
    ax[idx].text(-1, 0, node, fontsize=12) # write text
    

# plt.axis(True)
# plt.axes().get_xaxis().set_visible(True)
# plt.xlim([200, 220])
plt.xlabel('Time (seconds)', fontsize=12)
plt.tight_layout()
plt.show()

This is my result:

current result

But I'd like this:

desired result

Upvotes: 1

Views: 325

Answers (1)

JohanC
JohanC

Reputation: 80289

Here are some possible changes to the plot:

  • make the code more python by using zip instead of an index in the for loop
  • change the visibility of the "spines" (the lines surrounding the subplot) instead of use axis('off')
  • remove the padding (margins)
  • use the axes transform to position the text of the y-axis
  • ...
import matplotlib.pyplot as plt
import numpy as np

sfreq = 256
raw_data = np.random.rand(14, 1000 * sfreq)

duration = 10  # duration of the signal
start = 200 * sfreq
final = start + int(sfreq * duration)

channels = np.arange(len(raw_data)) + 1

fig, axs = plt.subplots(len(channels), 1, sharex=True, figsize=(10, 10))
for ax, node, data in zip(axs, channels, raw_data):
    data = data[start:final]
    times = np.arange(1, data.size + 1) / sfreq
    ax.plot(times, data, lw=1., ls='-', c='k')

    ax.set_yticks([])  # remove y ticks
    for sp in ax.spines:
        ax.spines[sp].set_visible(False)  # hide the 4 lines surrounding the subplot
    ax.text(-0.01, 0.5, node, fontsize=12, ha='right', va='center', transform=ax.transAxes)  # write text
    ax.margins(x=0) # avoid the empty space left and right
    if ax != axs[-1]:
        # ax.tick_params(axis='x', length=0)  # hide the tick marks
        ax.tick_params(bottom=False)  # no tick marks at the bottom

axs[-1].set_xlabel('Time (seconds)', fontsize=12, labelpad=-10) # use negative padding to get closer to the xaxis
axs[-1].set_xticks([0, duration])
axs[-1].set_xticklabels([start // sfreq, final // sfreq])
axs[-1].spines['bottom'].set_bounds([0, duration])  # only draw the spine between the two ticks
axs[-1].spines['bottom'].set_visible(True)
axs[-1].spines['bottom'].set_linewidth(2)
plt.tight_layout()
plt.show()

modified subplots

Upvotes: 1

Related Questions