mdates 定位器在我的图表中显示了不存在的时间区间

1 投票
2 回答
57 浏览
提问于 2025-04-14 15:18

我正在尝试为股市制作一个streamlit仪表板。我的股票数据是从早上9点到下午4点的。我在x轴上使用了定位器来标记刻度。然而,图表显示了一些不存在的时间段,比如在图上,刻度之间有很大的间隙,并且在下午4点到早上9点之间画了一条直线。我想去掉这个间隙,让图表变得连续。请问我该怎么解决这个问题?我尝试过滤我的数据,但没有成功。

这是我的代码和一些示例输出。

def create_plot(name:str,label:str,title_info:str,data,period_var:str):
        fig, ax1 = plt.subplots(figsize=(16,8))

        ax1.set_ylabel(name)
        plt.xlabel('Datetime')
        plt.ylabel(label)
        plt.title(title_info)
        
        if period_var in ["1d"]:
            date_formatter = DateFormatter('%H:%M')
            ax1.xaxis.set_major_formatter(date_formatter)
            ax1.xaxis.set_major_locator(mdates.MinuteLocator(interval=30))

        elif period_var in ["3d","5d"]:
            date_formatter = DateFormatter("%d-%H")
            ax1.xaxis.set_major_formatter(date_formatter)
            ax1.xaxis.set_major_locator(mdates.HourLocator(byhour=range(9,16),interval=2))
        elif period_var in ["1mo", "3mo", "6mo"]:
            date_formatter = DateFormatter("%Y - %b")
            ax1.xaxis.set_major_formatter(date_formatter)

            ax1.xaxis.set_major_locator(mdates.DayLocator(interval=int(period_var[0])*2))
        elif period_var in ["1y", "2y", "5y"]:
            date_formatter = DateFormatter("%Y-%b")
            ax1.xaxis.set_major_formatter(date_formatter)
            ax1.xaxis.set_major_locator(mdates.MonthLocator(interval=int(period_var[0])))
        else:
            date_formatter = DateFormatter("%Y")
            ax1.xaxis.set_major_formatter(date_formatter)
            ax1.xaxis.set_major_locator(mdates.YearLocator())
            

        ax1.plot(data.Date, data[name], label=name, marker='o', markersize=1)
        plt.xticks(rotation=45)
        plt.legend()
        plt.grid(True)
        plt.tight_layout()

        return fig


在这里输入图片描述

如果有人能帮我解决这个问题,我会很感激。

我尝试过滤我的数据,即数据["日期"],但没有效果。我想去掉那些在我的数据框中不存在的时间段。

2 个回答

1

一种方法是用原来的索引来重新排列你过滤后的数据表,这样在你不想绘制的时间点就会出现NaN(缺失值)记录。

最小可复现示例(MVCE):

import pandas as pd
import numpy as np

df = pd.DataFrame(np.random.random(2_000), 
                  index=pd.date_range('2021-10-03 07:00:00', 
                                      periods=2_000, freq='T'), 
                  columns=['value'])

dfs = df.between_time('09:00','15:00')

dfs.reindex(df.index).plot()

输出结果:

这里是图片描述

与不重新排列索引的情况对比:

dfs.plot()

这里是图片描述

0

我已经解决了我的问题,忽略了日期时间索引,并设置了新的刻度。下面是我代码的最新版本。如果有人遇到同样的问题,希望这对你们有帮助。

def create_plot(name: str, label: str, title_info: str, data, period_var: str):
    fig, ax1 = plt.subplots(figsize=(16, 8), sharex=True)

    data.index = pd.to_datetime(data.index)
    ax1.set_ylabel(name)
    plt.xlabel('Datetime')
    plt.ylabel(label)
    plt.title(title_info)

    if period_var in ["1d"]:
        date_formatter = DateFormatter('%H:%M')
        ax1.xaxis.set_major_formatter(date_formatter)
        ax1.xaxis.set_major_locator(mdates.MinuteLocator(interval=30))
        ax1.plot(data.index, data[name], label=name, marker='o', markersize=1)
        fill_green(data=data,name=name,ax1=ax1)

    elif period_var in ["3d", "5d"]:
        date_formatter = DateFormatter("%d-%H")
        ax1.xaxis.set_major_formatter(date_formatter)
        ax1.xaxis.set_major_locator(mdates.HourLocator(byhour=range(9, 16), interval=30))
        ax1.plot(range(data.index.size), data[name], label=name, marker='o', markersize=1)
        ymin = min(data[name])
        ymax = max(data[name])
        padding = 0.05 * (ymax - ymin) 
        ax1.set_ylim(ymin - padding, ymax + padding)


        ax1.fill_between(range(data.index.size), data[name], color='green', alpha=0.3)

        ticks_date = data.index.indexer_at_time('08:00')
        ticks_time = np.arange(data.index.size)[data.index.minute == 0][::2] 
        ax1.set_xticks(ticks_date)
        ax1.set_xticks(ticks_time, minor=True)

        labels_date = [maj_tick.strftime('\n%d-%b').replace('\n0', '\n')
                       for maj_tick in data.index[ticks_date]]
        labels_time = [min_tick.strftime('%d %I %p').lstrip('0').lower()
                       for min_tick in data.index[ticks_time]]
        ax1.set_xticklabels(labels_date)
        ax1.set_xticklabels(labels_time, minor=True)

    elif period_var in ["1mo", "3mo", "6mo"]:
        date_formatter = DateFormatter("%Y - %b")
        ax1.xaxis.set_major_formatter(date_formatter)
        ax1.plot(data.index, data[name], label=name, marker='o', markersize=1)
        ax1.xaxis.set_major_locator(mdates.DayLocator(interval=int(period_var[0]) * 2))
        fill_green(data=data,name=name,ax1=ax1)
    elif period_var in ["1y", "2y", "5y"]:
        date_formatter = DateFormatter("%Y-%b")
        ax1.xaxis.set_major_formatter(date_formatter)
        ax1.xaxis.set_major_locator(mdates.MonthLocator(interval=int(period_var[0])))
        ax1.plot(data.index, data[name], label=name, marker='o', markersize=1)
        fill_green(data=data,name=name,ax1=ax1)
    else:
        date_formatter = DateFormatter("%Y")
        ax1.xaxis.set_major_formatter(date_formatter)
        ax1.xaxis.set_major_locator(mdates.YearLocator())
        ax1.plot(data.index, data[name], label=name, marker='o', markersize=1)
        fill_green(data=data,name=name,ax1=ax1)
        
    plt.xticks(rotation=45)
    plt.legend()
    plt.grid(False)
    plt.tight_layout()

    return fig

撰写回答