[Перевод] Визуализация данных с боке в Python, часть 2: взаимодействие

Python визуализация данных
[Перевод] Визуализация данных с боке в Python, часть 2: взаимодействие

Диаграммы, выходящие за рамки статических графиков

из этой сериипервая частьВ вводимBokehБазовая гистограмма, созданная в (мощная библиотека визуализации на Python). Окончательный результат показывает распределение опоздавших из Нью-Йорка в 2013 году следующим образом (с очень хорошей подсказкой):

Эти часы выполняют свою работу, но они не очень привлекательны! Пользователи могут видеть, что задержки рейсов почти нормальные (с небольшим наклоном), но у них нет причин тратить на это число больше нескольких секунд.

Если мы хотим создать более привлекательную визуализацию данных, мы можем позволить пользователям интерактивно получать нужные им данные. Например, на этой гистограмме полезной функцией является возможность указать авиакомпании для сравнения или изменить ширину контейнера для более подробного изучения данных. К счастью, мы можем использовать Боке, чтобы добавить эти две функции к существующему графику. Первоначальная разработка гистограммы, казалось, включала в себя простой график, но теперь мы собираемся ощутить преимущества такой мощной библиотеки, как Bokeh!

Все коды этой сериидоступны на GitHub. Любой желающий может ознакомиться со всеми подробностями очистки данных (менее вдохновляющая, но важная часть науки о данных) или запустить их самостоятельно! (Для интерактивных графиков Bokeh мы все еще можем использовать Jupyter Notebook для отображения результатов, мы также можем писать сценарии Python и запускать сервер Bokeh. Я обычно использую Jupyter Notebook для разработки, потому что он работает без перезапуска сервера. Легко быстро выполнить итерацию и изменить графики. Затем я перенес их на сервер, чтобы показать окончательный результат. Вы можете увидеть отдельный скрипт и полные заметки на GitHub).

активное взаимодействие

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

Подсказки, пассивные интеракторы

Второй тип взаимодействия называется активным, потому что он изменяет фактические данные, отображаемые на графике. Это может быть что угодно, от выбора подмножества данных (например, указанной авиакомпании) до изменения подгонки соответствующей полиномиальной регрессии. Есть много типов бокеактивное взаимодействие, но здесь мы сосредоточимся на «виджетах», элементах, на которые можно нажимать и которыми пользователь может управлять некоторыми аспектами рисования.

Пример виджета (выпадающая кнопка и группа переключателей)

Мне нравится активное взаимодействие, когда я смотрю на графики (такие как взаимодействие с FlowingData), потому что они позволяют мне самому изучать данные. Меня больше впечатляет вывод из собственных данных (некоторые направления исследований, взятые у дизайнеров), чем из полностью статического графика. Кроме того, предоставление пользователям определенной степени свободы позволяет им придумывать более полезные обсуждения набора данных, что приводит к различным интерпретациям.

Обзор взаимодействия

Как только мы начнем добавлять активные взаимодействия, нам нужно выйти за рамки отдельных строк кода и погрузиться в функции, которые инкапсулируют определенные действия. Для взаимодействия виджетов Боке можно реализовать три основные функции:

  • make_dataset()Отформатируйте определенные данные, которые вы хотите отобразить
  • make_plot()График с указанными данными
  • update()Обновление чертежа на основе выбора пользователя

форматировать данные

Прежде чем мы нарисуем этот график, нам нужно спланировать данные, которые будут отображаться. Для нашей интерактивной гистограммы мы предоставим пользователю три управляемых параметра:

  1. Отображение полета (в коде именуется перевозчиком)
  2. Диапазон задержки на графике, например: от -60 до 120 минут
  3. По умолчанию ширина ячейки гистограммы составляет 5 минут.

Для функции, которая генерирует набор данных графика, нам нужно разрешить указывать каждый параметр. Чтобы показать нам, как конвертироватьmake_datasetdata в функции, нам нужно загрузить все соответствующие данные для проверки.

Данные гистограммы

В этом наборе данных каждая строка представляет собой отдельный рейс.arr_delayСтолбец — задержка прибытия рейса в минутах (отрицательное число означает, что рейс прибывает раньше). В первой части мы провели небольшое исследование данных и узнали, что было 327 236 рейсов с минимальной задержкой -86 минут и максимальной задержкой 1272 минуты. существуетmake_datasetфункция, мы хотим, чтобы основаnameстолбец для выбора компаний и использованияarr_delayколонка для ограничения полетов.

Для генерации данных гистограммы мы используем функцию numpyhistogramдля подсчета количества точек данных в каждом контейнере. В нашем примере это количество рейсов в каждом заданном интервале задержки. Для первой части мы сделали гистограмму со всеми рейсами, а пока у нас будет гистограмма для каждого оператора. Поскольку количество рейсов сильно различается для каждой авиакомпании, мы можем отображать задержки вместо необработанных чисел, которые можно масштабировать. То есть высоты на графике соответствуют доле всех рейсов конкретной авиакомпании, имеющих задержки в соответствующем контейнере. От счета к масштабу делим на общее количество авиакомпаний.

Ниже приведен полный код для создания набора данных. Функция принимает список операторов, которые мы хотим включить, минимальную и максимальную задержку отрисовки и указанную ширину контейнера (в минутах).

def make_dataset(carrier_list, range_start = -60, range_end = 120, bin_width = 5):

    # 为了确保起始点小于终点而进行检查
    assert range_start < range_end, "Start must be less than end!"
    
    by_carrier = pd.DataFrame(columns=['proportion', 'left', 'right', 
                                       'f_proportion', 'f_interval',
                                       'name', 'color'])
    range_extent = range_end - range_start
    
    # 遍历所有运营商
    for i, carrier_name in enumerate(carrier_list):

        # 运营商子集
        subset = flights[flights['name'] == carrier_name]

        # 创建具有指定容器和范围的柱状图
        arr_hist, edges = np.histogram(subset['arr_delay'], 
                                       bins = int(range_extent / bin_width), 
                                       range = [range_start, range_end])

        # 将极速除以总数,得到一个比例,并创建 df
        arr_df = pd.DataFrame({'proportion': arr_hist / np.sum(arr_hist), 
                               'left': edges[:-1], 'right': edges[1:] })

        # 格式化比例
        arr_df['f_proportion'] = ['%0.5f' % proportion for proportion in arr_df['proportion']]

        # 格式化间隔
        arr_df['f_interval'] = ['%d to %d minutes' % (left, right) for left, 
                                right in zip(arr_df['left'], arr_df['right'])]

        # 为标签指定运营商
        arr_df['name'] = carrier_name

        # 不同颜色的运营商
        arr_df['color'] = Category20_16[i]

        # 添加到整个 dataframe 中
        by_carrier = by_carrier.append(arr_df)

    # 总体 dataframe
    by_carrier = by_carrier.sort_values(['name', 'left'])
    
    # 将 dataframe 转换为列数据源
    return ColumnDataSource(by_carrier)

(Я знаю, что это сообщение в блоге о боке, но вы не можете создать диаграмму без форматирования данных, поэтому я использовал соответствующий код, чтобы продемонстрировать свой подход!)

Запуск функции с нужным оператором приводит к следующему:

Напоминаем, что мы используем бокеquadtable, чтобы сделать столбчатую диаграмму, поэтому нам нужно предоставить левую, правую и верхнюю части таблицы (нижняя часть будет зафиксирована на 0). Они перечислены вleft,rightа такжеproportion. Столбец цвета предоставляет уникальный цвет для каждого оператора,f_Перечисленные инструменты предоставляют возможность форматирования текста.

Следующей функцией, которую необходимо реализовать, являетсяmake_plot. Функция должна принимать ColumnDataSource(особый тип объекта, используемый для рисования боке)и вернуть объект сюжета:

def make_plot(src):
        # 带有正确标签的空白图
        p = figure(plot_width = 700, plot_height = 700, 
                  title = 'Histogram of Arrival Delays by Carrier',
                  x_axis_label = 'Delay (min)', y_axis_label = 'Proportion')

        # 创建柱状图的四种符号
        p.quad(source = src, bottom = 0, top = 'proportion', left = 'left', right = 'right',
               color = 'color', fill_alpha = 0.7, hover_fill_color = 'color', legend = 'name',
               hover_fill_alpha = 1.0, line_color = 'black')

        # vline 模式下的悬停工具
        hover = HoverTool(tooltips=[('Carrier', '@name'), 
                                    ('Delay', '@f_interval'),
                                    ('Proportion', '@f_proportion')],
                          mode='vline')

        p.add_tools(hover)

        # Styling
        p = style(p)

        return p 

Если передать исходник всем авиакомпаниям, то этот код выдаст следующий сюжет:

Эта гистограмма очень сбивает с толку, потому что все 16 авиакомпаний нанесены на один и тот же график! Поскольку информация перекрывается, сравнивать авиакомпании нереально. К счастью, мы можем добавить виджеты, чтобы сделать графики более четкими, а также сделать быстрые сравнения.

Создавайте интерактивные виджеты

После того, как мы создали базовый график в Bokeh, добавление взаимодействия через виджеты становится относительно простым. Первый виджет, который нам нужен, — это поле выбора, которое позволяет пользователю выбрать, какую авиакомпанию отображать. Это элемент управления флажком, который позволяет выбрать столько вариантов, сколько вы хотите, называется T в боке.CheckboxGroup.. Чтобы сделать этот необязательный инструмент, нам нужно импортироватьCheckboxGroupкласс для создания экземпляра с двумя параметрами,labels: мы хотим отображать значение рядом с каждым полем, а такжеactive: Отметьте начальный флажок. Создано нижеCheckboxGroupТребуемый оператор прилагается к коду.

from bokeh.models.widgets import CheckboxGroup

# 创建复选框可选元素,可用的载体是
# 数据中所有航空公司组成的列表
carrier_selection = CheckboxGroup(labels=available_carriers, 
                                  active = [0, 1])

Виджет CheckboxGroup

Метка в флажке Боке должна быть строкой, но активное значение должно быть целым числом. Это означает, что на изображении «AirTran Airways Corporation» значение активации равно 0, а значение активации «Alaska Airlines Inc.» равно 1. Когда мы хотим сопоставить отмеченный флажок с авиакомпаниями, нам нужно убедиться, что выбранныйЦелое числоЗначение активации может соответствовать соответствующемунить. Мы можем использовать компонент.labelsи.activeсвойства для достижения.

# 从选择值中选择航空公司的名称
[carrier_selection.labels[i] for i in carrier_selection.active]

['AirTran Airways Corporation', 'Alaska Airlines Inc.']

После создания виджета нам нужно связать отмеченные флажки авиакомпаний с информацией, отображаемой на графике. Это использует CheckboxGroup.on_changeметод и что мы определяемupdateфункция завершена. Функция обновления всегда имеет три параметра:attr、old、newи обновить чертеж на основе элемента управления выбором. Способ изменить данные, отображаемые на графике, состоит в том, чтобы изменить то, что мы передаем.make_plotИсточник данных для графика в функции. Это может показаться немного абстрактным, поэтому вотupdateПример функции, которая изменяет гистограмму для отображения выбранных авиакомпаний:

# update 函数有三个默认参数
def update(attr, old, new):
    # Get the list of carriers for the graph
    carriers_to_plot = [carrier_selection.labels[i] for i in
                        carrier_selection.active]

    # 根据被选中的运营商和
    # 先前定义的 make_dataset 函数来创建一个新的数据集
    new_src = make_dataset(carriers_to_plot,
                           range_start = -60,
                           range_end = 120,
                           bin_width = 5)

    # update 在 quad glpyhs 中使用的源
    src.data.update(new_src.data)

Здесь мы получаем список авиакомпаний из CheckboxGroup для отображения на основе выбранной авиакомпании. Этот список передаетсяmake_datasetфункция, которая возвращает новый источник данных столбца. мы называемsrc.data.updateА входящие данные из нового источника обновляют исходные данные, используемые в диаграмме. Наконец, для того, чтобыcarrier_selectionИзменения в виджете связаны сupdateфункция, мы должны использовать.on_changeметод (так называемыйобработчик события).

# 将选定按钮中的更改链接到 update 函数
carrier_selection.on_change('active', update)

Функция обновления вызывается при выборе или отмене другого рейса. Конечным результатом является то, что на гистограмме отображаются только символы, соответствующие выбранной авиакомпании, например:

Больше элементов управления

Теперь, когда мы знаем основной рабочий процесс создания элементов управления, мы можем добавить дополнительные элементы. Каждый раз, когда мы создаем виджет, мы пишем функцию обновления для изменения данных, отображаемых на графике, связывая функцию обновления с виджетом через обработчик событий. Мы даже можем использовать одну и ту же функцию обновления из нескольких элементов, чтобы извлечь нужные нам значения из виджета, переопределив функцию. На практике мы добавим два дополнительных элемента управления: Slider для выбора ширины контейнера гистограммы и RangeSlider для установки минимальной и максимальной задержки. Вот код, который генерирует эти виджеты и функцию обновления:

# 滑动 bindwidth,对应的值就会被选中
binwidth_select = Slider(start = 1, end = 30, 
                     step = 1, value = 5,
                     title = 'Delay Width (min)')
# 当值被修改时,更新绘图
binwidth_select.on_change('value', update)

# RangeSlider 用于修改柱状图上的最小最大值
range_select = RangeSlider(start = -60, end = 180, value = (-60, 120),
                           step = 5, title = 'Delay Range (min)')

# 当值被修改时,更新绘图
range_select.on_change('value', update)


# 用于 3 个控件的 update 函数
def update(attr, old, new):
    
    # 查找选定的运营商
    carriers_to_plot = [carrier_selection.labels[i] for i in carrier_selection.active]
    
    # 修改 binwidth 为选定的值
    bin_width = binwidth_select.value

    # 范围滑块的值是一个元组(开始,结束)
    range_start = range_select.value[0]
    range_end = range_select.value[1]
    
    # 创建新的列数据
    new_src = make_dataset(carriers_to_plot,
                           range_start = range_start,
                           range_end = range_end,
                           bin_width = bin_width)

    # 在绘图上更新数据
    src.data.update(new_src.data)

Стандартные ползунки и ползунки диапазона следующие:

Если мы хотим, мы можем изменить другие функции построения графиков, помимо использования функции обновления для отображения данных. Например, чтобы текст заголовка соответствовал ширине контейнера, мы можем сделать:

# 将绘图标题修改为匹配选择
bin_width = binwidth_select.value
p.title.text = 'Delays with %d Minute Bin Width' % bin_width

В Bokeh CNOOC есть много других типов взаимодействия, но теперь наши три элемента управления позволяют «бегать» по иконке!

положил все это вместе

Все наши интерактивные элементы сюжета были сказаны и сделаны. У нас есть три необходимые функции:make_dataset,make_plotиupdate, чтобы изменить рисунок на основе управления и самой системы. Мы соединяем все эти элементы на странице, определяя макет.

from bokeh.layouts import column, row, WidgetBox
from bokeh.models import Panel
from bokeh.models.widgets import Tabs

# 将控件放在单个元素中
controls = WidgetBox(carrier_selection, binwidth_select, range_select)
    
# 创建行布局
layout = row(controls, p)
    
# 使用布局来创建一个选项卡
tab = Panel(child=layout, title = 'Delay Histogram')
tabs = Tabs(tabs=[tab])

Я помещаю весь макет на одну вкладку, и когда мы создадим полное приложение, мы можем создать отдельную вкладку для каждого рисунка. Итоговый результат работы следующий:

допустимыйGitHubОзнакомьтесь с соответствующим кодом и нарисуйте свой собственный.

Следующие шаги и содержание

В следующей части этой серии мы обсудим, как использовать несколько графиков для создания полноценного приложения. Мы представим результаты нашей работы через сервер, доступ к которому можно получить через браузер, и создадим полную панель инструментов для изучения набора данных.

Как мы видим, окончательный интерактивный сюжет намного полезнее оригинала! Теперь мы можем сравнить задержки между авиакомпаниями и изменить ширину/протяженность контейнера, чтобы увидеть, как это влияет на эти распределения. Добавленная интерактивность повышает ценность графика, поскольку добавляет поддержку данных и позволяет пользователям делать выводы на основе собственного исследования. Несмотря на настройку инициализированного чертежа, мы по-прежнему видим, как легко можно добавлять элементы и элементы управления к существующему чертежу. По сравнению с быстрыми и простыми библиотеками построения графиков, такими как matplotlib, использование более тяжелой библиотеки построения графиков, такой как bokeh, позволяет настраивать графики и взаимодействия. Различные библиотеки визуализации имеют разные преимущества и варианты использования, но Bokeh — отличный выбор, когда мы хотим добавить дополнительное измерение взаимодействия. Надеюсь, на этом этапе вы чувствуете себя достаточно уверенно, чтобы разрабатывать свои собственные визуализации, а также видеть, что вы можете поделиться своими собственными творениями.

Отзывы и конструктивная критика приветствуются в Твиттере.@koehrsen_willсвяжитесь со мной по.


  1. [перевод]Визуализация данных с боке в Python, часть 1: начало работы
  2. [перевод]Визуализация данных с боке в Python, часть 2: взаимодействие
  3. [перевод]Визуализация данных с помощью Bokeh в Python, часть 3: создание полной информационной панели

Если вы обнаружите ошибки в переводе или в других областях, требующих доработки, добро пожаловать наПрограмма перевода самородковВы также можете получить соответствующие бонусные баллы за доработку перевода и PR. начало статьиПостоянная ссылка на эту статьюЭто ссылка MarkDown этой статьи на GitHub.


Программа перевода самородковэто сообщество, которое переводит высококачественные технические статьи из Интернета сНаггетсДелитесь статьями на английском языке на . Охват контентаAndroid,iOS,внешний интерфейс,задняя часть,блокчейн,продукт,дизайн,искусственный интеллектЕсли вы хотите видеть более качественные переводы, пожалуйста, продолжайте обращать вниманиеПрограмма перевода самородков,официальный Вейбо,Знай колонку.