Теперь, когда мы познакомились с основными частями API Altair (см. часть 1 и часть 2), пришло время попрактиковаться в его использовании для изучения нового набора данных.
Выберите один из следующих четырех наборов данных, подробно описанных ниже.
Изучая данные, вспомните о строительных блоках, которые мы обсуждали ранее:
mark_point()
, mark_line()
, mark_tick()
, mark_bar()
, mark_area()
, mark_rect()
и т. д.x
, y
, color
, shape
, size
, row
, column
, text
, tooltip
и т. д.alt.layer
<-> +
, alt.hconcat
<-> |
, alt.vconcat
<-> &
)Начните с простого. Какие кодировки лучше всего работают с количественными данными? С категориальными данными? Что вы можете узнать о своем наборе данных с помощью этих инструментов?
from vega_datasets import data
Эти данные включают суточные осадки (daily precipitation), диапазон температур (temperature range), скорость ветра (wind speed) и тип погоды в зависимости от даты в период с 2012
по 2015
год в Сиэтле.
weather = data.seattle_weather()
weather.head()
date | precipitation | temp_max | temp_min | wind | weather | |
---|---|---|---|---|---|---|
0 | 2012-01-01 | 0.0 | 12.8 | 5.0 | 4.7 | drizzle |
1 | 2012-01-02 | 10.9 | 10.6 | 2.8 | 4.5 | rain |
2 | 2012-01-03 | 0.8 | 11.7 | 7.2 | 2.3 | rain |
3 | 2012-01-04 | 20.3 | 12.2 | 5.6 | 4.7 | rain |
4 | 2012-01-05 | 1.3 | 8.9 | 2.8 | 6.1 | rain |
Эти данные включают численность населения (population), рождаемости (fertility) и ожидаемой продолжительности жизни в ряде стран мира.
Обратите внимание: хотя у вас может возникнуть соблазн использовать временное кодирование для года, здесь год - это просто число, а не отметка даты, поэтому временное кодирование здесь не лучший выбор.
gapminder = data.gapminder()
gapminder.head()
year | country | cluster | pop | life_expect | fertility | |
---|---|---|---|---|---|---|
0 | 1955 | Afghanistan | 0 | 8891209 | 30.332 | 7.7 |
1 | 1960 | Afghanistan | 0 | 9829450 | 31.997 | 7.7 |
2 | 1965 | Afghanistan | 0 | 10997885 | 34.020 | 7.7 |
3 | 1970 | Afghanistan | 0 | 12430623 | 36.088 | 7.7 |
4 | 1975 | Afghanistan | 0 | 14132019 | 38.438 | 7.7 |
Эти данные содержат информацию о населении США, разделенное по возрасту и полу каждое десятилетие с 1850
года до настоящего времени.
Обратите внимание: хотя у вас может возникнуть соблазн использовать временное кодирование для года, здесь год - это просто число, а не отметка даты, и поэтому временное кодирование - не лучший выбор.
population = data.population()
population.head()
year | age | sex | people | |
---|---|---|---|---|
0 | 1850 | 0 | 1 | 1483789 |
1 | 1850 | 0 | 2 | 1450376 |
2 | 1850 | 5 | 1 | 1411067 |
3 | 1850 | 5 | 2 | 1359668 |
4 | 1850 | 10 | 1 | 1260099 |
Набор данных фильмов содержит данные о 3200
фильмах, включая дату выпуска, бюджет и рейтинги IMDB и Rotten Tomatoes.
movies = data.movies()
movies.head()
Title | US Gross | Worldwide Gross | US DVD Sales | Production Budget | Release Date | MPAA Rating | Running Time min | Distributor | Source | Major Genre | Creative Type | Director | Rotten Tomatoes Rating | IMDB Rating | IMDB Votes | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | The Land Girls | 146083.0 | 146083.0 | NaN | 8000000.0 | Jun 12 1998 | R | NaN | Gramercy | None | None | None | None | NaN | 6.1 | 1071.0 |
1 | First Love, Last Rites | 10876.0 | 10876.0 | NaN | 300000.0 | Aug 07 1998 | R | NaN | Strand | None | Drama | None | None | NaN | 6.9 | 207.0 |
2 | I Married a Strange Person | 203134.0 | 203134.0 | NaN | 250000.0 | Aug 28 1998 | None | NaN | Lionsgate | None | Comedy | None | None | NaN | 6.8 | 865.0 |
3 | Let's Talk About Sex | 373615.0 | 373615.0 | NaN | 300000.0 | Sep 11 1998 | None | NaN | Fine Line | None | Comedy | None | None | 13.0 | NaN | NaN |
4 | Slam | 1009819.0 | 1087521.0 | NaN | 1000000.0 | Oct 09 1998 | R | NaN | Trimark | Original Screenplay | Drama | Contemporary Fiction | None | 62.0 | 3.4 | 165.0 |
Интерактивность и грамматика выбора Altair - одна из его уникальных особенностей среди доступных графических библиотек. В этом разделе мы рассмотрим различные доступные типы выбора и начнем практиковаться в создании интерактивных диаграмм и информационных панелей (dashboards).
Доступны три основных типа выбора:
alt.selection_interval()
alt.selection_single()
alt.selection_multi()
И расскажем о четырех основных вещах, которые вы можете делать с этими выборками.
import altair as alt
from vega_datasets import data
Основные взаимодействия, которые предоставляет Altair, - это панорамирование (panning), масштабирование (zooming) и всплывающие подсказки (tooltips). Это можно сделать на диаграмме без использования интерфейса выбора, используя метод interactive()
и кодировку tooltip
.
Например, с нашим стандартным набором данных про автомобили мы можем сделать следующее:
cars = data.cars()
cars.head()
Name | Miles_per_Gallon | Cylinders | Displacement | Horsepower | Weight_in_lbs | Acceleration | Year | Origin | |
---|---|---|---|---|---|---|---|---|---|
0 | chevrolet chevelle malibu | 18.0 | 8 | 307.0 | 130.0 | 3504 | 12.0 | 1970-01-01 | USA |
1 | buick skylark 320 | 15.0 | 8 | 350.0 | 165.0 | 3693 | 11.5 | 1970-01-01 | USA |
2 | plymouth satellite | 18.0 | 8 | 318.0 | 150.0 | 3436 | 11.0 | 1970-01-01 | USA |
3 | amc rebel sst | 16.0 | 8 | 304.0 | 150.0 | 3433 | 12.0 | 1970-01-01 | USA |
4 | ford torino | 17.0 | 8 | 302.0 | 140.0 | 3449 | 10.5 | 1970-01-01 | USA |
alt.Chart(cars).mark_point().encode(
x='Horsepower:Q',
y='Miles_per_Gallon:Q',
color='Origin',
tooltip='Name'
).interactive()
В этот момент при наведении курсора на точку появится всплывающая подсказка с названием модели автомобиля, а нажатие/перетаскивание/прокрутка приведет к панорамированию и масштабированию графика.
В качестве примера выбора (selection) давайте добавим интервальное выделение на график.
Начнем с классического графика рассеяния (scatter plot):
cars = data.cars()
cars.head()
Name | Miles_per_Gallon | Cylinders | Displacement | Horsepower | Weight_in_lbs | Acceleration | Year | Origin | |
---|---|---|---|---|---|---|---|---|---|
0 | chevrolet chevelle malibu | 18.0 | 8 | 307.0 | 130.0 | 3504 | 12.0 | 1970-01-01 | USA |
1 | buick skylark 320 | 15.0 | 8 | 350.0 | 165.0 | 3693 | 11.5 | 1970-01-01 | USA |
2 | plymouth satellite | 18.0 | 8 | 318.0 | 150.0 | 3436 | 11.0 | 1970-01-01 | USA |
3 | amc rebel sst | 16.0 | 8 | 304.0 | 150.0 | 3433 | 12.0 | 1970-01-01 | USA |
4 | ford torino | 17.0 | 8 | 302.0 | 140.0 | 3449 | 10.5 | 1970-01-01 | USA |
alt.Chart(cars).mark_point().encode(
x='Horsepower:Q',
y='Miles_per_Gallon:Q',
color='Origin'
)
Чтобы добавить поведение выбора к диаграмме, мы создаем объект выбора и используем метод add_selection
:
interval = alt.selection_interval()
alt.Chart(cars).mark_point().encode(
x='Horsepower:Q',
y='Miles_per_Gallon:Q',
color='Origin'
).add_selection(
interval
)
Это добавляет к графику взаимодействие, которое позволяет выбирать точки на графике; возможно, наиболее распространенное использование выделения - это выделение точек путем определения их цвета в зависимости от результата выбора.
Это можно сделать с помощью alt.condition
:
interval = alt.selection_interval()
alt.Chart(cars).mark_point().encode(
x='Horsepower:Q',
y='Miles_per_Gallon:Q',
color=alt.condition(interval, 'Origin', alt.value('lightgray'))
).add_selection(
interval
)
Функция alt.condition
принимает три аргумента: объект выбора, значение, которое будет применяться к точкам внутри выделения, и значение, которое будет применено к точкам вне выделения. Здесь мы используем alt.value('lightgray')
, чтобы убедиться, что цвет обрабатывается как фактический цвет, а не как имя столбца данных.
Функция alt.selection_interval()
принимает ряд дополнительных аргументов; например, задавая encodings
, мы можем контролировать, охватывает ли выделение x
, y
или обе оси:
interval = alt.selection_interval(encodings=['x'])
alt.Chart(cars).mark_point().encode(
x='Horsepower:Q',
y='Miles_per_Gallon:Q',
color=alt.condition(interval, 'Origin', alt.value('lightgray'))
).add_selection(
interval
)
interval = alt.selection_interval(encodings=['y'])
alt.Chart(cars).mark_point().encode(
x='Horsepower:Q',
y='Miles_per_Gallon:Q',
color=alt.condition(interval, 'Origin', alt.value('lightgray'))
).add_selection(
interval
)
empty
(пустой) аргумент позволяет нам контролировать, будут ли пустые выделения содержать все значения или ни одно из значений; с empty='none'
точки по умолчанию неактивны:
interval = alt.selection_interval(empty='none')
alt.Chart(cars).mark_point().encode(
x='Horsepower:Q',
y='Miles_per_Gallon:Q',
color=alt.condition(interval, 'Origin', alt.value('lightgray'))
).add_selection(
interval
)
Функция alt.selection_single()
позволяет пользователю кликать на отдельные объекты диаграммы, чтобы выбрать их по одному. Мы сделаем точки немного больше, чтобы их было легче нажимать:
single = alt.selection_single()
alt.Chart(cars).mark_circle(size=100).encode(
x='Horsepower:Q',
y='Miles_per_Gallon:Q',
color=alt.condition(single, 'Origin', alt.value('lightgray'))
).add_selection(
single
)
Единичный выбор позволяет задать и другое поведение; например, мы можем установить nearest=True
и on='mouseover'
, чтобы обновлять выделение до ближайшей точки при перемещении мыши:
single = alt.selection_single(on='mouseover', nearest=True)
alt.Chart(cars).mark_circle(size=100).encode(
x='Horsepower:Q',
y='Miles_per_Gallon:Q',
color=alt.condition(single, 'Origin', alt.value('lightgray'))
).add_selection(
single
)
Функция alt.selection_multi()
очень похожа на функцию single
, за исключением того, что она позволяет выбрать несколько точек одновременно, удерживая клавишу Shift
:
multi = alt.selection_multi()
alt.Chart(cars).mark_circle(size=100).encode(
x='Horsepower:Q',
y='Miles_per_Gallon:Q',
color=alt.condition(multi, 'Origin', alt.value('lightgray'))
).add_selection(
multi
)
Такие опции, как on
и nearest
, также работают для множественного выбора:
multi = alt.selection_multi(on='mouseover', nearest=True)
alt.Chart(cars).mark_circle(size=100).encode(
x='Horsepower:Q',
y='Miles_per_Gallon:Q',
color=alt.condition(multi, 'Origin', alt.value('lightgray'))
).add_selection(
multi
)
Выше мы увидели, как alt.condition
можно использовать для привязки выделения к различным аспектам диаграммы. Давайте рассмотрим еще несколько способов использования выделения:
Для выбора интервала еще одна вещь, которую вы можете сделать с выделением, - это привязать область выбора к шкалам диаграммы:
bind = alt.selection_interval(bind='scales')
alt.Chart(cars).mark_circle(size=100).encode(
x='Horsepower:Q',
y='Miles_per_Gallon:Q',
color='Origin:N'
).add_selection(
bind
)
По сути, это то, что делает метод chart.interactive()
под капотом.
Также можно привязать шкалы к другим доменам (domain).
weather = data.seattle_weather()
weather.head()
date | precipitation | temp_max | temp_min | wind | weather | |
---|---|---|---|---|---|---|
0 | 2012-01-01 | 0.0 | 12.8 | 5.0 | 4.7 | drizzle |
1 | 2012-01-02 | 10.9 | 10.6 | 2.8 | 4.5 | rain |
2 | 2012-01-03 | 0.8 | 11.7 | 7.2 | 2.3 | rain |
3 | 2012-01-04 | 20.3 | 12.2 | 5.6 | 4.7 | rain |
4 | 2012-01-05 | 1.3 | 8.9 | 2.8 | 6.1 | rain |
base = alt.Chart(weather).mark_rule().encode(
x='date:T',
y='temp_min:Q',
y2='temp_max:Q',
color='weather:N'
)
base
chart = base.properties(
width=800,
height=300
)
view = chart.properties(
width=800,
height=50
)
chart & view
Давайте добавим выбор интервала к нижнему графику, который будет контролировать домен верхнего графика:
interval = alt.selection_interval(encodings=['x'])
base = alt.Chart(weather).mark_rule(size=2).encode(
x='date:T',
y='temp_min:Q',
y2='temp_max:Q',
color='weather:N'
)
chart = base.encode(
x=alt.X('date:T', scale=alt.Scale(domain=interval.ref()))
).properties(
width=800,
height=300
)
view = base.add_selection(
interval
).properties(
width=800,
height=50,
)
chart & view
В многопанельных диаграммах мы можем использовать результат выбора для фильтрации других представлений данных. Например, вот диаграмма рассеяния вместе с гистограммой:
interval = alt.selection_interval()
scatter = alt.Chart(cars).mark_point().encode(
x='Horsepower:Q',
y='Miles_per_Gallon:Q',
color=alt.condition(interval, 'Origin:N', alt.value('lightgray'))
).add_selection(
interval
)
hist = alt.Chart(cars).mark_bar().encode(
x='count()',
y='Origin',
color='Origin'
).transform_filter(
interval
)
scatter & hist
Точно так же вы можете использовать множественный выбор, чтобы пойти другим путем (разрешите кликнуть на гистограмму, чтобы отфильтровать содержимое диаграммы рассеяния.
Добавим эту возможность к предыдущей диаграмме:
click = alt.selection_multi(encodings=['color'])
scatter = alt.Chart(cars).mark_point().encode(
x='Horsepower:Q',
y='Miles_per_Gallon:Q',
color='Origin:N'
).transform_filter(
click
)
hist = alt.Chart(cars).mark_bar().encode(
x='count()',
y='Origin',
color=alt.condition(click, 'Origin', alt.value('lightgray'))
).add_selection(
click
)
scatter & hist
Типы выбора:
selection_interval()
selection_single()
selection_multi()
Привязки:
Теперь у вас есть возможность попробовать построить графики самостоятельно! Выберите один или несколько из следующих интерактивных примеров:
Используя данные об автомобилях, создайте диаграмму рассеяния (scatter-plot), на которой размер (size) точек становится больше при наведении на них курсора.
Используя данные об автомобилях, создайте двухпанельную (two-panel) гистограмму (скажем, количество миль на галлон на одной панели, количество лошадиных сил на другой), где вы можете перетащить мышь, чтобы выбрать данные на левой панели, чтобы отфильтровать данные на второй панели.
Измените приведенный выше пример диаграммы разброса и гистограммы, чтобы
Важным элементом конвейера визуализации является преобразование данных (data transformation).
С Altair у вас есть два возможных пути преобразования данных, а именно:
import altair as alt
В качестве примера рассмотрим преобразование входных данных о населении. В наборе данных перечислены агрегированные данные переписи США по годам, полу и возрасту, но пол указан как 1
и 2
, что делает надписи на диаграммах мало понятными:
from vega_datasets import data
population = data.population()
population.head()
year | age | sex | people | |
---|---|---|---|---|
0 | 1850 | 0 | 1 | 1483789 |
1 | 1850 | 0 | 2 | 1450376 |
2 | 1850 | 5 | 1 | 1411067 |
3 | 1850 | 5 | 2 | 1359668 |
4 | 1850 | 10 | 1 | 1260099 |
alt.Chart(population).mark_bar().encode(
x='year:O',
y='sum(people):Q',
color='sex:N'
)
Один из способов решить эту проблему с помощью Python - использовать инструменты Pandas для переназначения имен столбцов, например:
population['men_women'] = population['sex'].map({1: 'Men', 2: 'Women'})
alt.Chart(population).mark_bar().encode(
x='year:O',
y='sum(people):Q',
color='men_women:N'
)
Но Altair предназначен для использования с данными, доступными по URL, в которых такая предварительная обработка недоступна. В таких ситуациях лучше сделать преобразование частью спецификации графика.
Это можно сделать с помощью метода transform_calculate
, принимающего Vega-выражение, которое по сути представляет собой строку, которая может содержать небольшое подмножество операций JavaScript:
# отменить добавление столбца выше...
population = population.drop('men_women', axis=1)
alt.Chart(population).mark_bar().encode(
x='year:O',
y='sum(people):Q',
color='men_women:N'
).transform_calculate(
men_women='datum.sex == 1 ? "Men" : "Women"'
)
Одна потенциально сбивающая с толку часть - это наличие слова datum
: это просто соглашение, по которому Vega-выражения ссылаются на строку данных.
Если вы предпочитаете создавать эти выражения на Python, то Altair предоставляет для этого облегченный API:
from altair.expr import datum, if_
alt.Chart(population).mark_bar().encode(
x='year:O',
y='sum(people):Q',
color='men_women:N'
).transform_calculate(
men_women=if_(datum.sex == 1, "Men", "Women")
)
Преобразование фильтра аналогично. Например, предположим, что вы хотите создать диаграмму, состоящую только из мужского населения из записей переписи. Как и выше, это можно сделать в Pandas, но полезно, чтобы эта операция была доступна и в спецификации диаграммы. Это можно сделать с помощью метода transform_filter()
:
alt.Chart(population).mark_bar().encode(
x='year:O',
y='sum(people):Q',
).transform_filter(
datum.sex == 1
)
Мы уже встречали метод transform_filter
раньше, когда выполняли фильтрацию на основе результата выбора.
Доступны и другие методы преобразования, и хотя мы не будем их здесь демонстрировать, примеры можно найти в документации Altair Transform.
Altair предоставляет ряд полезных преобразований. Некоторые будут вам знакомы:
transform_aggregate()
transform_bin()
transform_timeunit()
Эти три преобразования приводят к созданию нового именованного значения, на которое можно ссылаться в нескольких местах на диаграмме.
Также существует множество других преобразований, таких как:
transform_lookup()
: позволяет выполнять одностороннее объединение нескольких наборов данных и часто используется, например, в географических визуализациях, где вы объединяете данные (например, безработица в пределах штатов) с данными о географических регионах, используемых для представления этих данных.transform_window()
: позволяет выполнять агрегирование по скользящим окнам, например, вычисляя локальные средние (local means) данных. Он был недавно добавлен в Vega-Lite, поэтому API Altair для этого преобразования пока не очень удобен.Посетите документацию по Transform для получения более полного списка.
Возьмем следующие данные:
import pandas as pd
import numpy as np
x = pd.DataFrame({'x': np.linspace(-5, 5)})
Создайте диаграмму на основе этих данных и постройте кривые синуса и косинуса с помощью transform_calculate
.
Используйте transform_filter
на этой диаграмме и удалите области графика, где значение кривой косинуса меньше значения кривой синуса.
Altair предоставляет несколько хуков для настройки внешнего вида диаграммы; у нас нет времени подробно описывать здесь все доступные параметры, но полезно знать, где и как можно получить доступ и изучить такие параметры.
Как правило, есть два или три места, где можно управлять видом диаграммы, каждое из которых имеет больший приоритет, чем предыдущее.
Конфигурация диаграммы верхнего уровня. На верхнем уровне диаграммы Altair вы можете указать параметры конфигурации, которые будут применяться к каждой панели или слою на диаграмме.
Параметры локальной конфигурации. Параметры верхнего уровня можно переопределить локально, указав локальную конфигурацию.
Значения кодирования. Если указано значение кодировки, оно будет иметь наивысший приоритет и переопределять другие параметры.
Посмотрим на пример.
import altair as alt
import numpy as np
import pandas as pd
np.random.seed(42)
data = pd.DataFrame(np.random.randn(100, 2), columns=['x', 'y'])
Предположим, вы хотите контролировать цвет маркеров на диаграмме рассеяния: давайте посмотрим на каждый из трех вариантов для этого. Мы будем использовать простые наборы данных нормально распределенных точек:
alt.Chart(data).mark_point().encode(
x='x:Q',
y='y:Q'
)
На верхнем уровне у Altair есть метод configure_mark()
, который позволяет настраивать большое количество параметров конфигурации для меток в целом, а также свойство configure_point()
, которое специально настраивает свойства точек.
Вы можете увидеть доступные параметры в строке документации Jupyter, доступ к которой осуществляется через вопросительный знак:
#alt.Chart.configure_point?
Эту конфигурацию верхнего уровня следует рассматривать как тему диаграммы: они являются настройками по умолчанию для эстетики всех элементов диаграммы. Давайте воспользуемся configure_point
, чтобы установить некоторые свойства точек:
alt.Chart(data).mark_point().encode(
x='x:Q',
y='y:Q'
).configure_point(
size=200,
color='red',
filled=True
)
Доступно множество локальных конфигураций; вы можете использовать функцию автозавершения табуляции и справочные функции Jupyter, чтобы изучить их
alt.Chart.configure_ # затем нажмите клавишу TAB, чтобы увидеть доступные конфигурации
В методе mark_point()
вы можете передавать локальные конфигурации, которые переопределяют параметры конфигурации верхнего уровня. Аргументы такие же, как у configure_mark
.
alt.Chart(data).mark_point(color='green', filled=False).encode(
x='x:Q',
y='y:Q'
).configure_point(
size=200,
color='red',
filled=True
)
Обратите внимание, что конфигурации color
и fill
переопределяются локальными конфигурациями, но size
остается таким же, как и раньше.
Наконец, самый высокий приоритет - это параметр encoding
. Здесь давайте установим цвет Steelblue
в кодировке:
alt.Chart(data).mark_point(color='green', filled=False).encode(
x='x:Q',
y='y:Q',
color=alt.value('steelblue')
).configure_point(
size=200,
color='red',
filled=True
)
Это немного надуманный пример, но он полезен, чтобы помочь понять различные места, в которых могут быть установлены свойства меток.
Названия диаграмм и осей устанавливаются автоматически в зависимости от источника данных, но иногда бывает полезно их изменить. Например, вот гистограмма приведенных выше данных:
alt.Chart(data).mark_bar().encode(
x=alt.X('x', bin=True),
y=alt.Y('count()')
)
Мы можем явно установить заголовки осей, используя аргумент title
для кодировки:
alt.Chart(data).mark_bar().encode(
x=alt.X('x', bin=True, title='binned x values'),
y=alt.Y('count()', title='counts in x')
)
Точно так же мы можем установить свойство title
диаграммы в свойствах диаграммы:
alt.Chart(data).mark_bar().encode(
x=alt.X('x', bin=True, title='binned x values'),
y=alt.Y('count()', title='counts in x')
).properties(
title='A histogram'
)
Если вы хотите установить свойства осей, включая линии сетки, вы можете использовать аргумент кодировки axis
.
alt.Chart(data).mark_bar().encode(
x=alt.X('x', bin=True, axis=alt.Axis(labelAngle=45)),
y=alt.Y('count()', axis=alt.Axis(labels=False, ticks=False, title=None))
)
Обратите внимание, что некоторые из этих значений также можно настроить в конфигурации верхнего уровня, если вы хотите, чтобы они применялись к диаграмме в целом. Например:
alt.Chart(data).mark_bar().encode(
x=alt.X('x', bin=True),
y=alt.Y('count()', axis=alt.Axis(labels=False, ticks=False, title=None))
).configure_axisX(
labelAngle=45
)
Каждая кодировка также имеет scale
(масштаб), который позволяет настраивать такие параметры, как пределы оси и другие свойства масштаба.
alt.Chart(data).mark_point().encode(
x=alt.X('x:Q', scale=alt.Scale(domain=[-5, 5])),
y=alt.Y('y:Q', scale=alt.Scale(domain=[-5, 5])),
)
Обратите внимание, что если вы уменьшите масштаб до меньшего размера, чем диапазон данных, данные по умолчанию будут выходить за пределы шкалы:
alt.Chart(data).mark_point().encode(
x=alt.X('x:Q', scale=alt.Scale(domain=[-3, 1])),
y=alt.Y('y:Q', scale=alt.Scale(domain=[-3, 1])),
)
Отсутствие скрытия данных - полезный вариант по умолчанию при исследовательской визуализации, поскольку он предотвращает непреднамеренное отсутствие точек данных.
Если вы хотите, чтобы маркеры были обрезаны за пределами диапазона шкал, вы можете установить свойство clip
для маркеров:
alt.Chart(data).mark_point(clip=True).encode(
x=alt.X('x:Q', scale=alt.Scale(domain=[-3, 1])),
y=alt.Y('y:Q', scale=alt.Scale(domain=[-3, 1])),
)
Другой полезный подход - вместо этого "зажимать" данные до крайних значений шкалы, сохраняя их видимыми, даже когда они находятся вне диапазона:
alt.Chart(data).mark_point().encode(
x=alt.X('x:Q', scale=alt.Scale(domain=[-3, 1], clamp=True)),
y=alt.Y('y:Q', scale=alt.Scale(domain=[-3, 1], clamp=True)),
).interactive()
Иногда полезно вручную настроить используемую цветовую шкалу.
from vega_datasets import data
weather = data.seattle_weather()
weather.head()
date | precipitation | temp_max | temp_min | wind | weather | |
---|---|---|---|---|---|---|
0 | 2012-01-01 | 0.0 | 12.8 | 5.0 | 4.7 | drizzle |
1 | 2012-01-02 | 10.9 | 10.6 | 2.8 | 4.5 | rain |
2 | 2012-01-03 | 0.8 | 11.7 | 7.2 | 2.3 | rain |
3 | 2012-01-04 | 20.3 | 12.2 | 5.6 | 4.7 | rain |
4 | 2012-01-05 | 1.3 | 8.9 | 2.8 | 6.1 | rain |
alt.Chart(weather).mark_point().encode(
x='date:T',
y='temp_max:Q',
color='weather:N'
)
Вы можете изменить цветовую схему с помощью свойства цветовой шкалы из цветовых схем Vega:
alt.Chart(weather).mark_point().encode(
x='date:T',
y='temp_max:Q',
color=alt.Color('weather:N', scale=alt.Scale(scheme="dark2"))
)
Как вариант, вы можете создать свою собственную цветовую схему, указав цветовую область и диапазон:
colorscale = alt.Scale(domain=['sun', 'fog', 'drizzle', 'rain', 'snow'],
range=['goldenrod', 'gray', 'lightblue', 'steelblue', 'midnightblue'])
alt.Chart(weather).mark_point().encode(
x='date:T',
y='temp_max:Q',
color=alt.Color('weather:N', scale=colorscale)
)
Потратьте около 10 минут и попрактикуйтесь в корректировке эстетики ваших графиков.
Используйте любимую визуализацию из предыдущего упражнения и настройте эстетику графика:
size
, strokewidth
и т. д.)x
и y
Используйте завершение табуляции в alt.Chart.configure_
, чтобы увидеть различные параметры конфигурации, затем используйте ?
, чтобы увидеть документацию по функциям.
В Altair 2.0 добавлена возможность построения географических данных.
Эта функциональность все еще немного сырая (например, не все взаимодействия или выборки работают должным образом с проецируемыми данными), но ее относительно просто использовать.
Мы покажем здесь несколько примеров.
import altair as alt
Сначала мы покажем пример построения данных широты/долготы с использованием картографической проекции. Мы загрузим набор данных, состоящий из широты/долготы каждого аэропорта США:
from vega_datasets import data
airports = data.airports()
airports.head()
iata | name | city | state | country | latitude | longitude | |
---|---|---|---|---|---|---|---|
0 | 00M | Thigpen | Bay Springs | MS | USA | 31.953765 | -89.234505 |
1 | 00R | Livingston Municipal | Livingston | TX | USA | 30.685861 | -95.017928 |
2 | 00V | Meadow Lake | Colorado Springs | CO | USA | 38.945749 | -104.569893 |
3 | 01G | Perry-Warsaw | Perry | NY | USA | 42.741347 | -78.052081 |
4 | 01J | Hilliard Airpark | Hilliard | FL | USA | 30.688012 | -81.905944 |
График очень похож на стандартный график рассеяния с некоторыми отличиями:
latitude
и longitude
вместо x
и y
Для данных, охватывающих только США, полезна проекция albersUsa
(Альберса):
Проекция Альберса — картографическая проекция, разработанная в 1805 году немецким картографом Хейнрихом Альберсом. Используется для изображения регионов, вытянутых в широтном направлении. Проекция коническая, сохраняющая площадь объектов, но искажающая углы и форму контуров (из Вики).
alt.Chart(airports).mark_circle().encode(
longitude='longitude:Q',
latitude='latitude:Q',
size=alt.value(10),
tooltip='name'
).project(
"albersUsa"
).properties(
width=500,
height=400
)
Доступные проекции перечислены в документации Vega.
Если вы хотите нанести географические границы, такие как штаты и страны, то должны загрузить данные географической формы для отображения в Altair. Для этого требуется немного шаблонов (boilerplate) (мы думаем о том, как оптимизировать эту типичную конструкцию в будущих выпусках) и использовать маркер geoshape
.
Например, вот государственные границы:
states = alt.topo_feature(data.us_10m.url, feature='states')
alt.Chart(states).mark_geoshape(
fill='lightgray',
stroke='white'
).project('albersUsa').properties(
width=500,
height=300
)
А вот и границы стран:
import altair as alt
from vega_datasets import data
countries = alt.topo_feature(data.world_110m.url, 'countries')
alt.Chart(countries).mark_geoshape(
fill='lightgray',
stroke='white'
).project(
"equirectangular"
).properties(
width=500,
height=300
)
Вы можете посмотреть, что произойдет, если попробуете другие типы проекций, например, можете попробовать mercator
, orthographic
, albers
или gnomonic
.
Если вы хотите нанести точки данных на фон карты, самый простой способ сделать это - использовать операторы наслоения (layering operators):
states = alt.topo_feature(data.us_10m.url, feature='states')
airports = data.airports()
background = alt.Chart(states).mark_geoshape(
fill='lightgray',
stroke='white'
).project('albersUsa').properties(
width=500,
height=300
)
points = alt.Chart(airports).mark_circle().encode(
longitude='longitude:Q',
latitude='latitude:Q',
size=alt.value(10),
tooltip='name'
)
background + points
Обратите внимание, что нам нужно указать проекцию и размер диаграммы только один раз.
Самый сложный тип диаграммы - это диаграмма, в которой регионы карты окрашены, чтобы отразить лежащие в основе данные. Причина, по которой это сложно, заключается в том, что это часто связано с объединением двух разных наборов данных с помощью преобразования поиска (lookup transform).
Опять же, это часть API, которую мы надеемся улучшить в будущем.
В качестве примера, вот диаграмма, представляющая общее население каждого штата:
pop = data.population_engineers_hurricanes()
pop.head()
state | id | population | engineers | hurricanes | |
---|---|---|---|---|---|
0 | Alabama | 1 | 4863300 | 0.003422 | 22 |
1 | Alaska | 2 | 741894 | 0.001591 | 0 |
2 | Arizona | 4 | 6931071 | 0.004774 | 0 |
3 | Arkansas | 5 | 2988248 | 0.002440 | 0 |
4 | California | 6 | 39250017 | 0.007126 | 0 |
import altair as alt
from vega_datasets import data
states = alt.topo_feature(data.us_10m.url, 'states')
variable_list = ['population', 'engineers', 'hurricanes']
alt.Chart(states).mark_geoshape().encode(
color='population:Q'
).transform_lookup(
lookup='id',
from_=alt.LookupData(pop, 'id', list(pop.columns))
).properties(
width=500,
height=300
).project(
type='albersUsa'
)
Обратите внимание на ключевой момент: данные хороплет имеют столбец id
, который соответствует столбцу id
в данных о населении. Мы используем его как ключ поиска, чтобы объединить два набора данных вместе и построить их соответствующим образом.
Чтобы увидеть больше примеров географических визуализаций, см. галерею Altair и имейте в виду, что это область Altair и Vega-Lite, которая постоянно улучшается!
Успехов!
Подписка на онлайн-обучение