1

Given the following data:

dt = pd.DataFrame.from_dict(
    {
        "thing": {0: "A", 1: "B", 2: "C"},
        "min": {
            0: "2021-11-01 00:00:00+00:00",
            1: "2021-11-01 00:00:00+00:00",
            2: "2021-11-01 00:00:00+00:00",
        },
        "max": {
            0: "2021-11-02 00:00:00+00:00",
            1: "2021-11-05 00:00:00+00:00",
            2: "2021-11-07 00:00:00+00:00",
        },
    }
).assign(
    min=lambda x: pd.to_datetime(x["min"]),
    max=lambda x: pd.to_datetime(x["max"]),
)

Which looks like:

|    | thing   | min                       | max                       |
|---:|:--------|:--------------------------|:--------------------------|
|  0 | A       | 2021-11-01 00:00:00+00:00 | 2021-11-02 00:00:00+00:00 |
|  1 | B       | 2021-11-01 00:00:00+00:00 | 2021-11-05 00:00:00+00:00 |
|  2 | C       | 2021-11-01 00:00:00+00:00 | 2021-11-07 00:00:00+00:00 |

I would like to create a plot which has thing on the y-axis, and each a line representing the min / max on the x-axis.

Eg:

enter image description here

So the x-axis is the date, and the y-axis represents each 'thing'.

1 Answer 1

2

One option first reshaping with melt:

import matplotlib.pyplot as plt

ax = plt.subplot()
for k, g in dt.reset_index().melt(['index', 'thing']).groupby('thing'):
    g.plot(x='value', y='index', ax=ax, label=k, marker='s')

labels = dt['thing'].unique()

ax.set_yticks(range(len(labels)), labels)
ax.invert_yaxis()

Output:

enter image description here

alternative with

import seaborn as sns

g = sns.relplot(data=dt.reset_index().melt(['index', 'thing']),
                x='value', y='index', hue='thing',
                kind='line', marker='s')
labels = dt['thing'].unique()

g.ax.set_yticks(range(len(labels)), labels)
g.ax.invert_yaxis()

g.set_xticklabels(rotation=30)

Output:

enter image description here

pure

ax = plt.subplot()
for row in dt.itertuples():
    ax.plot((row.min, row.max), (row.Index,)*2, label=row.thing, marker='s')

ax.set_yticks(range(len(dt)), dt['thing'])

ax.invert_yaxis()

If you want to keep the original order of the rows:

for row in dt.reset_index(drop=True).itertuples():
    ax.plot((row.min, row.max), (row.Index,)*2, label=row.thing, marker='s')

# OR

for i, row in enumerate(dt.itertuples()):
    ax.plot((row.min, row.max), (i,)*2, label=row.thing, marker='s')
Sign up to request clarification or add additional context in comments.

6 Comments

thanks - for the sns version as well, is there an approach using default mpl for the plotting instead of df.plot (or sns) though ? I tried ax.plot with the melt approach and it didn't work
Sure, see last update
Note - this is also dependent on the labels being in an ordering with sorted - if the labels were DBC instead of ABC the approach would give the wrong result
The ordering relies on the index, you can use enumerate if you prefer, or change the index. You haven't given any specifics for that so I assumed ;)
Yes, the sorted should be removed
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.