python - كيفية رسم خط متعدد الألوان إذا كان المحور السيني هو مؤشر وقت تاريخ الباندا




pandas matplotlib (2)

تعتبر إيماننس أوف بيينج إرنست إجابة جيدة للغاية وأنقذتني ساعات طويلة من العمل. أريد أن أشارك كيف استخدمت الإجابة أعلاه لتغيير اللون بناء على إشارة من الباندا DataFrame.

import matplotlib.dates as mdates
# import matplotlib.pyplot as plt
# import numpy as np
# import pandas as pd
from matplotlib.collections import LineCollection
from matplotlib.colors import ListedColormap, BoundaryNorm

جعل اختبار DataFrame

equity = pd.DataFrame(index=pd.date_range('20150701', periods=150))
equity['price'] = np.random.uniform(low=15500, high=18500, size=(150,))
equity['signal'] = 0
equity.signal[15:45] = 1
equity.signal[60:90] = -1
equity.signal[105:135] = 1

# Create a colormap for crimson, limegreen and gray and a norm to color
# signal = -1 crimson, signal = 1 limegreen, and signal = 0 lightgray
cmap = ListedColormap(['crimson', 'lightgray', 'limegreen'])
norm = BoundaryNorm([-1.5, -0.5, 0.5, 1.5], cmap.N)

# Convert dates to numbers
inxval = mdates.date2num(equity.index.to_pydatetime())

# Create a set of line segments so that we can color them individually
# This creates the points as a N x 1 x 2 array so that we can stack points
# together easily to get the segments. The segments array for line collection
# needs to be numlines x points per line x 2 (x and y)
points = np.array([inxval, equity.price.values]).T.reshape(-1,1,2)
segments = np.concatenate([points[:-1],points[1:]], axis=1)

# Create the line collection object, setting the colormapping parameters.
# Have to set the actual values used for colormapping separately.
lc = LineCollection(segments, cmap=cmap, norm=norm, linewidth=2)

# Set color using signal values
lc.set_array(equity.signal.values)

fig, ax = plt.subplots()
fig.autofmt_xdate()

# Add collection to axes
ax.add_collection(lc)

plt.xlim(equity.index.min(), equity.index.max())
plt.ylim(equity.price.min(), equity.price.max())
plt.tight_layout()

# plt.savefig('test_mline.png', dpi=150)
plt.show()

أحاول رسم خط متعدد الألوان باستخدام سلسلة الباندا. أعلم أن matplotlib.collections.LineCollection سيعزز بشدة الكفاءة. لكن LineCollection تتطلب قطاعات الخط يجب أن تطفو. أرغب في استخدام فهرس بيانات التاريخ للباندا كمحور x.

points = np.array((np.array[df_index.astype('float'), values]).T.reshape(-1,1,2))
segments = np.concatenate([points[:-1],points[1:]], axis=1)
lc = LineCollection(segments)
fig = plt.figure()
plt.gca().add_collection(lc)
plt.show()

لكن الصورة لا يمكن أن تجعلني راضية. هل هناك أي حل؟


لإنتاج خط متعدد الألوان ، ستحتاج إلى تحويل التواريخ إلى أرقام أولاً ، لأن matplotlib داخليًا يعمل فقط مع القيم الرقمية.

لتحويل matplotlib يوفر matplotlib.dates.date2num . هذا يفهم كائنات وقت ، لذلك ستحتاج أولاً إلى تحويل سلاسل الوقت إلى وقت باستخدام series.index.to_pydatetime() ثم قم بتطبيق date2num .

s = pd.Series(y, index=dates)
inxval = mdates.date2num(s.index.to_pydatetime())

يمكنك بعد ذلك العمل مع النقاط الرقمية كالمعتاد ، على سبيل المثال التخطيط مثل Polygon أو LineCollection [ 1 ، 2 ].

المثال الكامل:

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

dates = pd.date_range("2017-01-01", "2017-06-20", freq="7D" )
y = np.cumsum(np.random.normal(size=len(dates)))

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()

نظرًا لأن الأشخاص على ما يبدو يواجهون مشاكل في إيقاف هذا المفهوم ، فإليك نفس الكود المذكور أعلاه دون استخدام الباندا ومع مجموعة ألوان مستقلة:

import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import numpy as np; np.random.seed(42)
from matplotlib.collections import LineCollection

dates = np.arange("2017-01-01", "2017-06-20", dtype="datetime64[D]" )
y = np.cumsum(np.random.normal(size=len(dates)))
c = np.cumsum(np.random.normal(size=len(dates)))


fig, ax = plt.subplots()

#convert dates to numbers first
inxval = mdates.date2num(dates)
points = np.array([inxval, y]).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(c)
ax.add_collection(lc)


loc = mdates.AutoDateLocator()
ax.xaxis.set_major_locator(loc)
ax.xaxis.set_major_formatter(mdates.AutoDateFormatter(loc))
ax.autoscale_view()
plt.show()






matplotlib