Amelia
Amelia

Reputation: 89

Obtaining and plotting a step plot for time series dataframe

I had the following dataframe containing information about stages as a time series:

import pandas as pd
d = {'Stages': ['Stage 1', 'Stage 2', 'Stage 2', 'Stage 2', 'Stage 3', 'Stage 1'], 'Start(s)': [0, 630, 780, 840, 900, 930], 'End(s)': [630, 780, 840, 900, 930, 960]}
df = pd.DataFrame(data=d)

    Stages         Start(s) End(s)
0   Stage 1          0      630
1   Stage 2         630     780
2   Stage 2         780     840
3   Stage 2         840     900
4   Stage 3         900     930
5   Stage 1         930     960

I wanted to obtain a step plot as shown here so I did this:

#Replacing the string stages
mapping = {'Stage 1': 1, 'Stage 2': 2,'Stage 3': 3}
DF = df.replace({'Stages': mapping})

This gives me

    Stages     Start(s) End(s)
0   1            0      630
1   2            630    780
2   2            780    840
3   2            840    900
4   3            900    930
5   1            930    960

Can someone please tell me how to obtain a plot such as this?

Upvotes: 1

Views: 267

Answers (2)

Tom
Tom

Reputation: 8800

My first thought was to use the "steps" drawstyle provided by matploltib. If you use this, you can almost just plot the values in the "End(s)" column - the catch is you need to prepend the first start time/stage to the list of values being plotted:

x = [df['Start(s)'].iloc[0], *df['End(s)']]
y = [df['Stages'].iloc[0], *df['Stages']]

plt.plot(x, y, drawstyle='steps')

enter image description here

This is about the bare minimum; it ignores the particular formatting specific to the sleep cycle, rather it hopefully shows you how to draw the desired curve "from scratch".


Additional notes:

  • If you need to invert the y axis, you can convert the stages to negative integers instead of positive ones.
  • If you need to rename the y labels, you can use plt.yticks([1, 2, 3], ['a', 'b', 'c']) to rename them.
  • Generally this approach is reliant on the "stages" being interpretable as integers. If you had additional stages that were not numeric, you would need to recode them to numbers, and then change their name using plt.yticks as above.

Upvotes: 1

Timeless
Timeless

Reputation: 37847

IIUC, you can use yasa.plot_hypnogram.

Try this :

import pandas as pd
import yasa #pip install yasa

d = {'Stages': ['Stage 1', 'Stage 2', 'Stage 2', 'Stage 2', 'Stage 3', 'Stage 1'],
     'Start(s)': [0, 630, 780, 840, 900, 930], 'End(s)': [630, 780, 840, 900, 930, 960]}

ser = (
        pd.DataFrame(data=d)
            .replace({"Stages": {"Stage ": ""}}, regex=True)
            .astype({"Stages": int})
            .assign(Time= lambda x: [list(range(i, j+1)) for i, j in x[["Start(s)", "End(s)"]].values])
            .explode("Time")
            .loc[:, "Stages"]
      )

yasa.plot_hypnogram(ser)

# Output :

enter image description here

-2 = Unscored -1 = Artefact / Movement 0 = Wake 1 = N1 sleep 2 = N2 sleep 3 = N3 sleep 4 = REM sleep

NB : You may need to use a Python version (>=3.7, <3.11) to install all of yasa dependencies. Python version (3.11.0) seems to not be supported yet.

Upvotes: 2

Related Questions