Python 如何在matplotlib.axes.axes.stem plot中显示时间线?

Python 如何在matplotlib.axes.axes.stem plot中显示时间线?,python,matplotlib,Python,Matplotlib,我正在做一个matplotlib.axes.axes.stem图形,其中x轴是显示日期的日期线。我的一些数据出现在特定日期。而在其他日子,它没有数据(因为我的数据中不存在这样的信息) 问题1:我如何制作一个时间轴干图来显示我的数据,包括没有数据的天数?这可能吗?是否有某种方法可以自动缩放数据x轴的外观来处理这种情况 下面是一个名为test.txt的示例数据文件和我的python脚本,用于读取数据以显示时间轴干图,供您参考。下面也给出了此脚本的输出 问题2.演示问题。如何在每个注释处显示“-”符号

我正在做一个
matplotlib.axes.axes.stem
图形,其中x轴是显示日期的日期线。我的一些数据出现在特定日期。而在其他日子,它没有数据(因为我的数据中不存在这样的信息)

问题1:我如何制作一个时间轴干图来显示我的数据,包括没有数据的天数?这可能吗?是否有某种方法可以自动缩放数据x轴的外观来处理这种情况

下面是一个名为
test.txt
的示例数据文件和我的python脚本,用于读取数据以显示时间轴干图,供您参考。下面也给出了此脚本的输出

问题2.演示问题。如何在每个注释处显示“-”符号?另外,如何将注释旋转30度

test.txt

No. Date 
1   23/01/2020
2   24/01/2020
3   24/01/2020
4   26/01/2020
5   27/01/2020
6   28/01/2020
7   29/01/2020
8   29/01/2020
9   30/01/2020
10  30/01/2020
11  31/01/2020
12  31/01/2020
13  01/02/2020
14  01/02/2020
15  04/02/2020
16  04/02/2020
17  04/02/2020
18  05/02/2020
19  05/02/2020
20  05/02/2020
21  06/02/2020
22  07/02/2020
23  07/02/2020
24  07/02/2020
25  08/02/2020
26  08/02/2020
27  08/02/2020
28  08/02/2020
29  08/02/2020
30  09/02/2020
31  10/02/2020
32  10/02/2020
33  11/02/2020
34  11/02/2020
38  13/02/2020
39  13/02/2020
40  13/02/2020
41  13/02/2020
42  13/02/2020
43  13/02/2020
44  14/02/2020
45  14/02/2020
46  14/02/2020
47  14/02/2020
48  14/02/2020
49  14/02/2020
50  15/02/2020
51  15/02/2020
52  15/02/2020
53  15/02/2020
54  15/02/2020
57  18/02/2020
58  18/02/2020
59  18/02/2020
60  19/02/2020
61  21/02/2020
stem_plot.py

import matplotlib.pyplot as plt
import numpy as np
import matplotlib.dates as mdates
from datetime import datetime

from pathlib import Path

#########################
#### DATA EXTRACTION ####
#########################
source = Path('./test.txt')
with source.open() as f:
  lines = f.readlines()
#print( lines )

# Store source data in dictionary with date shown as mm-dd. 
data={}
for line in lines[1:]:
    case, cdate = line.strip().split()
    cdate = datetime.strptime(cdate, "%d/%m/%Y").strftime('%m-%d')
    data[case] = cdate
print( f'\ndata = {data}' )

# Collate data's y-axis for each date, i.e. history
history2={}
cdates = list(data.values())
sorted_dates = sorted( set( cdates ) )
for i in sorted_dates:
    cases=[]
    for case, date in data.items():
        if i == date:
            cases.append(case)
    #print( i, cases)
    history2[i] = cases 
print( f'\nhistory2 = {history2}')

###########################
#### DATA PRESENTATION ####
###########################
# Create figure and plot a stem plot with the date
fig, ax = plt.subplots(figsize=(8.8, 5), constrained_layout=True)
ax.set(title="Test")

labels=list( history2.values() ) # For annotation 
yy = [ len(i) for i in labels ]  # y-axis
xx = list(history2.keys())       # x-axis
markerline, stemline, baseline = ax.stem(
    xx, yy, linefmt="C1:", basefmt="k-", use_line_collection=True)

plt.setp(markerline, marker="None" ) 

# annotate stem lines
for ann_x, label in list(history2.items()):
    print(ann_x, label)
    each_count=1
    for each in label:
        ax.annotate( each, xy=(ann_x, each_count), xycoords='data')
        each_count += 1
        #print(f'each_count = {each_count}' )

# format xaxis
plt.setp( ax.get_xticklabels(), rotation=30 )

# remove top and right spines
for spine in ["top", "right"]:
    ax.spines[spine].set_visible(False)

# show axis name
ax.get_yaxis().set_label_text(label='Y-axis')
ax.get_xaxis().set_label_text(label='X-axis')

plt.show()
电流输出:


关于你的第一个问题。基本上,你可以列出你正在使用的日期和正在使用的日期之间的所有日期。因此,请在代码开头添加以下内容:

import pandas as pd
alldays = pd.date_range(start="20200123", 
                     end="20200221", 
                     normalize=True)
dates = []
for i in alldays:
    dates.append(f"{i.month:02}-{i.day:02}")
它的作用是获取两个日期之间的数据范围,并将该范围转换为一个月-日字符串列表

然后修改这部分代码,如下所示:

# Collate data's y-axis for each date, i.e. history
history2={}
cdates = list(data.values())
sorted_dates = sorted( set( cdates ) )
for i in dates:  # This is the only change!
    cases=[]
    for case, date in data.items():
        if i == date:
            cases.append(case)
    #print( i, cases)
    history2[i] = cases 
这一变化将给你带来:

关于第二个问题,请将代码更改为:

# annotate stem lines
for ann_x, label in list(history2.items()):
    print(ann_x, label)
    each_count=1
    for each in label:
        ax.annotate(f"--{each}", xy=(ann_x, each_count), xycoords='data', rotation=30)
        each_count += 1
我刚刚更改了
ax.annotate
行。这两项改变是:

  • 将“-”添加到每个批注标签
  • 添加了一个旋转参数。旋转参数不会直接出现在中,但文档中说明可以使用任何文本方法作为
    kwargs
    ,它们是
  • 这将有望满足您的要求:


    添加@SinanKurmus对我的第一个问题的回答:

    解决方案1: 对于给定数据的整个历史记录,可以使用matplotlib的方法,即and、and和python,获得具有每日间隔的时间轴。这里可以避免使用熊猫

    首先,将时间轴的开始和结束日期表示为python datetime对象。注意,您需要在结束日期后再添加一天,否则将不包括上一个日期的数据。接下来,使用python的
    datetime.timedelta
    对象使用1天作为时间间隔。接下来,将它们提供给将返回NumPy数组的
    matplotlib.date.drange
    方法。Matplotlib的num2date方法依次将其转换回python datetime对象

    def get_time_axis( data ):
        start = datetime.strptime(min(data.values()), "%Y-%m-%d")
        end = datetime.strptime(max(data.values()), "%Y-%m-%d") + timedelta(days=1)
        delta = timedelta(days=1)
        time_axis_md = mdates.drange( start, end, delta )
        time_axis_py = mdates.num2date( time_axis_md, tz=None ) # Add tz when required
        return time_axis_py
    
    解决方案2: 显然,Matplotlib也有一个常见问题解答。我在下面包含了他们的示例代码示例

    import numpy as np
    import matplotlib.pyplot as plt
    import matplotlib.mlab as mlab
    import matplotlib.ticker as ticker
    
    r = mlab.csv2rec('../data/aapl.csv')
    r.sort()
    r = r[-30:]  # get the last 30 days
    
    N = len(r)
    ind = np.arange(N)  # the evenly spaced plot indices
    
    def format_date(x, pos=None):
        thisind = np.clip(int(x+0.5), 0, N-1)
        return r.date[thisind].strftime('%Y-%m-%d')
    
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.plot(ind, r.adj_close, 'o-')
    ax.xaxis.set_major_formatter(ticker.FuncFormatter(format_date))
    fig.autofmt_xdate()
    
    plt.show() 
    

    你能把你目前掌握的密码发出去吗?(还有,输出的图像。)@MateenUlhaq我已经提供了您要求的信息。您是否必须使用文本文件并使用字典绘图?“可以用熊猫之类的东西吗?”SinanKurmus肯定。更重要的是,我需要有关matplotlib部分的建议