A python package for gravitational-wave astrophysics
—
Enhanced matplotlib integration with gravitational-wave specific plot types, GPS time handling, and publication-quality figure generation. GWpy's plotting system extends matplotlib with domain-specific visualizations and automatic formatting for gravitational-wave data.
Enhanced matplotlib Figure with gravitational-wave data integration and automatic formatting.
from gwpy.plot import Plot
class Plot:
def __init__(self, *args, figsize=None, **kwargs):
"""
Create an enhanced plot figure.
Parameters:
- *args: data objects to plot initially
- figsize: tuple, figure size (width, height) in inches
- **kwargs: additional matplotlib Figure arguments
"""
def add_timeseries(self, timeseries, **kwargs):
"""
Add a TimeSeries to the plot.
Parameters:
- timeseries: TimeSeries, data to plot
- label: str, legend label
- color: color specification
- alpha: float, transparency (0-1)
Returns:
Line2D object
"""
def add_frequencyseries(self, frequencyseries, **kwargs):
"""
Add a FrequencySeries to the plot.
Parameters:
- frequencyseries: FrequencySeries, data to plot
- label: str, legend label
- color: color specification
Returns:
Line2D object
"""
def add_spectrogram(self, spectrogram, **kwargs):
"""
Add a Spectrogram to the plot.
Parameters:
- spectrogram: Spectrogram, data to plot
- norm: str, normalization ('linear', 'log')
- vmin: float, minimum value for colormap
- vmax: float, maximum value for colormap
- cmap: str, colormap name
Returns:
Image object
"""
def show(self, **kwargs):
"""
Display the plot.
Parameters:
- **kwargs: arguments passed to matplotlib show()
"""
def save(self, filename, **kwargs):
"""
Save the plot to file.
Parameters:
- filename: str, output file path
- dpi: int, resolution in dots per inch
- bbox_inches: str, bounding box ('tight' recommended)
- **kwargs: additional matplotlib savefig arguments
"""
def close(self):
"""Close the plot figure."""
@property
def gca(self):
"""Get current axes."""
def add_subplot(self, *args, **kwargs):
"""
Add a subplot.
Returns:
Axes object
"""
def colorbar(self, mappable=None, **kwargs):
"""
Add a colorbar.
Parameters:
- mappable: mappable object (e.g., Image from spectrogram)
- label: str, colorbar label
Returns:
Colorbar object
"""Enhanced matplotlib Axes with automatic GPS time formatting and gravitational-wave specific features.
from gwpy.plot import Axes
class Axes:
def plot(self, *args, **kwargs):
"""
Plot data with automatic GPS time formatting.
Returns:
Line2D objects
"""
def loglog(self, *args, **kwargs):
"""
Log-log plot with enhanced formatting.
Returns:
Line2D objects
"""
def semilogx(self, *args, **kwargs):
"""
Semi-log plot (x-axis log scale).
Returns:
Line2D objects
"""
def semilogy(self, *args, **kwargs):
"""
Semi-log plot (y-axis log scale).
Returns:
Line2D objects
"""
def scatter(self, *args, **kwargs):
"""
Scatter plot with enhanced formatting.
Returns:
PathCollection object
"""
def hist(self, *args, **kwargs):
"""
Histogram with enhanced formatting.
Returns:
Histogram objects
"""
def imshow(self, *args, **kwargs):
"""
Display 2D data as image.
Returns:
Image object
"""
def set_xlim(self, left=None, right=None, **kwargs):
"""
Set x-axis limits with GPS time support.
Parameters:
- left: float, left limit (GPS time or relative)
- right: float, right limit
"""
def set_ylim(self, bottom=None, top=None, **kwargs):
"""
Set y-axis limits.
Parameters:
- bottom: float, bottom limit
- top: float, top limit
"""
def set_xlabel(self, label, **kwargs):
"""
Set x-axis label with automatic GPS time detection.
Parameters:
- label: str, axis label
"""
def set_ylabel(self, label, **kwargs):
"""
Set y-axis label.
Parameters:
- label: str, axis label
"""
def set_title(self, title, **kwargs):
"""
Set plot title.
Parameters:
- title: str, plot title
"""
def legend(self, **kwargs):
"""
Add legend with enhanced formatting.
Parameters:
- loc: str, legend location
- frameon: bool, draw frame around legend
Returns:
Legend object
"""
def grid(self, visible=True, **kwargs):
"""
Configure plot grid.
Parameters:
- visible: bool, show grid
- alpha: float, grid transparency
"""
def set_epoch(self, epoch):
"""
Set GPS epoch for time axis formatting.
Parameters:
- epoch: float, GPS time epoch
"""Specialized plot class for Bode magnitude and phase diagrams.
from gwpy.plot import BodePlot
class BodePlot(Plot):
def __init__(self, **kwargs):
"""
Create a Bode plot with magnitude and phase subplots.
"""
def add_transfer_function(self, tf, **kwargs):
"""
Add transfer function to Bode plot.
Parameters:
- tf: FrequencySeries, complex transfer function
- label: str, legend label
Returns:
tuple, (magnitude_line, phase_line)
"""
@property
def maxes(self):
"""Get magnitude axes."""
@property
def paxes(self):
"""Get phase axes."""Specialized axes for visualizing data quality segments and flags.
from gwpy.plot import SegmentAxes
class SegmentAxes(Axes):
def plot_segmentlist(self, segmentlist, **kwargs):
"""
Plot a SegmentList.
Parameters:
- segmentlist: SegmentList, segments to plot
- y: float, y-position for segments
- height: float, segment height
- color: color specification
Returns:
Collection of segment patches
"""
def plot_dqflag(self, flag, **kwargs):
"""
Plot a DataQualityFlag.
Parameters:
- flag: DataQualityFlag, flag to plot
- label: str, legend label
Returns:
Collection objects for active and valid segments
"""from gwpy.timeseries import TimeSeries
from gwpy.plot import Plot
# Read gravitational-wave data
strain = TimeSeries.fetch_open_data('H1', 1126259446, 1126259478)
# Create basic plot
plot = strain.plot()
plot.set_title('LIGO Hanford Strain Data')
plot.set_ylabel('Strain')
plot.show()
# Multiple time series comparison
l1_strain = TimeSeries.fetch_open_data('L1', 1126259446, 1126259478)
plot = Plot(figsize=(12, 6))
plot.add_timeseries(strain, label='Hanford (H1)', alpha=0.8)
plot.add_timeseries(l1_strain, label='Livingston (L1)', alpha=0.8)
plot.set_xlabel('Time')
plot.set_ylabel('Strain')
plot.legend()
plot.save('strain_comparison.png', dpi=300, bbox_inches='tight')# Calculate and plot PSDs
h1_psd = strain.psd(fftlength=4, overlap=2)
l1_psd = l1_strain.psd(fftlength=4, overlap=2)
# Log-log PSD plot
plot = Plot(figsize=(10, 6))
plot.gca.loglog(h1_psd.frequencies, h1_psd, label='H1', alpha=0.8)
plot.gca.loglog(l1_psd.frequencies, l1_psd, label='L1', alpha=0.8)
plot.set_xlabel('Frequency [Hz]')
plot.set_ylabel('Power Spectral Density [strain²/Hz]')
plot.set_xlim(10, 2000)
plot.legend()
plot.grid(True, alpha=0.3)
plot.show()
# ASD comparison with design sensitivity
asd = h1_psd.sqrt()
plot = asd.plot(label='H1 Measured')
# Add design curve (example)
design_freqs = asd.frequencies
design_asd = design_sensitivity_curve(design_freqs) # User function
plot.gca.loglog(design_freqs, design_asd,
label='Design Sensitivity', linestyle='--')
plot.set_xlabel('Frequency [Hz]')
plot.set_ylabel('Amplitude Spectral Density [strain/√Hz]')
plot.set_ylim(1e-24, 1e-18)
plot.legend()
plot.show()# Create and plot spectrogram
spec = strain.spectrogram(stride=1, fftlength=4, overlap=2)
plot = spec.plot(figsize=(12, 8))
plot.set_xlabel('Time')
plot.set_ylabel('Frequency [Hz]')
plot.set_title('H1 Strain Spectrogram')
plot.set_ylim(20, 2000)
plot.colorbar(label='Amplitude Spectral Density [strain/√Hz]')
plot.show()
# Custom spectrogram with ratio normalization
spec_ratio = spec.ratio('median')
plot = spec_ratio.plot(vmin=0.1, vmax=10, norm='log',
cmap='viridis')
plot.set_title('Normalized Spectrogram')
plot.colorbar(label='Ratio to median')
plot.show()# Create multi-panel figure
fig = Plot(figsize=(12, 10))
# Time series panel
ax1 = fig.add_subplot(3, 1, 1)
ax1.plot(strain.times, strain.value)
ax1.set_ylabel('Strain')
ax1.set_title('H1 Strain Time Series')
# PSD panel
ax2 = fig.add_subplot(3, 1, 2)
ax2.loglog(h1_psd.frequencies, h1_psd)
ax2.set_ylabel('PSD [strain²/Hz]')
ax2.set_xlim(10, 2000)
ax2.grid(True, alpha=0.3)
# Spectrogram panel
ax3 = fig.add_subplot(3, 1, 3)
im = ax3.imshow(spec.T, aspect='auto', origin='lower',
extent=[spec.xspan[0], spec.xspan[1],
spec.yspan[0], spec.yspan[1]],
norm='log')
ax3.set_xlabel('Time [s]')
ax3.set_ylabel('Frequency [Hz]')
ax3.set_ylim(20, 500)
# Add colorbar
fig.colorbar(im, ax=ax3, label='ASD [strain/√Hz]')
plt.tight_layout()
fig.show()from gwpy.plot import BodePlot
from gwpy.frequencyseries import FrequencySeries
# Read or calculate transfer function
cal_response = FrequencySeries.read('calibration_response.txt')
# Create Bode plot
bode = BodePlot()
bode.add_transfer_function(cal_response, label='Calibration Response')
# Customize magnitude plot
bode.maxes.set_ylabel('Magnitude')
bode.maxes.legend()
bode.maxes.grid(True, alpha=0.3)
# Customize phase plot
bode.paxes.set_ylabel('Phase [degrees]')
bode.paxes.set_xlabel('Frequency [Hz]')
bode.paxes.grid(True, alpha=0.3)
bode.show()from gwpy.segments import DataQualityDict
from gwpy.plot import Plot
# Query multiple flags
flags = DataQualityDict.query(['H1:DMT-ANALYSIS_READY:1',
'H1:DMT-CALIBRATED:1',
'H1:LSC-DARM_LOCKED:1'],
start=1126259446, end=1126259478)
# Plot flags
plot = flags.plot(figsize=(12, 6), sep=True)
plot.set_title('H1 Data Quality Flags')
plot.show()
# Custom segment visualization
plot = Plot(figsize=(12, 4))
ax = plot.gca
y_pos = 0
colors = ['green', 'blue', 'red']
for i, (name, flag) in enumerate(flags.items()):
# Plot active segments
for segment in flag.active:
ax.barh(y_pos, segment.duration, left=segment.start,
height=0.8, color=colors[i], alpha=0.7,
label=name if segment == flag.active[0] else "")
y_pos += 1
ax.set_xlabel('GPS Time')
ax.set_ylabel('Flags')
ax.set_yticks(range(len(flags)))
ax.set_yticklabels([name.split(':')[-1] for name in flags.keys()])
ax.legend()
plot.show()import matplotlib
matplotlib.rcParams.update({
'font.size': 12,
'font.family': 'serif',
'axes.labelsize': 14,
'axes.titlesize': 16,
'xtick.labelsize': 12,
'ytick.labelsize': 12,
'legend.fontsize': 12,
'figure.titlesize': 18
})
# Create publication plot
strain_zoom = strain.crop(1126259462, 1126259463)
plot = strain_zoom.plot(figsize=(10, 6), color='darkblue', linewidth=1)
plot.set_xlabel('Time from 1126259462 [s]')
plot.set_ylabel('Strain')
plot.set_title('LIGO Hanford Strain: GW150914 Detection')
plot.grid(True, alpha=0.3)
# Add annotation
plot.gca.annotate('Gravitational Wave Signal',
xy=(1126259462.4, strain_zoom.max().value),
xytext=(1126259462.6, strain_zoom.max().value * 0.8),
arrowprops=dict(arrowstyle='->', color='red'),
fontsize=12, color='red')
# Save high-quality figure
plot.save('gw150914_strain.pdf', dpi=300, bbox_inches='tight')
plot.save('gw150914_strain.png', dpi=300, bbox_inches='tight')# Interactive plot with zoom and pan
plot = strain.plot(figsize=(12, 6))
plot.set_title('Interactive H1 Strain Plot')
# Enable interactive features
plot.gca.set_navigate(True) # Enable zoom/pan
plot.show()
# Plot with custom GPS time epoch
plot = strain.plot()
plot.gca.set_epoch(1126259462) # Set epoch to GW150914 time
plot.set_xlabel('Time from GW150914 [s]')
plot.show()Install with Tessl CLI
npx tessl i tessl/pypi-gwpy