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

Altair保存数据到磁盘时图例顺序异常,如何维持正确排序?

问题描述

现有如下DataFrame:

A           B           C
0   1.624345    -0.611756   2
1   -1.072969   0.865408    1
2   1.744812    -0.761207   2
3   -0.249370   1.462108    2
4   -0.322417   -0.384054   11
5   -1.099891   -0.172428   1
6   0.042214    0.582815    1
7   1.144724    0.901591    11
8   0.900856    -0.683728   11
9   -0.935769   -0.267888   2

使用A、B列绘制散点图并按C列着色,执行以下代码时:

alt.Chart(randf).mark_point(size=100, filled=True).encode(
    x="A", y="B", color="C:N"
).properties(width=200, height=200)

图例顺序为1、2、11,符合数值排序预期。

但当使用自定义CSV数据转换器将数据保存到磁盘后(代码如下):

import os
from toolz.curried import pipe

def csv_dir(data, data_dir="altairdata") -> None:
    os.makedirs(data_dir, exist_ok=True)
    return pipe(data, alt.to_csv(filename=data_dir + "/{prefix} -{hash}.{extension}"))

alt.data_transformers.register("csv_dir", csv_dir)
alt.data_transformers.enable("csv_dir", data_dir="./.temporary_altair_data/")

再次绘制相同图表,图例顺序变成1、11、2,是按字符串排序而非数值排序。

需要解决的问题:在数据保存到磁盘的情况下,如何让图例保持正确的数值排序?

完整复现代码:

import pandas as pd
import altair as alt
import numpy as np 
import os
from toolz.curried import pipe


np.random.seed(1)
randf = pd.DataFrame(np.random.randn(10, 3), columns=list("ABC"))
randf["C"] = np.random.choice([1, 2, 11], 10)

# 内嵌数据时的图表
chart1 = alt.Chart(randf).mark_point(size=100, filled=True).encode(
    x="A", y="B", color="C:N"
)
chart1 

# 启用磁盘存储数据后的图表
def csv_dir(data, data_dir="altairdata") -> None:
    os.makedirs(data_dir, exist_ok=True)
    return pipe(data, alt.to_csv(filename=data_dir + "/{prefix} -{hash}.{extension}"))

alt.data_transformers.register("csv_dir", csv_dir)
alt.data_transformers.enable("csv_dir", data_dir="./.temporary_altair_data/")

chart2 = alt.Chart(randf).mark_point(size=100, filled=True).encode(
    x="A", y="B", color="C:N"
)
chart2
解决方案

问题根源是:数据保存为CSV文件时,C列数值会被默认解析为字符串类型,Altair对字符串字段按字典序排序,导致11排在2前面。可通过以下方式解决:

方法1:明确指定字段类型

在编码时将C:N改为有序分类类型C:O或定量类型C:Q,让Altair按数值排序:

chart2 = alt.Chart(randf).mark_point(size=100, filled=True).encode(
    x="A", y="B", color=alt.Color("C:O", title="C")
).properties(width=200, height=200)
  • C:O(有序分类)保留分类特性,同时按数值排序;
  • C:Q(定量)会将C视为连续数值,图例变为颜色条,按需选择。

方法2:使用类型保留的存储格式

改用Parquet格式存储数据(Parquet会完整保留数据类型),修改数据转换器:

def parquet_dir(data, data_dir="altairdata") -> None:
    os.makedirs(data_dir, exist_ok=True)
    return pipe(data, alt.to_parquet(filename=data_dir + "/{prefix} -{hash}.{extension}"))

alt.data_transformers.register("parquet_dir", parquet_dir)
alt.data_transformers.enable("parquet_dir", data_dir="./.temporary_altair_data/")

Parquet适合大数据场景,避免CSV的类型丢失问题。

方法3:手动指定图例排序

通过sort参数强制指定排序顺序:

# 获取C列唯一值并按数值排序
sorted_values = sorted(randf["C"].unique())

chart2 = alt.Chart(randf).mark_point(size=100, filled=True).encode(
    x="A", y="B", color=alt.Color("C:N", sort=sorted_values, title="C")
).properties(width=200, height=200)

该方法灵活性高,适合自定义排序需求。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 13:01:18