Streaming an NWB file¶
This section demonstrates how to access the files on the DANDI Archive without downloading them. Based on the Streaming NWB files tutorial from PyNWB.
The dandi.dandiapi.DandiAPIClient can be used to get the S3 URL of the NWB file stored in the DANDI Archive.
from dandi.dandiapi import DandiAPIClient
client = DandiAPIClient.for_dandi_instance("dandi")
dandiset_id = "001084"
file_path = "sub-DL18/sub-DL18_ses-211110_image+ophys.nwb"
with DandiAPIClient() as client:
asset = client.get_dandiset(dandiset_id, 'draft').get_asset_by_path(file_path)
s3_url = asset.get_content_url(follow_redirects=1, strip_query=True)
We will use remfile for streaming the file. You can read more about remfile at this tutorial section.
import h5py
from pynwb import NWBHDF5IO
import remfile
# We stream the file using remfile and open it with h5py and pynwb
file = remfile.File(s3_url)
h5_file = h5py.File(file, "r")
io = NWBHDF5IO(file=h5_file, load_namespaces=True)
nwbfile = io.read()
nwbfile.subject
subject (Subject)
date_of_birth
2021-04-21 00:00:00-04:00Access raw imaging¶
This section demonstrates how to access the imaging data in the NWBFile.
NWB organizes data into different groups depending on the type of data. Groups can be thought of as folders within the file. Here are some of the groups within an NWBFile and the types of data they are intended to store:
acquisition: raw, acquired data that should never changeprocessing: processed data, typically the results of preprocessing algorithms and could change
Fiber array imaging¶
The fiber bundle imaging data was acquired using HCImage Live (Hamamatsu) at 30 Hz. It is stored in a pynwb.ophys.OnePhotonSeries object which is added to nwbfile.acquisition.
one_photon_series = nwbfile.acquisition["OnePhotonSeriesGreen"]
one_photon_series
OnePhotonSeriesGreen (OnePhotonSeries)
data
dimension
imaging_plane
optical_channel
0
device
The information about the imaging plane can accessed as nwbfile.acquisition["OnePhotonSeries"].imaging_plane or nwbfile.imaging_planes["ImagingPlane"].
nwbfile.imaging_planes["ImagingPlaneGreen"]
ImagingPlaneGreen (ImagingPlane)
optical_channel
0
device
# Visualize the imaging data.
from matplotlib import pyplot as plt
frame = one_photon_series.data[50]
plt.imshow(frame)
plt.title("Raw Fiber Array Imaging")
plt.show()
Fiber photometry traces¶
The raw fluorescence traces from the multi-fiber array are added to nwbfile.acquisition and are stored in a FiberPhotometryResponseSeries object using ndx-fiber-photometry. The fluorescence data during 470 nm excitation can be accessed as nwbfile.acquisition["FiberPhotometryResponseSeriesGreen"].
fiber_photometry_response_series = nwbfile.acquisition["FiberPhotometryResponseSeriesGreen"]
import pandas as pd
from matplotlib import pyplot as plt
# Prepare data for plotting
fiber_indices = [0, 4]
data = fiber_photometry_response_series.data[100:500, fiber_indices]
timestamps = fiber_photometry_response_series.get_timestamps()[100:500]
fig, axes = plt.subplots(nrows=data.shape[1], ncols=1, figsize=(8, 3), sharey=True, sharex=True, dpi=300)
for i, ax in enumerate(axes):
ax.plot(timestamps, data[:, i], linewidth=0.5, color="green")
ax.tick_params(axis='y', labelsize=8)
ax.tick_params(axis='x', labelsize=8)
ax.legend([f"Fiber {i+1}"], frameon=False, bbox_to_anchor=(.95, 1), loc='upper left', prop={'size': 8})
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
axes[0].spines['bottom'].set_visible(False)
axes[0].set_title("Raw fluorescence traces", fontsize=8)
plt.xlabel('Time (s)', fontsize=8)
plt.tick_params(axis='x', labelsize=8)
plt.tight_layout()
plt.show()
Fiber photometry metadata¶
The fiber photometry metadata includes the type of indicator(s), optical fiber(s), excitation source(s), photodector(s), dichroic mirror(s), and optical filter(s) that were used to construct a single fluorescence signal.
The metadata is stored in a FiberPhotometryTable object using ndx-fiber-photometry and is added to nwbfile.lab_meta_data. It can be accessed as nwbfile.lab_meta_data["FiberPhotometry"].fiber_photometry_table.
nwbfile.lab_meta_data["FiberPhotometry"].fiber_photometry_table[:]
| location | indicator | optical_fiber | excitation_source | photodetector | dichroic_mirror | allen_atlas_coordinates | included | coordinates | emission_filter | excitation_filter | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| id | |||||||||||
| 0 | Caudoputamen | dLight1.3b abc.Indicator at 0x5312211472\nFiel... | FiberArray abc.OpticalFiber at 0x5312205648\nF... | ExcitationSource470 abc.ExcitationSource at 0x... | CMOSCamera pynwb.device.Device at 0x5312316432... | DichroicMirror1 abc.DichroicMirror at 0x531227... | [442, 644, 229] | False | [0.83, 0.74, 1.78] | OpticalFilter525 abc.BandOpticalFilter at 0x53... | OpticalFilter470 abc.BandOpticalFilter at 0x53... |
| 1 | Caudoputamen | dLight1.3b abc.Indicator at 0x5312211472\nFiel... | FiberArray abc.OpticalFiber at 0x5312205648\nF... | ExcitationSource470 abc.ExcitationSource at 0x... | CMOSCamera pynwb.device.Device at 0x5312316432... | DichroicMirror1 abc.DichroicMirror at 0x531227... | [454, 642, 304] | False | [0.71, 0.72, 2.44] | OpticalFilter525 abc.BandOpticalFilter at 0x53... | OpticalFilter470 abc.BandOpticalFilter at 0x53... |
| 2 | Primary motor area Layer 6a | dLight1.3b abc.Indicator at 0x5312211472\nFiel... | FiberArray abc.OpticalFiber at 0x5312205648\nF... | ExcitationSource470 abc.ExcitationSource at 0x... | CMOSCamera pynwb.device.Device at 0x5312316432... | DichroicMirror1 abc.DichroicMirror at 0x531227... | [460, 674, 180] | False | [0.65, 1.04, 1.35] | OpticalFilter525 abc.BandOpticalFilter at 0x53... | OpticalFilter470 abc.BandOpticalFilter at 0x53... |
| 3 | Caudoputamen | dLight1.3b abc.Indicator at 0x5312211472\nFiel... | FiberArray abc.OpticalFiber at 0x5312205648\nF... | ExcitationSource470 abc.ExcitationSource at 0x... | CMOSCamera pynwb.device.Device at 0x5312316432... | DichroicMirror1 abc.DichroicMirror at 0x531227... | [495, 685, 260] | False | [0.3, 1.15, 2.05] | OpticalFilter525 abc.BandOpticalFilter at 0x53... | OpticalFilter470 abc.BandOpticalFilter at 0x53... |
| 4 | Primary motor area Layer 6a | dLight1.3b abc.Indicator at 0x5312211472\nFiel... | FiberArray abc.OpticalFiber at 0x5312205648\nF... | ExcitationSource470 abc.ExcitationSource at 0x... | CMOSCamera pynwb.device.Device at 0x5312316432... | DichroicMirror1 abc.DichroicMirror at 0x531227... | [400, 686, 160] | False | [1.25, 1.16, 1.17] | OpticalFilter525 abc.BandOpticalFilter at 0x53... | OpticalFilter470 abc.BandOpticalFilter at 0x53... |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 98 | Caudoputamen | dLight1.3b abc.Indicator at 0x5312211472\nFiel... | FiberArray abc.OpticalFiber at 0x5312205648\nF... | ExcitationSource470 abc.ExcitationSource at 0x... | CMOSCamera pynwb.device.Device at 0x5312316432... | DichroicMirror1 abc.DichroicMirror at 0x531227... | [433, 775, 249] | False | [0.92, 2.05, 1.96] | OpticalFilter525 abc.BandOpticalFilter at 0x53... | OpticalFilter470 abc.BandOpticalFilter at 0x53... |
| 99 | Caudoputamen | dLight1.3b abc.Indicator at 0x5312211472\nFiel... | FiberArray abc.OpticalFiber at 0x5312205648\nF... | ExcitationSource470 abc.ExcitationSource at 0x... | CMOSCamera pynwb.device.Device at 0x5312316432... | DichroicMirror1 abc.DichroicMirror at 0x531227... | [444, 815, 381] | True | [0.81, 2.45, 3.12] | OpticalFilter525 abc.BandOpticalFilter at 0x53... | OpticalFilter470 abc.BandOpticalFilter at 0x53... |
| 100 | Caudoputamen | dLight1.3b abc.Indicator at 0x5312211472\nFiel... | FiberArray abc.OpticalFiber at 0x5312205648\nF... | ExcitationSource470 abc.ExcitationSource at 0x... | CMOSCamera pynwb.device.Device at 0x5312316432... | DichroicMirror1 abc.DichroicMirror at 0x531227... | [457, 833, 280] | False | [0.68, 2.63, 2.23] | OpticalFilter525 abc.BandOpticalFilter at 0x53... | OpticalFilter470 abc.BandOpticalFilter at 0x53... |
| 101 | Primary somatosensory area mouth layer 6a | dLight1.3b abc.Indicator at 0x5312211472\nFiel... | FiberArray abc.OpticalFiber at 0x5312205648\nF... | ExcitationSource470 abc.ExcitationSource at 0x... | CMOSCamera pynwb.device.Device at 0x5312316432... | DichroicMirror1 abc.DichroicMirror at 0x531227... | [482, 821, 396] | False | [0.43, 2.51, 3.25] | OpticalFilter525 abc.BandOpticalFilter at 0x53... | OpticalFilter470 abc.BandOpticalFilter at 0x53... |
| 102 | Primary motor area Layer 2/3 | dLight1.3b abc.Indicator at 0x5312211472\nFiel... | FiberArray abc.OpticalFiber at 0x5312205648\nF... | ExcitationSource470 abc.ExcitationSource at 0x... | CMOSCamera pynwb.device.Device at 0x5312316432... | DichroicMirror1 abc.DichroicMirror at 0x531227... | [396, 791, 209] | False | [1.29, 2.21, 1.6] | OpticalFilter525 abc.BandOpticalFilter at 0x53... | OpticalFilter470 abc.BandOpticalFilter at 0x53... |
103 rows × 11 columns
The fiber_photometry_table_region attribute in the FiberPhotometryResponseSeries object references row(s) of this table:
fiber_photometry_table_region = nwbfile.acquisition["FiberPhotometryResponseSeriesGreen"].fiber_photometry_table_region[:]
fiber_photometry_table_region.head()
| location | indicator | optical_fiber | excitation_source | photodetector | dichroic_mirror | allen_atlas_coordinates | included | coordinates | emission_filter | excitation_filter | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| id | |||||||||||
| 0 | Caudoputamen | dLight1.3b abc.Indicator at 0x5312211472\nFiel... | FiberArray abc.OpticalFiber at 0x5312205648\nF... | ExcitationSource470 abc.ExcitationSource at 0x... | CMOSCamera pynwb.device.Device at 0x5312316432... | DichroicMirror1 abc.DichroicMirror at 0x531227... | [442, 644, 229] | False | [0.83, 0.74, 1.78] | OpticalFilter525 abc.BandOpticalFilter at 0x53... | OpticalFilter470 abc.BandOpticalFilter at 0x53... |
| 1 | Caudoputamen | dLight1.3b abc.Indicator at 0x5312211472\nFiel... | FiberArray abc.OpticalFiber at 0x5312205648\nF... | ExcitationSource470 abc.ExcitationSource at 0x... | CMOSCamera pynwb.device.Device at 0x5312316432... | DichroicMirror1 abc.DichroicMirror at 0x531227... | [454, 642, 304] | False | [0.71, 0.72, 2.44] | OpticalFilter525 abc.BandOpticalFilter at 0x53... | OpticalFilter470 abc.BandOpticalFilter at 0x53... |
| 2 | Primary motor area Layer 6a | dLight1.3b abc.Indicator at 0x5312211472\nFiel... | FiberArray abc.OpticalFiber at 0x5312205648\nF... | ExcitationSource470 abc.ExcitationSource at 0x... | CMOSCamera pynwb.device.Device at 0x5312316432... | DichroicMirror1 abc.DichroicMirror at 0x531227... | [460, 674, 180] | False | [0.65, 1.04, 1.35] | OpticalFilter525 abc.BandOpticalFilter at 0x53... | OpticalFilter470 abc.BandOpticalFilter at 0x53... |
| 3 | Caudoputamen | dLight1.3b abc.Indicator at 0x5312211472\nFiel... | FiberArray abc.OpticalFiber at 0x5312205648\nF... | ExcitationSource470 abc.ExcitationSource at 0x... | CMOSCamera pynwb.device.Device at 0x5312316432... | DichroicMirror1 abc.DichroicMirror at 0x531227... | [495, 685, 260] | False | [0.3, 1.15, 2.05] | OpticalFilter525 abc.BandOpticalFilter at 0x53... | OpticalFilter470 abc.BandOpticalFilter at 0x53... |
| 4 | Primary motor area Layer 6a | dLight1.3b abc.Indicator at 0x5312211472\nFiel... | FiberArray abc.OpticalFiber at 0x5312205648\nF... | ExcitationSource470 abc.ExcitationSource at 0x... | CMOSCamera pynwb.device.Device at 0x5312316432... | DichroicMirror1 abc.DichroicMirror at 0x531227... | [400, 686, 160] | False | [1.25, 1.16, 1.17] | OpticalFilter525 abc.BandOpticalFilter at 0x53... | OpticalFilter470 abc.BandOpticalFilter at 0x53... |
The metadata on the optical fiber used to record the GCaMP fluorescence is added to nwbfile.devices and can be accessed as nwbfile.devices["FiberArray"] or can be accessed from the referenced optical fiber in the fiber_photometry_table_region of the FiberPhotometryResponseSeries.
fiber_photometry_table_region["optical_fiber"][0]
FiberArray (OpticalFiber)
fiber_photometry_table_region["indicator"][0]
dLight1.3b (Indicator)
fiber_photometry_table_region["excitation_source"][0]
ExcitationSource470 (ExcitationSource)
fiber_photometry_table_region["photodetector"][0]
CMOSCamera (Device)
fiber_photometry_table_region["dichroic_mirror"][0]
DichroicMirror1 (DichroicMirror)
reflection_band_in_nm
transmission_band_in_nm
fiber_photometry_table_region["emission_filter"][0]
OpticalFilter525 (BandOpticalFilter)
fiber_photometry_table_region["excitation_filter"][0]
OpticalFilter470 (BandOpticalFilter)
Access processed fiber photometry data¶
This section demonstrates how to access the processed fiber photometry data in the NWBFile.
The processed fiber photometry data is stored in "processing/ophys" which can be accessed as nwbfile.processing["ophys"]. Within this processing module we can access the ∆F/F traces as nwbfile.processing["ophys"]["DfOverFFiberPhotometryResponseSeriesGreen"].
nwbfile.processing["ophys"]
df_over_f_traces = nwbfile.processing["ophys"]["DfOverFFiberPhotometryResponseSeriesGreen"]
# Visualize the DF/F traces.
from matplotlib import pyplot as plt
# Prepare data for plotting
data = df_over_f_traces.data[100:500, :5]
timestamps = df_over_f_traces.get_timestamps()[100:500]
fig, axes = plt.subplots(nrows=data.shape[1], ncols=1, figsize=(6, 4), sharey=True, sharex=True, dpi=300)
for i, ax in enumerate(axes):
ax.plot(timestamps, data[:, i], linewidth=0.5, color="green")
ax.tick_params(axis='y', labelsize=6)
ax.tick_params(axis='x', labelsize=6)
ax.legend([f"∆F/F Fiber {i+1}"], frameon=False, bbox_to_anchor=(.95, 1), loc='upper left', prop={'size': 6})
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
if i != data.shape[1] - 1:
ax.spines['bottom'].set_visible(False)
axes[0].set_title("DF/F Fluorescence traces", fontsize=6)
plt.xlabel('Time (s)', fontsize=6)
plt.tick_params(axis='x', labelsize=6)
plt.tight_layout()
plt.show()
Access motion corrected imaging data¶
This section demonstrates how to access the motion corrected imaging data in the NWBFile.
Similarly to the raw imaging data, the processed imaging data is stored in a pynwb.ophys.OnePhotonSeries object and is added to nwbfile.processing["ophys"].
motion_corrected = nwbfile.processing["ophys"]["OnePhotonSeriesMotionCorrectedGreen"]
motion_corrected
OnePhotonSeriesMotionCorrectedGreen (OnePhotonSeries)
data
dimension
imaging_plane
optical_channel
0
device
# Visualize the motion corrected imaging data.
from matplotlib import pyplot as plt
fig, axes = plt.subplots(nrows=1, ncols=2, sharex=True, sharey=True, dpi=300)
axes[0].imshow(one_photon_series.data[50])
axes[0].set_title("Raw Fiber Array Imaging", fontsize=6)
axes[0].tick_params(axis='x', labelsize=6)
axes[0].tick_params(axis='y', labelsize=6)
axes[1].imshow(motion_corrected.data[50])
axes[1].set_title("Motion Corrected Fiber Array Imaging", fontsize=6)
axes[1].tick_params(axis='x', labelsize=6)
axes[1].tick_params(axis='y', labelsize=6)
plt.tight_layout()
plt.show()
Access ROIs¶
This section demonstrates how to access the ROIs corresponding to fiber tops in the NWBFile.
The centroids and image masks of the ROIs are stored in a PlaneSegmentation added to an ImageSegmentation object in nwbfile.processing["ophys"].
rois_table = nwbfile.processing["ophys"]["ImageSegmentation"]["PlaneSegmentation"][:]
rois_table.head()
| image_mask | ROICentroids | Accepted | Rejected | |
|---|---|---|---|---|
| id | ||||
| 0 | [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,... | [166.47541258012367, 59.00562445763765] | 0 | 1 |
| 1 | [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,... | [163.1369152701555, 80.29428559091824] | 0 | 1 |
| 2 | [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,... | [144.14977970147507, 83.10331721340896] | 0 | 1 |
| 3 | [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,... | [123.4401911607665, 85.54001655461578] | 0 | 1 |
| 4 | [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,... | [111.00957492596739, 100.35934701854168] | 0 | 1 |
# Visualize the ROIs and the motion corrected imaging data.
from matplotlib import pyplot as plt
import numpy as np
plt.imshow(motion_corrected.data[50])
roi_masks = rois_table["image_mask"].values
roi_masks_combined = np.zeros(roi_masks[0].shape)
for i in range(roi_masks.shape[0]):
inds = np.where(roi_masks[i] != 0)
roi_masks_combined[inds] = 1
masked_roi_masks_combined = np.ma.masked_where(roi_masks_combined == 0, roi_masks_combined)
plt.imshow(masked_roi_masks_combined, cmap='gray', interpolation='none', alpha=0.5)
plt.title("ROIs on motion corrected image")
plt.show()
Access behavior data¶
This section demonstrates how to access the behavior data in the NWBFile.
The velocity for the roll and pitch (x, y) measured in m/s is added to nwbfile.processing["behavior"] stored in a pynwb.base.TimeSeries object. It can be accessed as nwbfile.processing["behavior"]["Velocity"].
The angular velocity from yaw (rotational) velocity is converted to radians/s and is also stored in a pynwb.base.TimeSeries object.
It can be accessed as nwbfile.processing["behavior"]["AngularVelocity"].
nwbfile.processing["behavior"]
velocity = nwbfile.processing["behavior"]["Velocity"]
# Visualize the DF/F traces and velocity for the roll in m/s.
import pandas as pd
from matplotlib import pyplot as plt
# Prepare data for plotting
data = df_over_f_traces.data[200:600, :2]
timestamps = df_over_f_traces.get_timestamps()[200:600]
velocity_x = velocity.data[200:600, 0]
fig, axes = plt.subplots(nrows=3, ncols=1, figsize=(6, 4), sharey=False, sharex=True, dpi=300)
for i in range(len(axes)-1):
axes[i].plot(timestamps, data[:, i], linewidth=0.5, color="green")
axes[i].spines['top'].set_visible(False)
axes[i].spines['right'].set_visible(False)
axes[i].tick_params(axis='y', labelsize=6)
axes[i].tick_params(axis='x', labelsize=6)
axes[i].spines['bottom'].set_visible(False)
axes[i].set_ylim([-0.01, 0.09])
axes[i].legend([f"∆F/F Fiber {i+1}"], frameon=False, bbox_to_anchor=(.95, 1), loc='upper left', prop={'size': 6})
axes[i].spines['top'].set_visible(False)
axes[i].spines['right'].set_visible(False)
axes[-1].plot(timestamps, velocity_x, color="black", alpha=0.8, linewidth=0.5)
axes[-1].spines['top'].set_visible(False)
axes[-1].spines['right'].set_visible(False)
axes[-1].legend(["Roll velocity"], frameon=False, bbox_to_anchor=(.95, 1), loc='upper left', prop={'size': 6})
axes[-1].tick_params(axis='y', labelsize=6)
axes[-1].tick_params(axis='x', labelsize=6)
plt.xlabel('Time (s)', fontsize=6)
plt.tight_layout()
plt.show()
The onset times of the events (licking, tone, light or reward delivery) are added to nwbfile.processing["behavior"]["TimeIntervals"] table.
events = nwbfile.processing["behavior"]["TimeIntervals"][:]
events
| start_time | stop_time | event_type | |
|---|---|---|---|
| id | |||
| 0 | 10.21300 | 11.08000 | Light |
| 1 | 25.31550 | 26.18225 | Light |
| 2 | 36.25050 | 37.58400 | Tone |
| 3 | 69.78875 | 70.65550 | Light |
| 4 | 87.65825 | 88.99175 | Tone |
| ... | ... | ... | ... |
| 158 | 1312.37725 | 1312.54400 | Lick |
| 159 | 1313.64425 | 1313.74425 | Lick |
| 160 | 1318.24500 | 1319.07825 | Light |
| 161 | 1325.11250 | 1326.41275 | Tone |
| 162 | 1330.61350 | 1331.48025 | Light |
163 rows × 3 columns
from matplotlib import pyplot as plt
import matplotlib.lines as mlines
# Prepare data for plotting
data = df_over_f_traces.data[700:1200, 0]
timestamps = df_over_f_traces.get_timestamps()[700:1200]
fig, ax = plt.subplots(nrows=1, ncols=1, figsize=(6, 2), dpi=300, sharex=True)
light_events = events[events["event_type"] == "Light"]
light_events = light_events[(light_events["start_time"] >= timestamps[0]) & (light_events["stop_time"] < timestamps[-1])]
tone_events = events[events["event_type"] == "Tone"]
tone_events = tone_events[(tone_events["start_time"] >= timestamps[0]) & (tone_events["stop_time"] < timestamps[-1])]
ax.plot(timestamps, data, color="green", linewidth=0.5)
for ind, row in light_events.iterrows():
ax.fill_between(timestamps, min(data), max(data), where=(timestamps >= row["start_time"]) & (timestamps <= row["stop_time"]), color='blue', edgecolor='none', alpha=0.1)
for ind, row in tone_events.iterrows():
ax.fill_between(timestamps, min(data), max(data), where=(timestamps >= row["start_time"]) & (timestamps <= row["stop_time"]), color='red', edgecolor='none', alpha=0.1)
# Create proxy lines for legend entries with corresponding colors and transparency
green_line = mlines.Line2D([], [], color='green', label='∆F/F from striatum', alpha=0.5)
blue_line = mlines.Line2D([], [], color='blue', label='Light', alpha=0.1)
red_line = mlines.Line2D([], [], color='red', label='Tone', alpha=0.1)
ax.legend(handles=[green_line, blue_line, red_line], frameon=False, bbox_to_anchor=(.95, 1), loc='upper left', prop={'size': 6})
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.tick_params(axis='y', labelsize=6)
ax.tick_params(axis='x', labelsize=6)
plt.xlabel('Time (s)', fontsize=6)
plt.show()