You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Plotly柱状图中如何让rangeslider自动缩放Y轴(Python)

问题

使用Plotly + Dash时遇到如下问题:通过DatePicker手动选择日期范围,Y轴能自动缩放适配当前数据;但拖动rangeslider调整X轴范围时,Y轴不会自动更新缩放,导致图表难以解读。尝试设置fixedrange=False或autorange=True都无法解决该问题,希望找到无需额外组件的解决方案。

解决方案

要实现rangeslider拖动时Y轴自动缩放,核心是监听rangeslider触发的图表布局变化事件,根据新的X轴范围重新过滤数据并生成图表。具体修改如下:

  1. 在回调中添加对图表relayoutData的监听,捕捉rangeslider的拖动操作
  2. 在回调函数中判断是否是rangeslider触发的范围变更,优先使用该范围过滤数据
  3. 基于过滤后的最新数据重新绘制图表,让Y轴自动适配当前数据范围

修改后的完整代码:

import dash
from dash import dcc, html, Input, Output
import dash_bootstrap_components as dbc
import plotly.express as px
import pandas as pd
from datetime import datetime

# 生成测试数据
df1 = pd.DataFrame({'Type': ['B','K','L','N']})
N = 300
df1 = pd.concat([df1] * N, ignore_index=True)
df1['TIMESTAMP'] = pd.date_range(start='2024/01/01 07:36', end='2024/01/30 08:38', periods=len(df1))

df2 = pd.DataFrame({'Type': ['B','K','L','N']})
N = 3
df2 = pd.concat([df2] * N, ignore_index=True)
df2['TIMESTAMP'] = pd.date_range(start='2024/01/30 08:37', end='2024/02/28 08:38', periods=len(df2))

df = pd.concat([df1,df2])
df['Date'] = df['TIMESTAMP'].dt.date
df['Date'] = df['Date'].astype(str)

external_stylesheets = [dbc.themes.SPACELAB, dbc.icons.BOOTSTRAP]
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)

app.layout = dbc.Container([
    dbc.Row([
        html.Div([
            dcc.DatePickerRange(
                id='date-picker',
                display_format='DD/MM/YYYY',
                show_outside_days=True,
                minimum_nights=0,
                initial_visible_month=df['Date'].min(),
                min_date_allowed=df['Date'].min(),
                max_date_allowed=df['Date'].max(),
                start_date=df['Date'].min(),
                end_date=df['Date'].max()
            ),
            dcc.Dropdown(
                id='Type',
                options=[{'label': x, 'value': x} for x in df['Type'].unique()],
                value=df['Type'].unique(),
                multi=True,
            ),
        ]),
        dcc.Graph(id='date-bar-chart')
    ])
])

@app.callback(
    Output('date-bar-chart', 'figure'),
    Input('date-picker','start_date'), 
    Input('date-picker','end_date'),
    Input('Type', 'value'),
    Input('date-bar-chart', 'relayoutData')  # 添加监听relayout事件
)     
def chart(start_date, end_date, selected_types, relayout_data):
    # 优先使用rangeslider的范围
    if relayout_data and 'xaxis.range[0]' in relayout_data and 'xaxis.range[1]' in relayout_data:
        # 将rangeslider返回的时间字符串转为日期格式
        slider_start = datetime.strptime(relayout_data['xaxis.range[0]'].split('T')[0], '%Y-%m-%d').date()
        slider_end = datetime.strptime(relayout_data['xaxis.range[1]'].split('T')[0], '%Y-%m-%d').date()
        dff = df[(df['TIMESTAMP'].dt.date >= slider_start) & (df['TIMESTAMP'].dt.date <= slider_end)]
    else:
        # 使用DatePicker的范围
        dff = df[(df['Date'] >= start_date) & (df['Date'] <= end_date)]
    
    dff = dff[dff['Type'].isin(selected_types)]
    df_count = dff.groupby(['Date','Type'])['Type'].count().reset_index(name='counts')

    type_fig = px.bar(x=df_count['Date'], 
                      y=df_count['counts'],
                      color=df_count['Type']
                      )

    type_fig.update_layout(
        xaxis=dict(
            rangeselector=dict(
                buttons=list([
                    dict(count=7, label='1w', step='day', stepmode='backward'),
                    dict(count=1, label='1m', step='month', stepmode='backward'),
                    dict(count=6, label='6m', step='month', stepmode='backward'),
                    dict(count=1, label='YTD', step='year', stepmode='todate'),
                    dict(count=1, label='1y', step='year', stepmode='backward'),
                    dict(step='all')
                ])
            ),
            rangeslider=dict(visible=True),
            type='date'
        ),
        yaxis=dict(autorange=True, fixedrange=False),
    )

    return type_fig

if __name__ == '__main__':
    app.run_server(debug=True)

关键修改说明

  • 添加relayoutData监听:通过Input('date-bar-chart', 'relayoutData')捕捉rangeslider拖动时的布局变化事件
  • 范围优先级处理:当检测到rangeslider的范围数据时,优先使用该范围过滤数据;否则沿用DatePicker的选择
  • 日期格式转换:将rangeslider返回的ISO格式时间字符串转换为日期,确保和数据中的日期格式匹配
  • 简化布局配置:移除无效的xaxis_rangeslider_yaxis_rangemode等配置,依赖Plotly自动根据数据适配Y轴

内容的提问来源于stack exchange,提问作者tonydanza123

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 23:44:58