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)
问题原因
- 柱状图使用未聚合的原始数据
df_filtered_2023,Altair自动对同月份的Totais求和;文本标签使用提前聚合的total_custo_2023数据集,若两个数据集的x轴编码、数据范围(如年份筛选)存在偏差,会导致标签无法匹配显示。 - 示例数据年份为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
相关产品推荐
相关产品推荐

