线图#

line 标记表示存储在字段中的数据点,并用一条线连接所有这些点。线标记通常用于描绘轨迹或随时间的变化。与大多数表示每个标记一个数据元素的其他标记不同,一个线标记将多个数据元素表示为一条单独的线,类似于areatrail

注意:对于连接 (x,y) 位置到 (x2,y2) 位置的线段,请使用rule标记。对于大小连续变化的线条,请使用trail标记。

线标记属性#

点击显示代码
import altair as alt
import pandas as pd

interpolate_select = alt.binding_select(
    options=[
        "basis",
        "basis-open",
        "basis-closed",
        "bundle",
        "cardinal",
        "cardinal-open",
        "cardinal-closed",
        "catmull-rom",
        "linear",
        "linear-closed",
        "monotone",
        "natural",
        "step",
        "step-before",
        "step-after",
    ],
    name="interpolate",
)
interpolate_var = alt.param(bind=interpolate_select, value="linear")

tension_slider = alt.binding_range(min=0, max=1, step=0.05, name="tension")
tension_var = alt.param(bind=tension_slider, value=0)

strokeWidth_slider = alt.binding_range(min=0, max=10, step=0.5, name="strokeWidth")
strokeWidth_var = alt.param(bind=strokeWidth_slider, value=2)

strokeCap_select = alt.binding_select(
    options=["butt", "round", "square"],
    name="strokeCap",
)
strokeCap_var = alt.param(bind=strokeCap_select, value="butt")

strokeDash_select = alt.binding_select(
    options=[[1, 0], [8, 8], [8, 4], [4, 4], [4, 2], [2, 1], [1, 1]],
    name="strokeDash",
)
strokeDash_var = alt.param(bind=strokeDash_select, value=[1, 0])

source = pd.DataFrame({"u": [1, 2, 3, 4, 5, 6], "v": [28, 55, 42, 34, 36, 38]})

alt.Chart(source).mark_line(
    interpolate=interpolate_var,
    tension=tension_var,
    strokeWidth=strokeWidth_var,
    strokeCap=strokeCap_var,
    strokeDash=strokeDash_var,
).encode(x="u", y="v").add_params(
    interpolate_var, tension_var, strokeWidth_var, strokeCap_var, strokeDash_var
)

一个line标记定义可以包含任何标准标记属性以及以下线条插值和点覆盖属性

点击显示表格

属性

类型

描述

orient

方向

非堆叠条形图、刻度图、面积图和线图的方向。取值为 horizontal(水平,默认)或 vertical(垂直)。

  • 对于 bar、rule 和 tick,这决定了条形和刻度的大小应应用于 x 维度还是 y 维度。

  • 对于 area,此属性决定了 Vega 输出的 orient 属性。

  • 对于 line 和 trail 标记,如果未指定config.sortLineBy,此属性决定了线条中点的排序顺序。对于堆叠图表,这始终由堆叠的方向决定;因此,明确指定的值将被忽略。

interpolate

anyOf(Interpolate, ExprRef)

用于线和面积标记的线条插值方法。以下之一

  • "linear":分段线性段,如折线。

  • "linear-closed":闭合线性段形成多边形。

  • "step":在水平和垂直线段之间交替,如阶梯函数。

  • "step-before":在垂直和水平线段之间交替,如阶梯函数。

  • "step-after":在水平和垂直线段之间交替,如阶梯函数。

  • "basis":B样条,末端控制点重复。

  • "basis-open":开放B样条;可能不与起点或终点相交。

  • "basis-closed":闭合B样条,如循环。

  • "cardinal":Cardinal样条,末端控制点重复。

  • "cardinal-open":开放Cardinal样条;可能不与起点或终点相交,但会与其他控制点相交。

  • "cardinal-closed":闭合Cardinal样条,如循环。

  • "bundle":相当于 basis,只是使用张力参数来拉直样条。

  • "monotone":保持 y 单调性的三次插值。

tension

anyOf(number, ExprRef)

根据插值类型,设置张力参数(用于线和面积标记)。

point

anyOf(boolean, OverlayMarkDef, string)

一个标志,用于在线或面积标记之上叠加点,或者一个定义叠加点属性的对象。

  • 如果此属性为"transparent",将使用透明点(用于增强工具提示和选择)。

  • 如果此属性为空对象({})或true,将使用具有默认属性的实心点。

  • 如果此属性为false,则不会自动在线或面积标记中添加点。

**默认值:** false

示例#

线图#

使用一个时间或顺序字段(通常在x轴上)和另一个定量字段(通常在y轴上)与 line 标记结合,可以生成一个简单的单线条图。

import altair as alt
from altair import datum
from vega_datasets import data


source = data.stocks()

alt.Chart(source).mark_line().encode(
    x="date",
    y="price",
).transform_filter(datum.symbol == "GOOG")

我们可以通过沿着不同的属性(如colordetail)进行分组来创建多条线。

多系列彩色线图#

将一个字段添加到标记属性通道(如color)可以将数据点分组到不同的系列中,生成多系列彩色线图。

import altair as alt
from vega_datasets import data

source = data.stocks()

alt.Chart(source).mark_line().encode(
    x="date",
    y="price",
    color="symbol",
)

我们可以进一步应用选择,以便在悬停时突出显示某条线。

import altair as alt
from vega_datasets import data

source = data.stocks()

highlight = alt.selection_point(
    on="pointerover", fields=["symbol"], nearest=True
)

base = alt.Chart(source).encode(
    x="date:T",
    y="price:Q",
    color="symbol:N"
)

points = base.mark_circle().encode(
    opacity=alt.value(0)
).add_params(
    highlight
).properties(
    width=600
)

lines = base.mark_line().encode(
    size=alt.when(~highlight).then(alt.value(1)).otherwise(alt.value(3))
)

points + lines

使用不同虚线的的多系列线图#

将一个字段添加到strokeDash也会生成多系列线图。

import altair as alt
from vega_datasets import data

source = data.stocks()

alt.Chart(source).mark_line().encode(
    x="date",
    y="price",
    strokeDash="symbol",
)

我们还可以使用线条分组来创建具有不同样式部分的线图。

import altair as alt
import pandas as pd

source = pd.DataFrame({
    "a": ["A", "B", "D", "E", "E", "G", "H"],
    "b": [28, 55, 91, 81, 81, 19, 87],
    "predicted": [False, False, False, False, True, True, True]
})

alt.Chart(source).mark_line().encode(
    x="a:O",
    y="b:Q",
    strokeDash="predicted:N"
)

使用 Detail 通道的多系列线图#

为了通过一个字段对线条进行分组,而无需将该字段映射到任何视觉属性,我们可以将该字段映射到detail通道,以创建具有相同颜色的多系列线图。

import altair as alt
from vega_datasets import data

source = data.stocks()

alt.Chart(source).mark_line().encode(
    x="date",
    y="price",
    detail="symbol",
)

同样的方法可用于为范围点图分组线条。

import altair as alt
from vega_datasets import data

source = data.countries()

base = alt.Chart(source).encode(
    alt.X("life_expect:Q")
        .scale(zero=False)
        .title("Life Expectancy (years)"),
    alt.Y("country:N")
        .axis(offset=5, ticks=False, minExtent=70, domain=False)
        .title("Country")
).transform_filter(
    alt.FieldOneOfPredicate(field="country", oneOf=["China", "India", "United States", "Indonesia", "Brazil"])
)


line = base.mark_line().encode(
    detail="country",
    color=alt.value("#db646f")
).transform_filter(
    alt.FieldOneOfPredicate(field="year", oneOf=[1995, 2000])
)

point = base.mark_point(filled=True).encode(
    alt.Color("year").scale(range=["#e6959c", "#911a24"], domain=[1995, 2000]),
    size=alt.value(100),
    opacity=alt.value(1),
)

line + point

带有标记点的线图#

通过将标记定义的point属性设置为True或定义叠加点标记属性的对象,我们可以在线条上方叠加点标记。

import altair as alt
from vega_datasets import data

source = data.stocks()

alt.Chart(source).mark_line(point=True).encode(
    x="year(date)",
    y="mean(price):Q",
    color="symbol:N"
)

这等同于添加另一层实心点标记。

请注意,叠加点标记默认为opacity = 1(而不是像普通点标记那样半透明)。

这里我们通过将filled设置为False并将fill设置为"white"来创建带描边的点。

import altair as alt
from vega_datasets import data

source = data.stocks()

alt.Chart(source).mark_line(
    point=alt.OverlayMarkDef(filled=False, fill="white")
).encode(
    x="year(date)",
    y="mean(price):Q",
    color="symbol:N"
)

自定义排序#

默认情况下,线的路径(线中点的顺序)由时间/顺序字段上的数据值决定。但是,可以将一个字段映射到order通道来确定自定义路径。

例如,为了显示汽油价格和人均行驶里程随时间的数据变化模式,我们使用order通道按年份字段对线条中的点进行排序。在此示例中,我们还使用point属性在线条标记上叠加点标记,以突出显示每个数据点。现在,最早的数据点(1956)是线条的一个端点,而最新的数据点(2010)是线条的另一个端点。

import altair as alt
from vega_datasets import data

source = data.driving()

alt.Chart(source).mark_line(point=True).encode(
    alt.X("miles").scale(zero=False),
    alt.Y("gas").scale(zero=False),
    order="year",
    tooltip=["miles", "gas", "year"],
)

线条插值#

标记定义的interpolate属性可用于更改线条插值方法。例如,我们可以将interpolate设置为"monotone"

import altair as alt
from vega_datasets import data

source = data.stocks()

alt.Chart(source).mark_line(interpolate="monotone").encode(
    x="date",
    y="price",
).transform_filter(
    alt.datum.symbol == "GOOG"
)

我们还可以将interpolate设置为"step-after"来创建阶梯图。

import altair as alt
from vega_datasets import data

source = data.stocks()

alt.Chart(source).mark_line(interpolate="step-after").encode(
    x="date",
    y="price"
).transform_filter(
    alt.datum.symbol == "GOOG"
)

地理线图#

通过将地理坐标数据映射到相应投影的longitudelatitude通道,我们可以绘制穿过地理点的线条。

import altair as alt
from vega_datasets import data
import pandas as pd

airports = data.airports.url
flights_airport = data.flights_airport.url

states = alt.topo_feature(data.us_10m.url, feature="states")

lookup_data = alt.LookupData(
    airports, key="iata", fields=["state", "latitude", "longitude"]
)

source = pd.DataFrame({
    "airport": ["SEA", "SFO", "LAX", "LAS", "DFW", "DEN", "ORD", "JFK"],
    "order": [1, 2, 3, 4, 5, 6, 7, 8],
})

background = alt.Chart(states).mark_geoshape(
    fill="lightgray",
    stroke="white"
).properties(
    width=750,
    height=500,
).project("albersUsa")

line = alt.Chart(source).mark_line().encode(
    latitude="latitude:Q",
    longitude="longitude:Q",
    order="order"
).transform_lookup(
    lookup="airport",
    from_=lookup_data
)

background + line