关于Altair中mark_text()图层模糊与重复问题的技术咨询
热图叠加文本模糊重复问题解决
我尝试制作带叠加文本的热图,参考Altair官方教程适配示例数据时一切正常,但使用自有数据集运行以下代码后,mark_text()图层出现模糊、重复的情况:
import altair as alt, pandas as pd, numpy as np quarters = ['2022-Q1', '2022-Q2', '2022-Q3', '2022-Q4', '2023-Q1', '2023-Q2', '2023-Q3', '2023-Q4'] risk_bands = ['A++', 'A+', 'A', 'B', 'C', 'R'] vintages = [2020, 2021, 2022, 2023] cpr = pd.DataFrame({ 'quarter': np.random.choice(quarters, 1000), 'GEN5_RISK_BAND_CALC': np.random.choice(risk_bands, 1000), 'VINTAGE_YEAR': np.random.choice(vintages, 1000), 'cpr': np.random.randint(0, 40, 1000) }) base = alt.Chart(cpr).mark_rect().encode( x=alt.X('quarter:O', axis=(alt.Axis(labelAngle=45))), y='VINTAGE_YEAR:O', ) heatmap = base.mark_rect().encode( color=alt.Color( 'cpr:Q', scale=alt.Scale( range=['white', 'red'], ), legend=alt.Legend(direction='vertical', orient='left', title='cpr') ), ) text = base.mark_text( baseline='middle', dx=0, ).encode( text='cpr', tooltip=[] ) chart = alt.layer(base + heatmap + text).facet( 'GEN5_RISK_BAND_CALC:N', columns=2 ) chart
运行后效果如图:
问题原因
原始数据中,每个热图单元格(由quarter、VINTAGE_YEAR、GEN5_RISK_BAND_CALC共同确定)对应多条记录,文本图层会将每条记录的cpr值都绘制在同一位置,导致文字重叠、模糊。
解决方法
先对数据按热图的分组维度进行聚合,得到每个单元格的唯一统计值(示例中取均值,可根据需求替换为求和、中位数等),再基于聚合后的数据绘图:
import altair as alt, pandas as pd, numpy as np quarters = ['2022-Q1', '2022-Q2', '2022-Q3', '2022-Q4', '2023-Q1', '2023-Q2', '2023-Q3', '2023-Q4'] risk_bands = ['A++', 'A+', 'A', 'B', 'C', 'R'] vintages = [2020, 2021, 2022, 2023] cpr = pd.DataFrame({ 'quarter': np.random.choice(quarters, 1000), 'GEN5_RISK_BAND_CALC': np.random.choice(risk_bands, 1000), 'VINTAGE_YEAR': np.random.choice(vintages, 1000), 'cpr': np.random.randint(0, 40, 1000) }) # 按分组维度聚合,计算每个单元格的cpr均值 cpr_agg = cpr.groupby(['quarter', 'VINTAGE_YEAR', 'GEN5_RISK_BAND_CALC'])['cpr'].mean().reset_index() # 可选:将均值取整,让文本更整洁 cpr_agg['cpr'] = cpr_agg['cpr'].round(0).astype(int) base = alt.Chart(cpr_agg).mark_rect().encode( x=alt.X('quarter:O', axis=(alt.Axis(labelAngle=45))), y='VINTAGE_YEAR:O', ) heatmap = base.mark_rect().encode( color=alt.Color( 'cpr:Q', scale=alt.Scale( range=['white', 'red'], ), legend=alt.Legend(direction='vertical', orient='left', title='cpr') ), ) text = base.mark_text( baseline='middle', dx=0, color='black' # 可选:设置文本颜色,与背景区分更明显 ).encode( text='cpr', tooltip=[] ) chart = alt.layer(heatmap + text).facet( 'GEN5_RISK_BAND_CALC:N', columns=2 ) chart
额外优化说明
- 聚合时可根据业务需求选择合适的统计函数(如
sum()、median()) - 可设置文本颜色(如
color='black'),让文字与热图背景对比更清晰 - 移除了冗余的
base图层叠加,因为heatmap已经包含了矩形标记
内容的提问来源于stack exchange,提问作者Derek Fulton
相关产品推荐
相关产品推荐

