Фильтрация — Filter

Преобразование filter удаляет объекты из потока данных на основании выражения фильтра, выбора или другого предиката. Добавить фильтр на верхнем уровне диаграммы можно методом Chart.transform_filter. Его аргументом может быть:

  1. Выражение Vega в виде строки или выражение, построенное с помощью модуля expr.
  2. Предикат поля, например FieldOneOfPredicate, FieldRangePredicate, FieldEqualPredicate, FieldLTPredicate, FieldGTPredicate, FieldLTEPredicate или FieldGTEPredicate.
  3. Предикат выбора или объект, созданный функцией selection.
  4. Логическая операция, объединяющая перечисленные варианты.

Ниже приведены краткие примеры каждого подхода.

Выражение фильтра

Выражение фильтра использует язык выражений Vega: его можно задать строкой или построить с помощью модуля expr. Это удобно, например, для выбора подмножества данных:

import altair as alt
from altair import datum

from altair.datasets import data
pop = data.population.url

alt.Chart(pop).mark_area().encode(
    x='age:O',
    y='people:Q',
).transform_filter(
    (datum.year == 2000) & (datum.sex == 1)
)

Значения данных, как и в других примерах фильтрации, доступны через имя datum.

Предикаты полей

По возможностям предикаты полей частично пересекаются с выражениями. Их преимущество — проверка содержимого по схеме. Например:

  • FieldEqualPredicate проверяет равенство значения поля заданному значению.
  • FieldOneOfPredicate проверяет, входит ли значение поля в указанный список.
  • FieldRangePredicate проверяет, находится ли непрерывное значение поля в заданном диапазоне.
  • FieldLTPredicate проверяет, меньше ли непрерывное значение поля заданного значения.
  • FieldGTPredicate проверяет, больше ли непрерывное значение поля заданного значения.
  • FieldLTEPredicate проверяет, меньше ли непрерывное значение поля заданного значения или равно ему.
  • FieldGTEPredicate проверяет, больше ли непрерывное значение поля заданного значения или равно ему.

Вот пример FieldEqualPredicate, который выбирает только значения за 2000 год, как на предыдущей диаграмме:

import altair as alt
from altair.datasets import data
pop = data.population.url

alt.Chart(pop).mark_line().encode(
    x='age:O',
    y='sum(people):Q',
    color='year:O'
).transform_filter(
    alt.FieldEqualPredicate(field='year', equal=2000)
)

FieldOneOfPredicate действует похоже, но позволяет выбрать несколько конкретных значений:

import altair as alt
from altair.datasets import data
pop = data.population.url

alt.Chart(pop).mark_line().encode(
    x='age:O',
    y='sum(people):Q',
    color='year:O'
).transform_filter(
    alt.FieldOneOfPredicate(field='year', oneOf=[1900, 1950, 2000])
)

Наконец, FieldRangePredicate выбирает значения внутри заданного непрерывного диапазона:

import altair as alt
from altair.datasets import data
pop = data.population.url

alt.Chart(pop).mark_line().encode(
    x='age:O',
    y='sum(people):Q',
    color='year:O'
).transform_filter(
    alt.FieldRangePredicate(field='year', range=[1960, 2000])
)

Предикаты выбора

Предикаты выбора фильтруют данные на основании выбора. Их можно создавать напрямую с помощью класса SelectionPredicate, но в Altair обычно удобнее использовать функцию selection. В этом примере множественный выбор позволяет щёлкать по столбцам нижней диаграммы, в том числе с удержанием Shift, чтобы выбрать данные для верхней диаграммы:

import altair as alt
from altair.datasets import data
pop = data.population.url

selection = alt.selection_point(fields=['year'])

top = alt.Chart(width=600, height=200).mark_line().encode(
    x="age:O",
    y="sum(people):Q",
    color="year:O"
).transform_filter(
    selection
)

color = alt.when(selection).then(alt.value("steelblue")).otherwise(alt.value("lightgray"))
bottom = alt.Chart(width=600, height=100).mark_bar().encode(
    x="year:O",
    y="sum(people):Q",
    color=color
).add_params(
    selection
)

alt.vconcat(top, bottom, data=pop)

Логические операции

Иногда нужно объединить несколько видов предикатов. Для логической композиции используются &, | и ~: соответственно AND, OR и NOT.

Например, построим распределение населения США для всех лет, кроме 1950–1960.

Сначала зададим FieldRangePredicate, выбирающий 1950–1960:

import altair as alt
from altair.datasets import data

source = data.population.url
chart = alt.Chart(source).mark_line().encode(
    x="age:O",
    y="sum(people):Q",
    color="year:O"
).properties(
    width=600, height=200
)

between_1950_60 = alt.FieldRangePredicate(field="year", range=[1950, 1960])

Затем инвертируем условие с помощью ~:

# NOT between 1950-1960
chart.transform_filter(~between_1950_60)

Можно уточнить фильтр, объединяя несколько предикатов. Здесь используется datum:

chart.transform_filter(~between_1950_60 & (datum.age <= 70))

Если передать несколько предикатов, они объединяются через &:

chart.transform_filter(datum.year > 1980, datum.age != 90)

Именованные ограничения constraints упрощают первый пример из раздела «Выражение фильтра»:

alt.Chart(source).mark_area().encode(
    x="age:O",
    y="people:Q",
).transform_filter(year=2000, sex=1)

Параметры преобразования

Метод Chart.transform_filter основан на классе FilterTransform, который поддерживает следующие параметры:

Нажмите, чтобы показать таблицу
СвойствоТипОписание
filterPredicateComposition

Свойство filter задаёт предикат в одной из следующих форм:

  1. Строка с выражением, где datum обозначает текущий объект данных. Например, {filter: "datum.b2 > 60"} оставляет только записи, в которых значение b2 больше 60.
  2. Один из предикатов полей: equal, lt, lte, gt, gte, range, oneOf или valid.
  3. Предикат выбора, задающий имя выбора, которому должна принадлежать точка данных, либо логическую композицию выборов.
  4. Логическая композиция перечисленных вариантов.