如何用Python Plotly实现Treemap正负值分色及按日期时间调整
使用Plotly绘制带正负值颜色区分与日期可调的Treemap
解决方案概述
针对你的需求,我们可以通过自定义颜色映射实现负值节点红色、正值节点绿色的样式,同时借助Dash(Plotly的交互框架)实现日期范围的动态筛选,以下是完整的可运行代码和关键细节说明:
1. 数据准备(模拟你的数据结构)
假设你的数据包含日期时间、一级分类、二级分类、百分比变化字段,先模拟一份可复用的测试数据:
import pandas as pd import numpy as np from datetime import datetime, timedelta # 生成模拟数据 dates = pd.date_range(start='2024-01-01', end='2024-01-31', freq='D') categories = ['产品', '运营', '技术'] sub_categories = ['电商', '线下', '活动', '用户', '后端', '前端'] data = [] for date in dates: for cat in categories: for sub_cat in sub_categories: if sub_cat in ['电商','线下'] and cat == '产品': pct = np.random.uniform(-12, 18) data.append({ 'date': date, 'category': cat, 'sub_category': sub_cat, 'percent_change': round(pct, 2) }) elif sub_cat in ['活动','用户'] and cat == '运营': pct = np.random.uniform(-8, 22) data.append({ 'date': date, 'category': cat, 'sub_category': sub_cat, 'percent_change': round(pct, 2) }) elif sub_cat in ['后端','前端'] and cat == '技术': pct = np.random.uniform(-5, 25) data.append({ 'date': date, 'category': cat, 'sub_category': sub_cat, 'percent_change': round(pct, 2) }) df = pd.DataFrame(data)
2. 正负值颜色映射逻辑
直接通过自定义列给每个条目分配颜色,确保负值红、正值绿、零值灰色:
# 自定义颜色规则 df['node_color'] = df['percent_change'].apply( lambda x: '#e74c3c' if x < 0 else '#2ecc71' if x > 0 else '#95a5a6' )
3. 日期动态调整实现
使用Dash的DatePickerRange组件实现日期范围选择,结合回调函数实时更新Treemap:
import plotly.express as px import dash from dash import dcc, html, Input, Output, callback # 初始化Dash应用 app = dash.Dash(__name__) app.layout = html.Div([ html.H2("Treemap:按日期筛选+正负值颜色区分"), # 日期范围选择器 dcc.DatePickerRange( id='date-selector', min_date_allowed=df['date'].min(), max_date_allowed=df['date'].max(), start_date=df['date'].max() - timedelta(days=6), end_date=df['date'].max(), display_format='YYYY-MM-DD' ), # Treemap图表容器 dcc.Graph(id='treemap-plot') ]) # 回调函数:根据选择的日期更新图表 @callback( Output('treemap-plot', 'figure'), Input('date-selector', 'start_date'), Input('date-selector', 'end_date') ) def update_treemap(start_date, end_date): # 筛选指定日期范围的数据 filtered_df = df[(df['date'] >= start_date) & (df['date'] <= end_date)] # 按分类聚合百分比(可根据你的需求调整聚合逻辑) aggregated_df = filtered_df.groupby(['category', 'sub_category'])['percent_change'].sum().reset_index() # 重新生成颜色列 aggregated_df['node_color'] = aggregated_df['percent_change'].apply( lambda x: '#e74c3c' if x < 0 else '#2ecc71' if x > 0 else '#95a5a6' ) # 绘制Treemap fig = px.treemap( aggregated_df, path=['category', 'sub_category'], values=np.abs(aggregated_df['percent_change']), # 用绝对值确保节点大小不受负值影响 color='node_color', color_discrete_map='identity', # 直接使用自定义颜色值 hover_data={ 'percent_change': ':,.2f%', # 格式化百分比显示 'node_color': False # 隐藏颜色字段的hover提示 }, title=f"日期范围:{start_date} 至 {end_date}" ) # 显示节点名称和数值 fig.update_traces(textinfo='label+value') return fig # 运行应用 if __name__ == '__main__': app.run_server(debug=True)
关键注意事项
- 节点大小逻辑:用
np.abs()处理百分比,避免负值导致节点大小异常,节点大小反映百分比的绝对值 - 颜色适配:如果需要调整红绿色调,直接修改
#e74c3c(红色)和#2ecc71(绿色)的十六进制颜色码即可 - 聚合逻辑:根据你的实际数据结构调整
groupby的字段,比如如果不需要聚合,直接使用原始筛选数据即可 - 交互优化:如果不需要Dash的网页交互,也可以用Plotly的静态RangeSlider组件,但动态筛选功能会受限
内容的提问来源于stack exchange,提问作者Đỗ Văn Thắng
相关产品推荐
相关产品推荐

