Skip to content

Commit

Permalink
Merge pull request #398 from LinkedEarth/stripe_fix
Browse files Browse the repository at this point in the history
Stripe fix
  • Loading branch information
CommonClimate authored Apr 26, 2023
2 parents 24151c3 + 40a201d commit 5315080
Show file tree
Hide file tree
Showing 6 changed files with 143 additions and 151 deletions.
80 changes: 44 additions & 36 deletions pyleoclim/core/multipleseries.py
Original file line number Diff line number Diff line change
Expand Up @@ -2024,8 +2024,9 @@ def stackplot(self, figsize=None, savefig_settings=None, time_unit = None, xlim=
else:
return ax

def stripes(self, ref_period=None, figsize=None, savefig_settings=None, time_unit=None,
LIM = 2.8, thickness=1.0, labels='auto', label_color = 'gray',
def stripes(self, cmap = 'RdBu_r', sat=1.0, ref_period=None,
figsize=None, savefig_settings=None, time_unit=None,
labels='auto', label_color = 'gray', show_xaxis=False,
common_time_kwargs=None, xlim=None, font_scale=0.8, x_offset = 0.05):
'''
Represents a MultipleSeries object as a quilt of Ed Hawkins' "stripes" patterns
Expand All @@ -2039,21 +2040,24 @@ def stripes(self, ref_period=None, figsize=None, savefig_settings=None, time_un
Parameters
----------
cmap: str
colormap name (https://matplotlib.org/stable/tutorials/colors/colormaps.html)
Default is 'RdBu_r'
ref_period : TYPE, optional
dates of the reference period, in the form "(first, last)".
The default is None, which will pick the beginning and end of the common time axis.
LIM : float
scaling factor for color saturation. default is 2.8.
The higher the LIM, the more compressed the color range (milder hues)
thickness : float, optional
vertical thickness of the stripe . The default is 1.0
figsize : list
a list of two integers indicating the figure size (in inches)
Size of the figure.
sat : float > 0
Controls the saturation of the colormap normalization by scaling the vmin, vmax in https://matplotlib.org/stable/tutorials/colors/colormapnorms.html
default = 1.0
show_xaxis : bool
flag indicating whether or not the x-axis should be shown (default = False)
savefig_settings : dictionary
Expand Down Expand Up @@ -2126,12 +2130,11 @@ def stripes(self, ref_period=None, figsize=None, savefig_settings=None, time_un
:okexcept:
import pyleoclim as pyleo
url = 'http://wiki.linked.earth/wiki/index.php/Special:WTLiPD?op=export&lipdid=MD982176.Stott.2004'
d = pyleo.Lipd(usr_path = url)
tslist = d.to_LipdSeriesList()
tslist = tslist[2:] # drop the first two series which only concerns age and depth
ms = pyleo.MultipleSeries(tslist)
@savefig md76_stripes.png
co2ts = pyleo.utils.load_dataset('AACO2')
lr04 = pyleo.utils.load_dataset('LR04')
edc = pyleo.utils.load_dataset('EDC-dD')
ms = lr04.flip() & edc & co2ts # create MS object
@savefig ms_stripes.png
fig, ax = ms.stripes()
pyleo.closefig(fig)
Expand All @@ -2144,23 +2147,25 @@ def stripes(self, ref_period=None, figsize=None, savefig_settings=None, time_un
:okwarning:
:okexcept:
import pyleoclim as pyleo
url = 'http://wiki.linked.earth/wiki/index.php/Special:WTLiPD?op=export&lipdid=MD982176.Stott.2004'
d = pyleo.Lipd(usr_path = url)
tslist = d.to_LipdSeriesList()
tslist = tslist[2:] # drop the first two series which only concerns age and depth
ms = pyleo.MultipleSeries(tslist)
@savefig md76_stripes2.png
fig, ax = ms.stripes(common_time_kwargs={'step': 0.5}, x_offset = 200,
LIM=4, figsize=[8,3])
pyleo.closefig(fig)
import pyleoclim as pyleo
co2ts = pyleo.utils.load_dataset('AACO2')
lr04 = pyleo.utils.load_dataset('LR04')
edc = pyleo.utils.load_dataset('EDC-dD')
ms = lr04.flip() & edc & co2ts # create MS object
@savefig ms_stripes2.png
fig, ax = ms.stripes(figsize=(8,2.5),show_xaxis=True, sat = 0.8)
pyleo.closefig(fig)
'''
current_style = deepcopy(mpl.rcParams)
plotting.set_style('journal', font_scale=font_scale)
savefig_settings = {} if savefig_settings is None else savefig_settings.copy()
common_time_kwargs = {} if common_time_kwargs is None else common_time_kwargs.copy()

if len(self.series_list)>20:
warnings.warn("You are trying to plot over 20 series; results will be hard to see",
UserWarning, stacklevel=2)

# deal with time units
self = self.convert_time_unit(time_unit=time_unit)

Expand Down Expand Up @@ -2188,20 +2193,23 @@ def stripes(self, ref_period=None, figsize=None, savefig_settings=None, time_un
fig, axs = plt.subplots(n_ts, 1, sharex=True, figsize=figsize, layout = 'tight')
ax = axs.flatten()

if xlim is None:
xlim = [time.min(), time.max()]

for idx in range(n_ts-1): # loop over series
ts = msc.series_list[idx].gaussianize()
ts.stripes(ref_period, LIM = LIM, label_color = label_color,
ts = msc.series_list[idx]
ts.stripes(ref_period, sat=sat, cmap= cmap,
label_color = label_color,
ax=ax[idx], x_offset=x_offset)

# handle bottom plot
ts = msc.series_list[last].gaussianize()
ts.stripes(ref_period, LIM = LIM, label_color = label_color,
ax=ax[last], x_offset=x_offset, show_xaxis=True)
ax[last].set_xlabel(time_label)
ts = msc.series_list[last]
ts.stripes(ref_period, sat=sat, cmap=cmap,
label_color = label_color, show_xaxis=show_xaxis,
ax=ax[last], x_offset=x_offset)

if xlim is None:
xlim = [time.min(), time.max()]
ax[last].set_xlim(xlim)

fig.tight_layout()

if 'fig' in locals():
if 'path' in savefig_settings:
Expand Down
2 changes: 1 addition & 1 deletion pyleoclim/core/psds.py
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ def signif_test(self, method='ar1sim', number=None, seed=None, qs=[0.95],
elif method == 'ar1asym':
std = self.timeseries.stats()['std'] # assess standard deviation
if np.abs(std-1) > 0.1:
warnings.warn("Asymptoics are only defined for a standard deviation of unity. Please apply to a standardized series only")
warnings.warn("Asymptotics are only defined for a standard deviation of unity. Please apply to a standardized series only")

new=self.copy()

Expand Down
70 changes: 40 additions & 30 deletions pyleoclim/core/series.py
Original file line number Diff line number Diff line change
Expand Up @@ -964,10 +964,11 @@ def plot(self, figsize=[10, 4],

return res

def stripes(self, ref_period, LIM = 2.8, thickness=1.0, figsize=[8, 1], xlim=None,
top_label=None, bottom_label=None, label_color = 'gray', label_size = None,
xlabel=None, savefig_settings=None, ax=None, invert_xaxis=False,
show_xaxis=False, x_offset = 0.05):
def stripes(self, figsize=[8, 1], cmap = 'RdBu_r', ref_period=None,
sat=1.0, top_label=None, bottom_label=None,
label_color = 'gray', label_size = None, xlim=None,
xlabel=None, savefig_settings=None, ax=None, invert_xaxis=False,
show_xaxis=False, x_offset = 0.03):
'''Represents the Series as an Ed Hawkins "stripes" pattern
Credit: https://matplotlib.org/matplotblog/posts/warming-stripes/
Expand All @@ -977,14 +978,15 @@ def stripes(self, ref_period, LIM = 2.8, thickness=1.0, figsize=[8, 1], xlim=Non
ref_period : array-like (2-elements)
dates of the reference period, in the form "(first, last)"
thickness : float, optional
vertical thickness of the stripe . The default is 1.0
LIM : float
scaling factor for color saturation. default is 2.8
figsize : list
a list of two integers indicating the figure size (in inches)
cmap: str
colormap name (https://matplotlib.org/stable/tutorials/colors/colormaps.html)
sat : float > 0
Controls the saturation of the colormap normalization by scaling the vmin, vmax in https://matplotlib.org/stable/tutorials/colors/colormapnorms.html
default = 0.9
xlim : list
time axis limits
Expand Down Expand Up @@ -1032,48 +1034,56 @@ def stripes(self, ref_period, LIM = 2.8, thickness=1.0, figsize=[8, 1], xlim=Non
See also
--------
pyleoclim.utils.plotting.stripes : stripes representation of a timeseries
pyleoclim.utils.plotting.savefig : saving a figure in Pyleoclim
Examples
--------
Plot the HadCRUT5 Global Mean Surface Temperature
>>> gmst = pyleo.utils.load_dataset('HadCRUT5')
>>> fig, ax = gmst.stripes(ref_period=(1971,2000))
>>> pyleo.closefig(fig)
If you wanted to show the time axis:
For a more pastel tone, dial down saturation:
>>> fig, ax = gmst.stripes(ref_period=(1971,2000), sat = 0.8)
>>> gmst = pyleo.utils.load_dataset('HadCRUT5')
>>> fig, ax = gmst.stripes(ref_period=(1971,2000), show_xaxis=True, figsize=[8, 1.2])
>>> pyleo.closefig(fig)
To change the colormap:
>>> fig, ax = gmst.stripes(ref_period=(1971,2000), cmap='Spectral_r')
>>> fig, ax = gmst.stripes(ref_period=(1971,2000), cmap='magma_r')
To show the time axis:
>>> fig, ax = gmst.stripes(ref_period=(1971,2000), show_xaxis=True)
Note that we had to increase the figure height to make space for the extra text.
'''

if top_label is None:
top_label = self.label

if bottom_label is None:
bottom_label = self.value_name

idx0 = (np.abs(self.time - ref_period[0])).argmin()
idx1 = (np.abs(self.time - ref_period[1])).argmin()

LIMs = self.value.std()*LIM

if ref_period is None:
ref_period = [self.time.min(), self.time.max()]

if sat <= 0:
raise ValueError('sat must be a strictly positive number, ideally close to unity.')

# Ed Hawkins says: Currently I use HadCRUT5 with a 1971-2000 baseline
# and a colour scaling of +/- 0.75K (which is probably similar to LIM).
# It should be relatively simple to duplicate the stripes exactly

# center and normalize values for proper display
yc = self.center(timespan=ref_period).value
vmax = np.abs(yc).max()/sat

time_label, _ = self.make_labels()

res = plotting.stripes_xy(
x=self.time, y=self.value, ref_period=(idx0,idx1), LIM = LIMs, thickness = thickness,
res = plotting.stripes_xy(x=self.time, y=yc, cmap=cmap, vmin=-vmax, vmax=vmax,
top_label = top_label, bottom_label = bottom_label, label_color = label_color,
figsize=figsize, ax=ax, xlim=xlim, invert_xaxis=invert_xaxis, label_size=label_size,
savefig_settings=savefig_settings, show_xaxis=show_xaxis, x_offset = x_offset,
figsize=figsize, ax=ax, xlim=xlim, invert_xaxis=invert_xaxis,
label_size=label_size, xlabel = time_label, x_offset = x_offset,
savefig_settings=savefig_settings, show_xaxis=show_xaxis,
)

return res
Expand Down
14 changes: 6 additions & 8 deletions pyleoclim/tests/test_core_MultipleSeries.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ def test_plot(self):
assert_allclose(t_1, x_plot_1)
assert_allclose(v_0, y_plot_0)
assert_allclose(v_1, y_plot_1)
pyleo.closefig(fig)

class TestMultipleSeriesStripes:
'''Test for MultipleSeries.stripes()
Expand All @@ -140,17 +141,14 @@ def test_stripes(self):
t_1, v_1 = gen_normal()

#Create series objects
ts_0 = pyleo.Series(time = t_0, value = v_0)
ts_1 = pyleo.Series(time = t_1, value = v_1)

#Create a list of series objects
serieslist = [ts_0, ts_1]
ts_0 = pyleo.Series(time = t_0, value = v_0, label='series 1')
ts_1 = pyleo.Series(time = t_1, value = v_1, label='series 2')

#Turn this list into a multiple series object
ts_M = pyleo.MultipleSeries(serieslist)

fig, ax = ts_M.stripes(LIM=4, x_offset=2, label_color = 'red')
ts_M = ts_0 & ts_1

fig, ax = ts_M.stripes(sat=0.9, label_color = 'red', cmap='cividis_r')
pyleo.closefig(fig)

class TestMultipleSeriesStandardize:
'''Test for MultipleSeries.standardize()
Expand Down
15 changes: 5 additions & 10 deletions pyleoclim/tests/test_core_Series.py
Original file line number Diff line number Diff line change
Expand Up @@ -1037,22 +1037,17 @@ def test_plot(self):

x_plot = line.get_xdata()
y_plot = line.get_ydata()


pyleo.closefig(fig)

class TestUiSeriesStripes:
'''Test for Series.stripes()
Series.stripes outputs a matplotlib figure and axis object, so we will compare the time axis
of the axis object to the time array.'''

def test_stripes(self):
'''Test for Series.stripes()'''
@pytest.mark.parametrize('show_xaxis', [True, False])
def test_stripes(self, show_xaxis):

ts = gen_normal()

fig, ax = ts.stripes(ref_period=[61,90],x_offset=2)

fig, ax = ts.stripes(ref_period=[61,90], show_xaxis=show_xaxis)
assert ax.xaxis.get_ticklabels() != []
pyleo.closefig(fig)


Expand Down
Loading

0 comments on commit 5315080

Please sign in to comment.