Search code examples
pythonmatplotlibplotcolorsintervals

plot multicolor line with x as datetime and change color by y


For 2 days I am trying to plot a multicolor line. My data looks like this:

                     gradient result
date                                
2022-04-15 09:43:20  0.206947      E
2022-04-15 10:25:00  0.102620      E
2022-04-15 11:06:40  0.019450      C
2022-04-15 11:48:20  0.025945      D
2022-04-15 12:30:00  0.022455      D
                      ...    ...
2022-05-02 14:13:20  0.003770      A
2022-05-02 14:55:00  0.084120      E
2022-05-02 15:36:40  0.134970      E
2022-05-02 16:18:20  0.261385      E
2022-05-02 17:00:00  0.955833    NaN

I have used to following script to plot the graph:

import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import numpy as np
from matplotlib.collections import LineCollection

dates = data_646_mean.index
y = data_646_mean.gradient

s = pd.Series(y, index=dates)

fig, ax = plt.subplots()

#convert dates to numbers first
inxval = mdates.date2num(s.index.to_pydatetime())
points = np.array([inxval, s.values]).T.reshape(-1,1,2)
segments = np.concatenate([points[:-1],points[1:]], axis=1)

lc = LineCollection(segments, cmap="plasma", linewidth=3)
# set color to date values
#lc.set_array(inxval)
# note that you could also set the colors according to y values
lc.set_array(s.values())
# add collection to axes
ax.add_collection(lc)


ax.xaxis.set_major_locator(mdates.MonthLocator())
ax.xaxis.set_minor_locator(mdates.DayLocator())
monthFmt = mdates.DateFormatter("%b")
ax.xaxis.set_major_formatter(monthFmt)
ax.autoscale_view()
plt.show()

This has worked but the different colors are not set within a certain range for y:

Graph1

And I would really like to make the colors depend on the category in the result column. And if that is not possible I would like to give certain intervals:

blue = 0.1 - 0.2
red = 0.2 - 0.5
green = 0.5 - 0.9
black = 0.9 1.4

I hope somewan could help me out.


Solution

  • import pandas as pd
    import matplotlib.pyplot as plt
    import matplotlib.dates as mdates
    import numpy as np
    from matplotlib.collections import LineCollection
    import matplotlib.cm as cm
    
    data_646_mean = pd.read_csv("path/to/file")
    data_646_mean["date"] = pd.to_datetime(data_646_mean["date"])
    dates = data_646_mean["date"].values
    y = data_646_mean["gradient"].values
    # convert results to categories so that we can apply it
    # to the color value of the line
    cat_series = pd.Categorical(data_646_mean["result"])
    
    fig, ax = plt.subplots()
    
    # convert dates to numbers first
    dates_num = mdates.date2num(dates)
    points = np.array([dates_num, y]).T.reshape(-1,1,2)
    segments = np.concatenate([points[:-1],points[1:]], axis=1)
    
    # use a subset of Tab10 (categorical color map)
    cmap = cm.get_cmap('tab10', len(cat_series.categories))
    lc = LineCollection(segments, cmap=cmap, linewidth=3)
    lc.set_array(cat_series.codes)
    ax.add_collection(lc)
    
    # add a colorbar, modify the position of the ticks
    cb = fig.colorbar(lc, ticks=np.linspace(-0.5, 3.5, 5))
    # set the categories to be the value of the ticks
    cb.ax.set_yticklabels(cat_series.categories)
    
    ax.xaxis.set_major_locator(mdates.MonthLocator())
    ax.xaxis.set_minor_locator(mdates.DayLocator())
    monthFmt = mdates.DateFormatter("%b")
    ax.xaxis.set_major_formatter(monthFmt)
    ax.autoscale_view()
    plt.show()