Исследование погоды в Сиэтле
Этот урок адаптирован из документации Vega-Lite.
Вы познакомитесь с дополнительными приёмами создания визуализаций в Altair. Если вы ещё не знакомы с библиотекой, сначала прочитайте вводный материал.
Будем исследовать данные NOAA о погоде в Сиэтле. Набор представлен CSV-файлом со столбцами температуры в градусах Цельсия, осадков в миллиметрах, скорости ветра в метрах в секунду и типа погоды. Каждая строка соответствует одному дню с 1 января 2012 года по 31 декабря 2015 года.
Altair работает с данными в DataFrame pandas и предоставляет загрузчик этого и других встроенных наборов:
from altair.datasets import data
df = data.seattle_weather()
df.head()
Данные загружаются из интернета в DataFrame pandas. Теперь их можно исследовать с Altair.
Начнём с осадков: штрихи позволяют увидеть распределение значений:
import altair as alt
alt.Chart(df).mark_tick().encode(
x='precipitation',
)
Распределение смещено к низким значениям: когда в Сиэтле идёт дождь, осадков обычно немного. На непрерывной шкале закономерности трудно различить, поэтому построим гистограмму. Для этого разобьём значения канала x на интервалы, а в канале y зададим count:
alt.Chart(df).mark_bar().encode(
alt.X('precipitation').bin(),
y='count()'
)
Посмотрим, как количество осадков меняется в течение года. Altair поддерживает даты и их группировку, когда тип задан как temporal, сокращённо T. На следующей диаграмме вычисляется среднее количество осадков для каждого месяца. Группировка по месяцам задаётся через month; другие варианты описаны в разделе преобразования TimeUnit:
alt.Chart(df).mark_line().encode(
x='month(date):T',
y='average(precipitation)'
)
В Сиэтле среднее количество осадков зимой значительно выше, чем летом, что вряд ли удивит местных жителей. Меняя соответствие каналов кодирования и признаков данных, можно исследовать другие зависимости.
Для осадков и температуры бывает полезнее группировка по году и месяцу (yearmonth), а не только по месяцу. Она показывает сезонные тенденции, сглаживая ежедневные колебания. Можно также исследовать максимальную и минимальную температуру каждого месяца:
alt.Chart(df).mark_line().encode(
x='yearmonth(date):T',
y='max(temp_max)',
)
На этом коротком временном интервале максимальная температура, по-видимому, увеличивается от года к году. Рассмотрим среднее значение дневных максимумов температуры за каждый год:
alt.Chart(df).mark_line().encode(
x='year(date):T',
y='mean(temp_max)',
)
Столбчатая диаграмма делает сравнение нагляднее. Зададим году порядковый тип — ordinal, то есть упорядоченную категорию. Для удобства сделаем диаграмму горизонтальной, поместив год на ось y:
alt.Chart(df).mark_bar().encode(
x='mean(temp_max)',
y='year(date):O'
)
Диаграмма показывает, что средняя дневная максимальная температура росла в течение этих четырёх лет. Это можно проверить и для дневных минимумов.
Можно также исследовать изменение дневного диапазона температур. Для вычисления нового поля добавим преобразование calculate:
alt.Chart(df).mark_bar().encode(
x='mean(temp_range):Q',
y='year(date):O'
).transform_calculate(
temp_range="datum.temp_max - datum.temp_min"
)
Вычисление не изменяет данные в Python. Оно записывается в спецификацию диаграммы и выполняется механизмом отображения.
Тот же результат можно получить, явно добавив столбец средствами pandas. Однако тогда вычисленные значения придётся хранить в спецификации вместо их вычисления по необходимости в браузере.
Теперь рассмотрим поле weather: это категориальная переменная с типом погоды в конкретный день. Как распределяются солнечные, дождливые и другие дни в течение года? Сгруппируем даты по месяцам, посчитаем записи в канале y и разделим столбцы по типу погоды, связав это поле с цветом. Когда поле данных сопоставлено цвету, Altair автоматически располагает сегменты столбцов с накоплением:
alt.Chart(df).mark_bar().encode(
x='month(date):N',
y='count()',
color='weather',
)
Палитра по умолчанию может не соответствовать смыслу данных. Например, для солнечной погоды (sun) вряд ли ожидается фиолетовый цвет. Зададим диапазон цветовой шкалы, сопоставляющий значения поля weather подходящим цветам через обычные шестнадцатеричные коды:
scale = alt.Scale(domain=['sun', 'fog', 'drizzle', 'rain', 'snow'],
range=['#e7ba52', '#c7c7c7', '#aec7e8', '#1f77b4', '#9467bd'])
Передадим шкалу каналу цвета. Дополнительно зададим понятные заголовки оси и легенды:
alt.Chart(df).mark_bar().encode(
x=alt.X('month(date):N').title('Month of the year'),
y='count()',
color=alt.Color('weather', legend=alt.Legend(title='Weather type'), scale=scale),
)
Сочетая эти приёмы, можно создавать самые разные визуализации набора данных. Следующая диаграмма исследует связь погоды, осадков, максимальной температуры и дневного диапазона температур. Она использует предыдущие настройки, увеличенную область отображения и интерактивное перемещение и масштабирование мышью:
alt.Chart(df).mark_point().encode(
alt.X('temp_max').title('Maximum Daily Temperature (C)'),
alt.Y('temp_range:Q').title('Daily Temperature Range (C)'),
alt.Color('weather').scale(scale),
alt.Size('precipitation').scale(range=[1, 200])
).transform_calculate(
"temp_range", "datum.temp_max - datum.temp_min"
).properties(
width=600,
height=400
).interactive()
Диаграмма помогает увидеть закономерности: дождливые и туманные дни обычно прохладнее и имеют меньший диапазон температур, а тёплые дни чаще сухие и солнечные, с большей разницей между минимумом и максимумом.
Продолжим исследование с помощью составных диаграмм и интерактивности. Например, построим гистограмму количества дней по типу погоды:
alt.Chart(df).mark_bar().encode(
x='count()',
y='weather:N',
color=alt.Color('weather:N').scale(scale),
)
Расположим её под предыдущей диаграммой рассеяния и добавим инструмент выделения области. Гистограмма будет отражать содержимое выбора. Подробнее см. «Интерактивные диаграммы»:
brush = alt.selection_interval()
color = alt.Color("weather:N").scale(scale)
temp_range = alt.datum["temp_max"] - alt.datum["temp_min"]
points = alt.Chart(width=600, height=400).mark_point().encode(
alt.X("temp_max:Q").title("Maximum Daily Temperature (C)"),
alt.Y("temp_range:Q").title("Daily Temperature Range (C)"),
color=alt.when(brush).then(color).otherwise(alt.value("lightgray")),
size=alt.Size("precipitation:Q").scale(range=[1, 200]),
).transform_calculate(
temp_range=temp_range
).add_params(
brush
)
bars = alt.Chart(width=600).mark_bar().encode(
x="count()",
y="weather:N",
color=color
).transform_calculate(
temp_range=temp_range
).transform_filter(
brush
)
alt.vconcat(points, bars, data=df)
Эта диаграмма сочетает объединение панелей, преобразования данных, выборы, настройку подписей осей и шкал. Она показывает возможности грамматики Altair: сложная визуализация складывается из небольшого числа строительных блоков.
В уроке вы познакомились с группировкой и агрегацией данных, вычислением новых полей и настройкой диаграмм. Другие визуализации представлены в галерее примеров. Для дальнейшей настройки обратитесь к справочнику API.