TL;DR - 问题
我有一个基于 pandas
数据框的 mplfinance
图,其中索引采用格鲁吉亚日历格式,我需要将它们显示为 Jalali 格式。
我的数据和代码
我的数据如下所示:
open high low close
date
2021-03-15 67330.0 69200.0 66870.0 68720.0
2021-03-16 69190.0 71980.0 69000.0 71620.0
2021-03-17 72450.0 73170.0 71700.0 71820.0
2021-03-27 71970.0 73580.0 70000.0 73330.0
2021-03-28 73330.0 73570.0 71300.0 71850.0
... ... ... ... ...
第一列既是日期又是索引。这是 mplfinance 正确绘制数据所必需的; 我可以用这样的东西来绘制:
import mplfinance as mpf
mpf.plot(chart_data.tail(7), figratio=(16,9), type="candle", style='yahoo', ylabel='', tight_layout=True, xrotation=90)
其中 chart_data
是上面的数据,其余的几乎都是格式化内容。
我现在拥有的
我的图表如下所示:
但是,我需要日期如下所示:1400-01-12
。这是一个等价表,可以进一步证明我的情况。
2021-03-15 1399-12-25
2021-03-16 1399-12-26
2021-03-17 1399-12-27
2021-03-27 1400-01-07
2021-03-28 1400-01-08
我尝试过的
将 Jdates 设置为我的索引:
chart_data.index = history.jdate
mpf.plot(chart_data_j)
抛出此异常:
TypeError('Expect data.index as DatetimeIndex')
所以我尝试将 jdates 转换为 datetime
s:
chart_data_j.index = pd.to_datetime(history.jdate)
这引发了越界异常:
OutOfBoundsDatetime: Out of bounds nanosecond timestamp: 1398-03-18 00:00:00
所以我认为更改时区/区域设置可能是一种选择,所以我尝试按照官方文档更改时区:
pd.to_datetime(history.date).tz_localize(tz='US/Eastern')
但是我遇到了这个异常:
raise TypeError(f"{ax_name} is not a valid DatetimeIndex or PeriodIndex")
最后我尝试使用 PersianTools 和 pandas_jalali 等库,但没有成功。
最佳答案
您可以通过创建自己的自定义 DateFormatter 类并使用 mpf.plot()
kwarg returnfig=True
来访问 Axes 对象来实现此功能能够安装您自己的自定义 DateFormatter。
我编写了一个自定义 DateFormatter(请参阅下面的代码)它知道当 show_nontrading=False< 时 MPLfinance 处理 x 轴的特殊方式
(即默认值)。
import pandas as pd
import mplfinance as mpf
import jdatetime as jd
import matplotlib.dates as mdates
from matplotlib.ticker import Formatter
class JalaliDateTimeFormatter(Formatter):
"""
Formatter for JalaliDate in mplfinance.
Handles both `show_nontrading=False` and `show_nontrading=True`.
When show_nonntrading=False, then the x-axis is indexed by an
integer representing the row number in the dataframe, thus:
Formatter for axis that is indexed by integer, where the integers
represent the index location of the datetime object that should be
formatted at that lcoation. This formatter is used typically when
plotting datetime on an axis but the user does NOT want to see gaps
where days (or times) are missing. To use: plot the data against
a range of integers equal in length to the array of datetimes that
you would otherwise plot on that axis. Construct this formatter
by providing the arrange of datetimes (as matplotlib floats). When
the formatter receives an integer in the range, it will look up the
datetime and format it.
"""
def __init__(self, dates=None, fmt='%b %d, %H:%M', show_nontrading=False):
self.dates = dates
self.len = len(dates) if dates is not None else 0
self.fmt = fmt
self.snt = show_nontrading
def __call__(self, x, pos=0):
'''
Return label for time x at position pos
'''
if self.snt:
jdate = jd.date.fromgregorian(date=mdates.num2date(x))
formatted_date = jdate.strftime(self.fmt)
return formatted_date
ix = int(round(x,0))
if ix >= self.len or ix < 0:
date = None
formatted_date = ''
else:
date = self.dates[ix]
jdate = jd.date.fromgregorian(date=mdates.num2date(date))
formatted_date = jdate.strftime(self.fmt)
return formatted_date
# ---------------------------------------------------
df = pd.read_csv('so_67001540.csv',index_col=0,parse_dates=True)
mpf.plot(df,figratio=(16,9),type="candle",style='yahoo',ylabel='',xrotation=90)
dates = [mdates.date2num(d) for d in df.index]
formatter = JalaliDateTimeFormatter(dates=dates,fmt='%Y-%m-%d')
fig, axlist = mpf.plot(df,figratio=(16,9),
type="candle",style='yahoo',
ylabel='',xrotation=90,
returnfig=True)
axlist[0].xaxis.set_major_formatter(formatter)
mpf.show()
- 文件
'so_67001540.csv'
如下所示:
date,open,high,low,close,alt_date
2021-03-15,67330.0,69200.0,66870.0,68720.0,1399-12-25
2021-03-16,69190.0,71980.0,69000.0,71620.0,1399-12-26
2021-03-17,72450.0,73170.0,71700.0,71820.0,1399-12-27
2021-03-27,71970.0,73580.0,70000.0,73330.0,1400-01-07
2021-03-28,73330.0,73570.0,71300.0,71850.0,1400-01-08
- 运行上述脚本时,您应该得到以下两个图:
关于python-3.x - 如何在 mplfinance 中显示替代日历日期?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67001540/