- 数据可视化
【免费下载链接】altair
Declarative visualization library for Python
导读
本文围绕 Altair(声明式 Python 可视化库)中circle标记展开,系统讲解mark_circle()的用法、circle标记与point标记的区别、专用属性size的语义,并结合仓库源码与真实示例给出可复跑的散点图代码。读完本文,你将掌握如何用mark_circle()快速绘制散点图、气泡图,理解其填充与尺寸的底层行为,并能进一步结合size/color/tooltip等编码通道做出更丰富的可视化。
1. circle 标记是什么
Altair 官方文档在 circle.rst 中开宗明义地定义:
circle标记与point标记相似,区别在于:(1)shape的值永远被固定为circle;(2) 默认情况下它们是填充(filled)的。
这句话点出了circle的本质——它是point的一种“特化形式”。散点图中最常见的用法就是把一个数据点画成一个实心圆点,这正是circle标记的定位。
与它形成对照的是 point.rst 中描述的point标记:
默认情况下,
point标记只有边框、内部是透明的;可以通过设置filled=True来创建填充的点。
也就是说:
| 对比项 | point标记 | circle标记 |
|---|---|---|
| shape 取值 | 可自由指定(circle、square、cross、diamond、triangle 等) | 固定为circle |
| 默认填充 | 不填充(仅描边) | 填充 |
| 典型用途 | 需要形状编码或描边样式 | 通用散点图、地图上的地理点 |
这一默认行为在 Vega-Lite 模式定义中也有据可查。core.py 中对filled属性写道:
默认值为:
point、line、rule标记以及 graticule 数据源的geoshape标记为false;其余情况为true。
circle不在此列,因此其filled默认值为true,即实心圆点。
2. circle 标记的属性体系
一个circle标记定义可以包含所有 标准标记属性(如color、opacity、stroke、tooltip等),外加以下这个专有属性:
2.1 专有属性:size
| 属性 | 类型 | 说明 |
|---|---|---|
size | 数值 / 表达式引用(ExprRef) | 标记的默认尺寸 |
size的确切语义在源码的MarkDef模式定义(core.py)中有详细注释:
对于
point/circle/square,size表示标记的像素面积。注意该值设置的是符号的面积,其边长会随该值的平方根增长。 对于bar,它表示条带的像素宽度;对于text,它表示字体大小(像素)。
这是一个容易踩坑的细节:size不是“半径”也不是“直径”,而是面积。若想让圆点看起来大一倍,需要把size乘以 4(面积增大为 4 倍、直径才增大为 2 倍),而不是乘以 2。由于面积与边长是平方根关系,size的数值跨度往往较大(常见取值从几到几百)。
2.2 标准标记属性
除size外,circle同样支持MarkDef中定义的标准属性,例如(依据 core.py 的 MarkDef 文档):
color:默认填充颜色,默认值"#4682b4";fill/stroke的优先级高于color;opacity:整体透明度;fillOpacity:填充透明度,默认1;stroke/strokeWidth/strokeOpacity:描边颜色与宽度;tooltip:是否显示提示信息(可传True或字段定义);cursor、href、aria等辅助属性。
这些属性既可以作为关键字参数直接传入mark_circle(),也可以在encode()中映射到数据字段,实现按数据取值动态变化。
3. 源码级解析:mark_circle 是如何实现的
mark_circle()是Chart对象上的方法,定义在 mixins.py:
@use_signature(_MarkDef) def mark_circle(self, **kwds: Any) -> Self: """Set the chart's mark to 'circle' (see :class:`MarkDef`).""" copy = self.copy(deep=False) # type: ignore if any(val is not Undefined for val in kwds.values()): copy.mark = core.MarkDef(type="circle", **kwds) else: copy.mark = "circle" return copy从源码可以看到两条实现事实:
- 浅拷贝非原地修改:方法返回的是当前图表对象的一份浅拷贝(
self.copy(deep=False)),并在这份拷贝上设置mark,因此不会污染原图表对象,也支持链式调用。 - 两种底层表示:
- 当没有传入任何标记属性(如
mark_circle())时,mark被设置为字符串"circle"——Vega-Lite 的最简简写形式; - 当传入了任意属性(如
mark_circle(size=50))时,mark被构造为core.MarkDef(type="circle", **kwds)模式定义对象。
- 当没有传入任何标记属性(如
也就是说,mark_circle(size=50, color="steelblue")最终会被序列化为{"mark": {"type": "circle", "size": 50, "color": "steelblue"}}这样的 Vega-Lite 规范。这种“无参用简写、有参用 MarkDef”的设计,保证了生成规范的精简与可读。
顺带一提,mark_circle与mark_point、mark_square等共享同一套_MarkDef签名机制(@use_signature(_MarkDef)),因此 IDE 中会得到完整的参数提示,类型上则统一走 core.py 的MarkDef模式包装类。
4. 实战:用 circle 标记绘制散点图
原文档给出的最小可运行示例是汽车数据集上的散点图。为了与原文档保持一致且保证可复现,建议使用当前仓库的 datasets 接口获取数据 URL:
import altair as alt from altair.datasets import data source = data.cars.url alt.Chart(source).mark_circle().encode( x=("Horsepower:Q"), y=("Miles_per_Gallon:Q"), )代码要点说明:
data.cars.url返回cars数据集的远程 URL(字符串),无需本地文件;当前仓库的 datasets 模块(altair/datasets/init.py)支持data.cars()直接加载为 DataFrame、data.cars.url获取地址,并可指定engine="polars"/"pandas"/"pyarrow"等后端;x与y使用带类型后缀的简写字段描述"Horsepower:Q"(Q 表示定量/连续数据)与"Miles_per_Gallon:Q";mark_circle()不传任何参数,此时底层mark会被简写为字符串"circle"。
运行后即可得到一张“马力(Horsepower)对每加仑英里数(Miles_per_Gallon)”的散点图,每个观测点渲染为一个默认填充的实心圆点。
4.1 指定 size 属性
若想控制圆点大小,直接传入size(像素面积):
alt.Chart(source).mark_circle(size=100).encode( x="Horsepower:Q", y="Miles_per_Gallon:Q", )仓库测试中也有同样的用法,例如 deviation_ellipses.py 中的mark_circle(size=50, tooltip=True)。
4.2 结合 size 通道绘制气泡图
把第三个字段映射到size编码通道,散点图就升级为气泡图:
alt.Chart(source).mark_circle().encode( x="Horsepower:Q", y="Miles_per_Gallon:Q", size="Acceleration:Q", )此时圆点面积随Acceleration字段取值连续变化,这与mark_circle(size=100)的固定尺寸不同:前者是数据驱动的编码通道,后者是标记的固定默认值。仓库中的 gapminder_bubble_plot.py 正是这类气泡图的完整范例。
4.3 叠加颜色与透明度
circle支持所有标准标记属性,例如按分类字段着色、设置透明度以便观察重叠点:
alt.Chart(source).mark_circle(opacity=0.6).encode( x="Horsepower:Q", y="Miles_per_Gallon:Q", color="Origin:N", )其中opacity=0.6作为标记属性固定透明度,color="Origin:N"将产地(名义型字段)映射为颜色。在点密度高的散点图中,适度降低透明度能有效缓解点与点的遮挡问题;仓库示例 interval_selection_map_quakes.py 就使用了mark_circle(opacity=0.35, tooltip=True)。
5. circle 与 point、square 的取舍
- circle vs point:需要保持圆形、且想要默认填充时优先用
circle;需要给不同类别分配不同形状(如正方形、三角形、菱形)时,必须用point并映射shape通道(参考 point.rst 中的形状列表)。 - circle vs square:二者是“同构”关系——都固定形状、默认填充,唯一区别是几何形状本身。mixins.py 中
mark_square与mark_circle的实现完全对称,均按“无参简写字符串、有参构造 MarkDef”的规则生成。选择依据纯粹是视觉语义。
6. 延伸:circle 在地理可视化中的典型应用
由于circle固定为圆形且默认填充,它常被用来渲染地理点。在 point.rst 的 Geo Point 示例中,mark_circle配合longitude/latitude通道与投影即可在地图上标出机场位置:
import altair as alt from altair.datasets import data airports = data.airports() states = alt.topo_feature(data.us_10m.url, feature="states") background = alt.Chart(states).mark_geoshape( fill="lightgray", stroke="white" ).properties(width=500, height=300).project("albersUsa") points = alt.Chart(airports).mark_circle( size=10, color="steelblue", ).encode( longitude="longitude:Q", latitude="latitude:Q", tooltip=["name", "city", "state"], ) background + points这里mark_circle(size=10, color="steelblue")固定了圆点面积与颜色,tooltip展示机场信息,background + points则利用图层叠加把圆点绘制在美国州界底图之上。仓库中的 airport_connections.py 与 groupby-map.py 也展示了mark_circle在地理/分组地图中的更多组合方式。
7. 小结
circle是point的特化:shape固定为circle,默认填充,适合散点图与地理点图;- 专有属性
size表示像素面积而非半径,调整视觉大小需按平方关系换算; mark_circle()无参时生成简写字符串"circle",有参时构造MarkDef(type="circle", **kwds)(见 mixins.py);- 通过
size/color/opacity/tooltip等编码通道,可将散点图扩展为气泡图、着色散点图与交互式地图点层,仓库 tests/examples_arguments_syntax 目录下有大量可直接借鉴的完整示例。
若需进一步了解标记属性的完整清单,可查阅 marks 索引文档 与 core.py 中MarkDef的完整参数文档。
- 数据可视化
【免费下载链接】altair
Declarative visualization library for Python
相关推荐
Lucide React 图标尺寸调整完全指南:size 属性、CSS 与 Tailwind 实战
Lucide React 图标尺寸调整完全指南:size 属性、CSS 与 Tailwind 实战 本篇指南聚焦 Lucide 官方 React 图标库 luc
文档教程Lucide Solid 图标尺寸控制完全指南:size 属性与 CSS 缩放实战
Lucide Solid 图标尺寸控制完全指南:size 属性与 CSS 缩放实战 本文面向使用 Solid 框架的开发者,系统讲解 Lucide 图标库(So
前端UI组件设计系统Bokeh 散点图(Scatter Plots)完全指南:内置标记、自定义标记与图像标记
Bokeh 散点图(Scatter Plots)完全指南:内置标记、自定义标记与图像标记 导读 散点图是数据可视化中最基础也最常用的图形之一。Bokeh 提供了
数据可视化图表库
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考