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

Altair同一月份多数据场景下mark_text总和不显示问题求助

解决Altair中同月份多数据时mark_text不显示月度求和值的问题

问题描述

使用Python的Altair和Streamlit开发时,遇到同一产品同一月份存在多条采购数据的情况,柱状图鼠标悬停能看到拆分的数值,但mark_text无法显示月度求和值。

示例数据

DT Digitacao;Descr Prod;Totais;
01/01/2024;SOLUPAN;2352
02/01/2024;SOLUPAN;2352
03/01/2024;SOLUPAN;1176
03/01/2024;SOLUPAN;588
04/01/2024;SOLUPAN;1176

原代码

import streamlit as st
import pandas as pd 
import locale
import altair as alt

locale.setlocale(locale.LC_TIME, 'pt_BR.UTF-8')

st.set_page_config(
    layout="wide",
    page_title="SD1 Lavadores"
)

df = pd.read_csv("consultas/scczxck0.csv", encoding='latin-1', sep=';')

#Altera o campo para data
df['DT Digitacao'] = pd.to_datetime(df['DT Digitacao'])
df['Ano'] = df['DT Digitacao'].dt.year
df['Mes'] = df['DT Digitacao'].dt.month

#Conta quantas vezes 'Descr Prod' aparece no csv
produtos = df['Descr Prod'].unique()

#Cria a selectbox de acordo com os nomes existentes
produto = st.selectbox('Nome Produto', produtos)
df_filtered = df[df['Descr Prod'] == produto]

# Calcula o custo de cada mês
total_custo = df_filtered.groupby(['Ano', 'Mes'])['Totais'].sum().reset_index(name='ValorTotal')
total_custo_2023 = total_custo[total_custo['Ano'] == 2023]

# Filtra os dados apenas para o ano de 2023
df_filtered_2023 = df_filtered[df_filtered['Ano'] == 2023]

# Gráfico de barras custo mensal 2023
grafico_custo_2023 = alt.Chart(df_filtered_2023).mark_bar().encode(
    x=alt.X('Mes:N', axis=alt.Axis(title='Mês'.upper())),
    y=alt.Y('Totais:Q', axis=alt.Axis(title='Custo Total por Mês'.upper()), scale=alt.Scale(domain=[0, 30000])),
            ).interactive()

# Adiciona rótulos de dados com o custo total de cada mês 2023
custo_2023 = alt.Chart(total_custo_2023).mark_text(
    align='center',
    baseline='middle',
    dx=0,
    dy=-7,  # Ajuste para posicionar o texto acima das barras
    fontSize=14  # Define o tamanho da fonte do rótulo
).encode(
    x=alt.X('Mes:N', axis=alt.Axis(title='Mês'.upper())),
    y=alt.Y('ValorTotal:Q'),
    text=alt.Text('ValorTotal:Q', format='$,.2f')  # Formata o texto para exibir moeda
)

grafico_final_custo2023 = (grafico_custo_2023 + custo_2023).properties(width=600, height=400)

# Coluna 1
col1, col2 = st.columns(2)

with col1:
    st.markdown("<h2 style='text-align: center; color: black;'>Custo de Compra Mensal 2023</h2>", unsafe_allow_html=True)
    col1.altair_chart(grafico_final_custo2023, use_container_width=True)

问题原因

  1. 柱状图使用未聚合的原始数据df_filtered_2023,Altair自动对同月份的Totais求和;文本标签使用提前聚合的total_custo_2023数据集,若两个数据集的x轴编码、数据范围(如年份筛选)存在偏差,会导致标签无法匹配显示。
  2. 示例数据年份为2024,但代码中筛选了2023年数据,导致total_custo_2023为空,自然无文本标签显示。

解决方案

方案1:统一使用聚合后的数据集

将柱状图和文本标签的数据源统一为聚合后的total_custo_2023(或对应年份的聚合数据),确保两者数据完全匹配,避免匹配偏差:

# 替换原柱状图代码
grafico_custo_2023 = alt.Chart(total_custo_2023).mark_bar().encode(
    x=alt.X('Mes:N', axis=alt.Axis(title='Mês'.upper())),
    y=alt.Y('ValorTotal:Q', axis=alt.Axis(title='Custo Total por Mês'.upper()), scale=alt.Scale(domain=[0, 30000])),
).interactive()

方案2:在Altair中直接使用聚合函数

无需提前用Pandas分组,直接在Altair的编码中使用sum()函数计算月度总和,同时文本标签也使用相同的聚合逻辑:

# 删除原total_custo相关代码,替换为以下内容
df_filtered_2024 = df_filtered[df_filtered['Ano'] == 2024]  # 匹配示例数据年份

# 柱状图直接聚合求和
grafico_custo_2024 = alt.Chart(df_filtered_2024).mark_bar().encode(
    x=alt.X('Mes:N', axis=alt.Axis(title='Mês'.upper())),
    y=alt.Y('sum(Totais):Q', axis=alt.Axis(title='Custo Total por Mês'.upper()), scale=alt.Scale(domain=[0, 30000])),
).interactive()

# 文本标签同样使用sum(Totais)计算总和
custo_2024 = alt.Chart(df_filtered_2024).mark_text(
    align='center',
    baseline='middle',
    dx=0,
    dy=-7,
    fontSize=14
).encode(
    x=alt.X('Mes:N'),
    y=alt.Y('sum(Totais):Q'),
    text=alt.Text('sum(Totais):Q', format='$,.2f')
)

额外注意事项

确保年份筛选与实际数据一致,比如示例数据是2024年,代码中需将2023替换为2024,否则聚合后的数据集为空,文本标签无法显示。

修改后的完整代码

import streamlit as st
import pandas as pd 
import locale
import altair as alt

locale.setlocale(locale.LC_TIME, 'pt_BR.UTF-8')

st.set_page_config(
    layout="wide",
    page_title="SD1 Lavadores"
)

df = pd.read_csv("consultas/scczxck0.csv", encoding='latin-1', sep=';')

#Altera o campo para data
df['DT Digitacao'] = pd.to_datetime(df['DT Digitacao'])
df['Ano'] = df['DT Digitacao'].dt.year
df['Mes'] = df['DT Digitacao'].dt.month

#Conta quantas vezes 'Descr Prod' aparece no csv
produtos = df['Descr Prod'].unique()

#Cria a selectbox de acordo com os nomes existentes
produto = st.selectbox('Nome Produto', produtos)
df_filtered = df[df['Descr Prod'] == produto]

# Calcula o custo de cada mês
total_custo = df_filtered.groupby(['Ano', 'Mes'])['Totais'].sum().reset_index(name='ValorTotal')
total_custo_2024 = total_custo[total_custo['Ano'] == 2024]  # 匹配示例数据年份

# 统一使用聚合后的数据集绘制柱状图
grafico_custo_2024 = alt.Chart(total_custo_2024).mark_bar().encode(
    x=alt.X('Mes:N', axis=alt.Axis(title='Mês'.upper())),
    y=alt.Y('ValorTotal:Q', axis=alt.Axis(title='Custo Total por Mês'.upper()), scale=alt.Scale(domain=[0, 30000])),
).interactive()

# 文本标签同样使用聚合后的数据集
custo_2024 = alt.Chart(total_custo_2024).mark_text(
    align='center',
    baseline='middle',
    dx=0,
    dy=-7,  # Ajuste para posicionar o texto acima das barras
    fontSize=14  # Define o tamanho da fonte do rótulo
).encode(
    x=alt.X('Mes:N'),
    y=alt.Y('ValorTotal:Q'),
    text=alt.Text('ValorTotal:Q', format='$,.2f')  # Formata o texto para exibir moeda
)

grafico_final_custo2024 = (grafico_custo_2024 + custo_2024).properties(width=600, height=400)

# Coluna 1
col1, col2 = st.columns(2)

with col1:
    st.markdown("<h2 style='text-align: center; color: black;'>Custo de Compra Mensal 2024</h2>", unsafe_allow_html=True)
    col1.altair_chart(grafico_final_custo2024, use_container_width=True)

内容的提问来源于stack exchange,提问作者Renan Ceolim Ramos

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 20:44:55