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

Plotly/Dash直方图分箱hovertemplate自定义格式化展示钢琴练习时长

解决方案

有两种可行实现方式,你可以根据自己的需求选择:

方案1:最小改动现有直方图逻辑

核心利用Plotly内置的时间格式化能力,仅需修改几行代码即可实现需求:

改动点:

  • SQL查询直接读取秒级时长,避免分钟转秒的精度损失
  • 将y值乘以1000转为毫秒时间戳格式,即可通过Plotly的strftime格式化符直接渲染时分秒
  • 如需y轴也展示时分秒,新增y轴tickformat配置即可

修改后核心代码片段:

# 改动1:查询直接取秒
cur.execute("select started date, seconds FROM practice")
result = cur.fetchall()
con.close()

df = pd.DataFrame(result, columns=['date', 'seconds'])

data = [dict(
    x=df['date'],
    # 改动2:y值转毫秒,适配Plotly时间格式化规则
    y=df['seconds'] * 1000,
    marker=dict(color='rgb(68, 68, 68)'),
    name='date',
    type='histogram',
    histfunc="sum",
    xbins=dict(
        size='1D',
        start='1983-12-31 00:00',
        end='2026-12-31 00:00',
    ),
    # 改动3:hover模板用时间格式渲染
    hovertemplate=
    '%{y|%H:%M:%S} 练习时长<br>' +
    '%{x}<br><extra></extra>'
)]

layout = dict(
    # 其他配置不变,新增y轴tickformat可让y轴也显示时分秒,不需要可以删掉
    yaxis=dict(
        title='练习时长',
        type='linear',
        tickformat='%H:%M:%S'
    ),
    # 原有updatemenus配置不变
)

注意:该方案如果单日练习时长超过24小时,%H格式化会自动取模显示为0-23区间值,无法正确显示超过24小时的总时长,如果有超过24小时的统计需求请使用方案2。


方案2:改用预聚合柱状图(更灵活,推荐)

直方图的自动聚合逻辑限制较多,你可以放弃直方图,改用pandas提前按选中的时间粒度聚合数据,自定义格式化时分秒后放到customdata中,完全可控hover展示内容。需要新增一个Dash回调触发聚合逻辑,替换原有restyle改xbins的实现:

完整修改后代码:

import sqlite3
import dash
from dash import dcc, html, Input, Output
import pandas as pd
from datetime import timedelta

app = dash.Dash(__name__)

# 提前加载基础数据避免每次请求查库
con = sqlite3.connect('practicetracker.db')
df = pd.read_sql("select started as date, seconds FROM practice", con, parse_dates=['date'])
con.close()
df = df.set_index('date')

def format_seconds(sec):
    # 自定义格式化函数,支持超过24小时的时长展示
    td = timedelta(seconds=int(sec))
    hours = td.days * 24 + td.seconds // 3600
    minutes = (td.seconds % 3600) // 60
    seconds = td.seconds % 60
    return f"{hours:02d}:{minutes:02d}:{seconds:02d}"

app.layout = html.Div([
    dcc.RadioItems(
        id='time-granularity',
        options=[
            {'label': '小时', 'value': 'H'},
            {'label': '天', 'value': 'D'},
            {'label': '周', 'value': 'W'},
            {'label': '月', 'value': 'M'}
        ],
        value='D',
        style={'position': 'absolute', 'top': 10, 'right': 10}
    ),
    dcc.Graph(id='practice-fig')
])

@app.callback(
    Output('practice-fig', 'figure'),
    Input('time-granularity', 'value')
)
def update_fig(gran):
    # 按选中粒度聚合
    agg_df = df.resample(gran).sum().reset_index()
    # 格式化时分秒存入customdata
    agg_df['format_time'] = agg_df['seconds'].apply(format_seconds)
    return {
        'data': [
            {
                'x': agg_df['date'],
                'y': agg_df['seconds'],
                'type': 'bar',
                'marker': {'color': 'rgb(68, 68, 68)'},
                'customdata': agg_df['format_time'],
                'hovertemplate': '%{customdata} 练习时长<br>%{x}<br><extra></extra>'
            }
        ],
        'layout': {
            'paper_bgcolor': 'rgb(240, 240, 240)',
            'plot_bgcolor': 'rgb(240, 240, 240)',
            'title': '<b>钢琴练习时长</b>',
            'bargap': 0.2,
            'yaxis': {
                'title': '练习时长(秒)'
                # 也可以自定义y轴tick为时分秒格式,按需调整即可
            }
        }
    }

if __name__ == '__main__':
    app.run_server(host="0.0.0.0", debug=True)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 02:06:04