Issue
I would like to plot for each value from my dataframe a different axvspan function.
My df to plot a simple curve:
date_time value End_DateTime Duration(Min)
2020-09-08 13:05:08.506633 5 2020-09-08 13:05:08.847000 0.005673
2020-09-08 13:05:08.847000 15 2020-09-08 13:05:39.176823 0.505497
2020-09-08 13:05:39.176823 20 2020-09-08 13:05:40.785900 0.026818
2020-09-08 13:05:40.785900 25 2020-09-08 13:05:41.091760 0.005098
2020-09-08 13:05:41.091760 30 2020-09-08 13:06:26.207699 0.751932
2020-09-08 13:06:26.207699 35 2020-09-08 13:08:31.656359 2.090811
2020-09-08 13:08:31.656359 40 2020-09-08 13:24:19.688665 15.800538
2020-09-08 13:24:19.688665 45 2020-09-08 13:24:25.853547 0.102748
2020-09-08 13:24:25.853547 47 2020-09-08 13:24:26.824579 0.016184
2020-09-08 13:24:26.824579 55 2020-09-08 13:24:27.788014 0.016057
2020-09-08 13:24:27.788014 5 2020-09-08 13:24:28.143081 0.005918
And for each value, I would like to plot axvspan with start = date_time and end = end_datetime with a color for each value. So I tried this :
data = df #create unique list of names
UniqueNames = data.value.unique()
#create a data frame dictionary to store your data frames
DataFrameDict_axvspan = {elem : pd.DataFrame for elem in UniqueNames}
for key in DataFrameDict_axvspan.keys():
DataFrameDict_axvspan[key] = data[:][data.value == key]
and:
df.plot('date_time', 'value', figsize=(16, 8), label="G7", drawstyle="steps-post")
for i in DataFrameDict_axvspan:
plt.axvspan(i[0],i[1], facecolor='orange', alpha=0.5)
plt.show()
My main problem is to plot axvspan with a different color for each value... PS : With this df, there is 2 value = 5, so it must be 2 area with the same color.
EDITH
when I use your method it works except for small changes in values, the color doesn't change, i think it's due to normalization, is there a way to take these small changes into account anyway with colors ?
Solution
Note that your DataFrameDict_axvspan
contains at some point data from the value
column as keys and for all of them the class pd.DataFrame
as values. I doubt this is what you want. Simply write DataFrameDict_axvspan = dict()
and populate the dict in the for-loop:
data = df #create unique list of names
uniques = data.value.unique()
#create a data frame dictionary to store your data frames
dfdict_axvspan = {} # this is your DataFrameDict_axvspan
for key in uniques:
dfdict_axvspan[key] = ...
However, I'm not sure if why you would need all of this to plot axvspan's with colors based on the value column of your df... Mabye simply have a look at the example below and try this directly with your df:
One way to associate colors to values is with colormaps, matplotlib has quite a few.
If you are not familiar with colormaps in matplotlib, the idea behind them is to associate color-flows to the numerical interval [0, 1]. In general the mapping is linear, however, other relations are possible.
To account for values from an arbitrary interval, it is also straightforward to map the data range to the unit interval with Normalize.
So one way to approach your problem could be by mapping the data range of your value
column to a colormap. The colormap 'viridis', used below is just as an example, here you can find others. An implementation might look a little like this:
from matplotlib import pyplot as plt
from matplotlib import cm
from matplotlib.colors import Normalize
class ColoredValues():
"""Colormap for arbitrary values"""
def __init__(self, cmap: str, vmin, vmax):
self._cmap = cm.get_cmap(cmap)
self._norm = Normalize(vmin, vmax)
def get_color(self, value):
return self._cmap(self._norm(value))
# get the data range
vmin, vmax = df['value'].min(), df['value'].max()
# initiate the colormap 'viridis' is just an example
cv = ColoredValues('viridis', vmin, vmax)
# now the plotting could look something like this:
for i, row in df.iterrows():
plt.axvspan(row['date_time'],row['End_DateTime'],
facecolor=cv.get_color(row['value']),
alpha=0.5)
Hope this is enough to get you started!
Addedndum
Small changes in the values might lead to similar colors which can be difficult to disentangle.
As a first approach to address this you could simply try out colormaps with stronger fluctuations in color, like the 'prism'
colormap for example.
If this does not lead to satisfying results then one way to address this problem is with listed-colormaps. This approach consists in generating a colormap from a list of colors. This allows to change single colors in this list before generating the colormap. In fact, we can actually use a colormap to generate this list of colors, that is then used to generate a custom colormap:
Here is how this could look in your case.
import numpy as np
from matplotlib.colors import (Normalize, to_rgba,
ListedColormap)
from matplotlib import pyplot as plt
from matplotlib import cm
# just the same as before...
class ColoredValues():
"""Colormap for arbitrary values"""
def __init__(self, cmap: str, vmin, vmax):
self._cmap = cm.get_cmap(cmap)
self._norm = Normalize(vmin, vmax)
def get_color(self, value):
return self._cmap(self._norm(value))
# get the data range
vmin, vmax = df['value'].min(), df['value'].max()
# HERE we create a colormap as basis for the list of colors
refcmap = cm.get_cmap('viridis', int(vmax))
# create the list of colors (the +1 is just to map your values to the index)
colorlist = refcmap(np.linspace(0, 1, int(vmax) + 1))
# now you can change single colors in the list
colorlist[10] = to_rgba('blue')
colorlist[47] = to_rgba('green')
# now, we create a custom colormap from this list of colors
newcmp = ListedColormap(colorlist)
# initiate the colormap this time directly passing newcmp
cv = ColoredValues(newcmp, vmin, vmax)
# now the plotting could look something like this:
for i, row in df.iterrows():
plt.axvspan(row['date_time'],row['End_DateTime'],
facecolor=cv.get_color(row['value']),
alpha=0.5)
Answered By - jojo
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.