Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog/144.bugfix.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fixed an issue where plotting spectrograms with non-UTC time scales (e.g., 'tt') would result in time offsets by ensuring conversion to UTC before plotting.
2 changes: 2 additions & 0 deletions pytest.ini
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,5 @@ filterwarnings =
ignore:The --rsyncdir command line argument and rsyncdirs config variable are deprecated.:DeprecationWarning
ignore:File may have been truncated.*
ignore:pattern has been replaced with the format keyword
# pyparsing deprecation warning from old matplotlib in oldestdeps
ignore:.*deprecated:pyparsing.warnings.PyparsingDeprecationWarning
36 changes: 20 additions & 16 deletions radiospectra/mixins.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,10 @@ def plot(self, axes=None, **kwargs):
-------
`matplotlib.collections.QuadMesh`
"""
import matplotlib.dates as mdates
from matplotlib import pyplot as plt

from astropy.visualization import time_support

if axes is None:
fig, axes = plt.subplots()
else:
Expand All @@ -36,17 +37,15 @@ def plot(self, axes=None, **kwargs):
title = f"{title}, {self.detector}"

axes.set_title(title)
axes.plot(self.times.datetime[[0, -1]], self.frequencies[[0, -1]], linestyle="None", marker="None")
if self.times.shape[0] == self.data.shape[0] and self.frequencies.shape[0] == self.data.shape[1]:
ret = axes.pcolormesh(self.times.datetime, self.frequencies.value, data, shading="auto", **kwargs)
else:
ret = axes.pcolormesh(self.times.datetime, self.frequencies.value, data[:-1, :-1], shading="auto", **kwargs)
axes.set_xlim(self.times.datetime[0], self.times.datetime[-1])
locator = mdates.AutoDateLocator(minticks=4, maxticks=8)
formatter = mdates.ConciseDateFormatter(locator)
axes.xaxis.set_major_locator(locator)
axes.xaxis.set_major_formatter(formatter)
fig.autofmt_xdate()
with time_support():
axes.plot(self.times[[0, -1]], self.frequencies[[0, -1]], linestyle="None", marker="None")
if self.times.shape[0] == self.data.shape[0] and self.frequencies.shape[0] == self.data.shape[1]:
ret = axes.pcolormesh(self.times, self.frequencies.value, data, shading="auto", **kwargs)
else:
ret = axes.pcolormesh(self.times, self.frequencies.value, data[:-1, :-1], shading="auto", **kwargs)
axes.set_xlim(self.times[0], self.times[-1])
fig.autofmt_xdate()

# Set current axes/image if pyplot is being used (makes colorbar work)
for i in plt.get_fignums():
if axes in plt.figure(i).axes:
Expand All @@ -61,13 +60,18 @@ class NonUniformImagePlotMixin:
"""

def plotim(self, fig=None, axes=None, **kwargs):
import matplotlib.dates as mdates
from matplotlib import pyplot as plt
from matplotlib.image import NonUniformImage

from astropy.visualization import time_support

if axes is None:
fig, axes = plt.subplots()

im = NonUniformImage(axes, interpolation="none", **kwargs)
im.set_data(mdates.date2num(self.times.datetime), self.frequencies.value, self.data)
axes.images.append(im)
with time_support():
axes.plot(self.times[[0, -1]], self.frequencies[[0, -1]], linestyle="None", marker="None")
im = NonUniformImage(axes, interpolation="none", **kwargs)
im.set_data(axes.convert_xunits(self.times), self.frequencies.value, self.data)
axes.add_image(im)
axes.set_xlim(self.times[0], self.times[-1])
axes.set_ylim(self.frequencies.value[0], self.frequencies.value[-1])
3 changes: 3 additions & 0 deletions radiospectra/spectrogram/tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import matplotlib

matplotlib.use("Agg")
57 changes: 57 additions & 0 deletions radiospectra/spectrogram/tests/test_spectrogrambase.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
from unittest import mock

import matplotlib.pyplot as plt
import numpy as np

import astropy.units as u
from astropy.time import Time

from radiospectra.spectrogram.spectrogrambase import GenericSpectrogram


def _get_spectrogram_with_time_scale(scale):
times = Time("2020-01-01T00:00:00", format="isot", scale=scale) + np.arange(4) * u.min
frequencies = np.linspace(10, 40, 4) * u.MHz
meta = {
"observatory": "Test",
"instrument": "TestInst",
"detector": "TestDet",
"start_time": times[0],
"end_time": times[-1],
"wavelength": np.array([1, 10]) * u.m,
"times": times,
"freqs": frequencies,
}
return GenericSpectrogram(np.arange(16).reshape(4, 4), meta)


def test_plot_uses_time_support_for_datetime_conversion():
spec = _get_spectrogram_with_time_scale("tt")

mesh = spec.plot()
x_limits = np.array(mesh.axes.get_xlim())
expected_tt_limits = mesh.axes.convert_xunits(spec.times[[0, -1]])

plt.close(mesh.axes.figure)

np.testing.assert_allclose(x_limits, expected_tt_limits)


def test_plotim_uses_time_support_for_datetime_conversion():
spec = _get_spectrogram_with_time_scale("tt")
fig, axes = plt.subplots()

with (
mock.patch("matplotlib.image.NonUniformImage.set_interpolation", autospec=True),
mock.patch("matplotlib.image.NonUniformImage.set_data", autospec=True) as set_data,
):
spec.plotim(fig=fig, axes=axes)

plt.close(fig)

_, x_values, y_values, image = set_data.call_args.args
expected_tt = axes.convert_xunits(spec.times)

np.testing.assert_allclose(x_values, expected_tt)
np.testing.assert_allclose(y_values, spec.frequencies.value)
np.testing.assert_allclose(image, spec.data)