matplotlib 如何将背景颜色从折线图添加到折线图的线段

zi8p0yeb  于 2023-10-24  发布在  其他
关注(0)|答案(1)|浏览(136)

我有一个框架如下,并希望得到一个情节与线和背景颜色要么红色或白色(取决于颜色的值_var)。

line_var color_var
datetime        
2023-04-20 13:45    3     1
2023-04-20 14:00    4     0
2023-04-20 15:00    5     0
2023-04-20 15:15    4     1
2023-04-20 15:45    3     1
2023-04-20 16:00    5     1
2023-04-20 16:45    6     0
2023-04-20 17:45    7     0
2023-04-20 18:00    5     0
2023-04-20 18:45    6     1
2023-04-20 19:45    8     1
2023-04-21 13:45    9     0

下面的代码

import pandas as pd
import numpy as np
from matplotlib import dates as mdates
from matplotlib.colors import ListedColormap
import matplotlib.pyplot as plt

df = pd.DataFrame({'datetime':['2023-04-20 13:45','2023-04-20 14:00','2023-04-20 15:00',
'2023-04-20 15:15','2023-04-20 15:45','2023-04-20 16:00','2023-04-20 16:45','2023-04-20 17:45','2023-04-20 18:00','2023-04-20 18:45','2023-04-20 19:45','2023-04-21 13:45'],
'line_var':[3,4,5,4,3,5,6,7,5,6,8,9], 
'color_var':[1,0,0,1,1,1,0,0,0,1,1,0]})

df = df.assign(datetime=pd.to_datetime(df.datetime))
df = df.set_index('datetime')

cmap = ListedColormap(['white','red'])

fig = plt.figure(figsize=(50,10))
ax = fig.add_subplot()

ax.plot(df['line_var'])
ax.set_xlabel('')

plt.xticks(rotation = 30)
ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d'))

#this gives an error
ax.pcolor(df.index, ax.get_ylim(), 
           df['color_var'].values[np.newaxis].T, 
           cmap = cmap, alpha = 0.4, 
           linewidth=0, antialiased=True, shading='nearest')
plt.axhline(y = 0, color = 'black')
plt.tight_layout()

抛出错误

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[21], line 21
     18 ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d'))
     20 #this gives an error
---> 21 ax.pcolor(df.index, ax.get_ylim(), 
     22            df['color_var'].values[np.newaxis].T, 
     23            cmap = cmap, alpha = 0.4, 
     24            linewidth=0, antialiased=True, shading='nearest')
     25 plt.axhline(y = 0, color = 'black')
     26 plt.tight_layout()

File ~\anaconda3\envs\py11\Lib\site-packages\matplotlib\__init__.py:1442, in _preprocess_data.<locals>.inner(ax, data, *args, **kwargs)
   1439 @functools.wraps(func)
   1440 def inner(ax, *args, data=None, **kwargs):
   1441     if data is None:
-> 1442         return func(ax, *map(sanitize_sequence, args), **kwargs)
   1444     bound = new_sig.bind(ax, *args, **kwargs)
   1445     auto_label = (bound.arguments.get(label_namer)
   1446                   or bound.kwargs.get(label_namer))

File ~\anaconda3\envs\py11\Lib\site-packages\matplotlib\axes\_axes.py:5946, in Axes.pcolor(self, shading, alpha, norm, cmap, vmin, vmax, *args, **kwargs)
   5944     shading = mpl.rcParams['pcolor.shading']
   5945 shading = shading.lower()
-> 5946 X, Y, C, shading = self._pcolorargs('pcolor', *args, shading=shading,
   5947                                     kwargs=kwargs)
   5948 Ny, Nx = X.shape
   5950 # convert to MA, if necessary.

File ~\anaconda3\envs\py11\Lib\site-packages\matplotlib\axes\_axes.py:5757, in Axes._pcolorargs(self, funcname, shading, *args, **kwargs)
   5755 else:    # ['nearest', 'gouraud']:
   5756     if (Nx, Ny) != (ncols, nrows):
-> 5757         raise TypeError('Dimensions of C %s are incompatible with'
   5758                         ' X (%d) and/or Y (%d); see help(%s)' % (
   5759                             C.shape, Nx, Ny, funcname))
   5760     if shading == 'nearest':
   5761         # grid is specified at the center, so define corners
   5762         # at the midpoints between the grid centers and then use the
   5763         # flat algorithm.
   5764         def _interp_grid(X):
   5765             # helper for below

TypeError: Dimensions of C (12, 1) are incompatible with X (12) and/or Y (2); see help(pcolor)

我在这里读到Numpy pcolormesh: TypeError: Dimensions of C are incompatible with X and/or Y,我应该转置我的数组,但它不起作用,或者我没有正确地这样做。

bn31dyow

bn31dyow1#

matplotlib的pcolor函数期望X、Y和C参数在特定的维度上,以在图中阴影区域。您遇到的问题是X、Y和C数组的维度不匹配。
当你为X提供df.index,为Y提供ax.get_ylim()时,你基本上是告诉pcolor考虑尺寸为(12,2)的矩形网格,因为df.index的长度为12,ax.get_ylim()的长度为2。
但是,df['color_var'].values[np.newaxis].T提供的C数组(颜色数据)的形状是(12,1),这与前面提到的网格不兼容。
解决这个问题的一种方法是将X和Y数组网格化以创建所需的网格,然后扩展C数组以匹配此网格的形状。

import pandas as pd
import numpy as np
from matplotlib import dates as mdates
from matplotlib.colors import ListedColormap
import matplotlib.pyplot as plt

df = pd.DataFrame({
    'datetime': ['2023-04-20 13:45', '2023-04-20 14:00', '2023-04-20 15:00',
                 '2023-04-20 15:15', '2023-04-20 15:45', '2023-04-20 16:00',
                 '2023-04-20 16:45', '2023-04-20 17:45', '2023-04-20 18:00',
                 '2023-04-20 18:45', '2023-04-20 19:45', '2023-04-21 13:45'],
    'line_var': [3, 4, 5, 4, 3, 5, 6, 7, 5, 6, 8, 9],
    'color_var': [1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0]
})

df = df.assign(datetime=pd.to_datetime(df.datetime))
df = df.set_index('datetime')

fig, ax = plt.subplots(figsize=(10, 6))

# Plot the line
ax.plot(df['line_var'], color='blue')

# Fill background color based on color_var values
for i in range(1, len(df)):
    if df['color_var'].iloc[i] == 1:
        ax.fill_between([df.index[i-1], df.index[i]], y1=ax.get_ylim()[0], y2=ax.get_ylim()[1], color='red', alpha=0.4)

plt.xticks(rotation=30)
ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d'))
plt.axhline(y=0, color='black')
plt.tight_layout()
plt.show()

更新:

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

df = pd.DataFrame({
    'datetime': ['2023-04-20 13:45', '2023-04-20 14:00', '2023-04-20 15:00',
                 '2023-04-20 15:15', '2023-04-20 15:45', '2023-04-20 16:00',
                 '2023-04-20 16:45', '2023-04-20 17:45', '2023-04-20 18:00',
                 '2023-04-20 18:45', '2023-04-20 19:45', '2023-04-21 13:45'],
    'line_var': [3, 4, 5, 4, 3, 5, 6, 7, 5, 6, 8, 9],
    'color_var': [1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0]
})

df = df.assign(datetime=pd.to_datetime(df.datetime))
df = df.set_index('datetime')

fig, ax = plt.subplots(figsize=(10, 6))

# Plot the line
ax.plot(df['line_var'], color='blue')

# Fill background color based on color_var values
start_fill = None
for i, (timestamp, value) in enumerate(df['color_var'].items()):
    if value == 1 and start_fill is None:
        start_fill = timestamp
    elif value == 0 and start_fill is not None:
        ax.fill_between([start_fill, timestamp], y1=ax.get_ylim()[0], y2=ax.get_ylim()[1], color='red', alpha=0.4)
        start_fill = None

# Handling the case if the last value in color_var is 1
if start_fill is not None:
    ax.fill_between([start_fill, df.index[-1]], y1=ax.get_ylim()[0], y2=ax.get_ylim()[1], color='red', alpha=0.4)

plt.xticks(rotation=30)
ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d'))
plt.axhline(y=0, color='black')
plt.tight_layout()
plt.show()

相关问题