Это руководство поможет вам без проблем создавать подсюжеты.

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

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

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

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

Импорт набора данных

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

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

Чтобы отобразить данные, нам нужно их импортировать. Если вы скачали набор данных и сохранили его в том же рабочем каталоге, что и ваш скрипт, вы можете импортировать его с помощью функции pandas.read_csv (), вызвав только имя файла. Ваш код должен выглядеть следующим образом:

import pandas as pd
data = pd.read_csv('COP_HPWH_f_Tamb&Tavg.csv', index_col = 0)

Вот и все. Теперь набор данных сохраняется в переменной «данные», а индекс фрейма данных устанавливается в первый столбец, в котором хранятся дата и время каждого измерения.

Важно знать, что данные даты и времени, используемые в качестве индекса, в настоящее время читаются как строка, а не как объект даты и времени. Для многих целей это не имеет значения, но matplotlib делает выбор форматирования оси по-разному, если это строка, а не объект даты / времени. Чтобы избежать головной боли в дальнейшем, вам нужно преобразовать индекс в индекс datetime. Вы можете сделать это с помощью функции pandas.to_datetime ():

data.index = pd.to_datetime(data.index)

И все готово! Теперь фрейм данных готов для построения графика. Если вы не знакомы с набором данных, возможно, вы захотите посмотреть, что в нем содержится, прежде чем продолжить. Вы можете сделать это вне Python, открыв файл .csv с помощью предпочитаемого вами инструмента, например Excel или OpenOffice. В python вы можете либо распечатать фрейм данных, либо использовать функцию отображения IPython для более удобного просмотра. Вот эти варианты:

# Viewing the dataframe by printing
print(data)
# Viewing the dataframe using IPython.display
from IPython.display import display
display(data)

Как только вы убедитесь, что понимаете, что находится во фрейме данных, мы готовы приступить к построению графика!

Создание графического объекта

Первым шагом в построении подзаголовков является создание объекта подзаголовка. Это создает переменную, представляющую сюжет, которую вы затем можете редактировать по своему усмотрению, чтобы получить желаемое изображение. Чтобы создать объект подзаголовка, нам нужно вызвать функцию matplotlib .subplot () и определить необходимые параметры. Хотя существует несколько вариантов параметров, наиболее важными из них являются следующие:

  • nrows: указывает количество строк, которые будут на рисунке подзаголовка. Это количество графиков, которые вы хотите выстроить по вертикали. Итак, если вы укажете три, будет верхний ряд, средний ряд и нижний ряд. Обратите внимание, что по умолчанию это значение равно единице, поэтому, если вы не введете значение, вы получите график с одной строкой.
  • ncols: то же самое, что и nrows, но для столбцов. Если вы укажете три, на вашем графике есть крайний левый столбец, центральный столбец и крайний правый столбец. Сочетание этих двух параметров означает, что ваше изображение будет иметь nrwos * ncols графиков. По умолчанию он также равен единице, поэтому, если вы не введете значение, вы получите график с одним столбцом.
  • figsize: размер желаемого изображения (всех графиков в пределах этого размера) в виде кортежа (ширина, высота) в дюймах. Если вам нужно изображение размером 12 на 4 дюйма, введите figsize = (12, 4). Чтобы упростить задачу, программисты часто вводят это как функцию от nrows и ncols. Например, если я знаю, что мне нужны две строки, три столбца и каждый график размером пять дюймов на 3 дюйма, я могу ввести figsize = (2 * 5, 3 * 3).
  • sharex: этот параметр указывает, должны ли все графики иметь одинаковые данные x и должны ли изображения отображать метки оси x только на оси нижнего графика. Я лично не использую эту функцию часто, так как мне кажется, что графики намного легче читать, если на каждой есть метки оси, но у некоторых людей разные предпочтения.
  • sharey: то же самое, что sharex, за исключением того, что применяется к оси y.
  • constrained_layout: установка для этого параметра значения True имеет тот же эффект, что и применение tight_layout () к одному изображению графика. Он очищает фигуру, уменьшая шум и избегая наложения текста друг на друга. Одно из ключевых отличий заключается в том, что tight_layout () не регулирует suptitle (я немного опишу, что это такое), в то время как constrained_layout делает, что может быть очень важно при работе с подзаголовками.

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

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

fig, axs = plt.subplots(4, 1, figsize = (12, 3 * 4), constrained_layout = True)

Этот код вернет два отдельных объекта. Один, который мы сохранили на рис., Представляет собой изображение подзаголовка, содержащее несколько графиков. Второй, который мы сохранили в axs, представляет собой указатель различных графиков, на которые мы можем ссылаться, чтобы редактировать каждый по отдельности. Созданное изображение будет состоять из четырех строк и одного столбца графиков. Его ширина будет 12 дюймов, а высота - три раза по четыре (12). И для параметра constrained_layout установлено значение True, что помогает сохранить красивый вид сюжета.

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

Добавление данных

Основной способ добавить данные в подзаголовок - вызвать команду matplotlib .plot () на желаемом графике для каждого набора данных, который вы хотите запустить. Базовый синтаксис для этого выглядит следующим образом.

axs[row, column].plot(x, y, parameters)

В этой строке и столбце кода указывается график matplotlib на изображении, которое мы редактируем. Поскольку в нашем примере есть только один столбец, значение для столбца всегда будет нулевым (и мы можем просто пренебречь кодом в столбце, поскольку matplotlib уже знает, что он будет равен нулю). Поскольку на нашем изображении четыре графика, row будет от 0 до 3. Затем мы можем установить данные x и y по мере необходимости, а также указать желаемые параметры построения, которые я опишу позже.

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

Чтобы создать словарь, вам нужно подумать о том, что вы хотите построить. В этом примере мы хотим создать четыре графика из набора данных образца. Они будут:

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

Чтобы создать эти четыре графика, нам необходимо структурировать словарь таким образом, чтобы 1) разбить данные на четыре набора для четырех графиков и 2) предоставить столбцы для ссылки при построении данных. Мы даже можем облегчить себе жизнь, заставив словарь передавать метки оси Y и метки легенды для наборов данных. Я сделаю это в примере, а затем объясню, как это работает.

Словарь, который соответствует требованиям, указанным выше для нашего набора данных, выглядит следующим образом.

columns = {
           'Temperature (deg F)': {
                     'T_In (deg F)': 'Inlet',
                     'T_Out (deg F)': 'Outlet',
                     'T_Amb (deg F)': 'Ambient'               
                    },
           'Water Temperature (deg F)': {
                      'T1 (deg F)': 'T1',
                      'T2 (deg F)': 'T2',
                      'T3 (deg F)': 'T3',
                      'T4 (deg F)': 'T4',
                      'T5 (deg F)': 'T5',
                      'T6 (deg F)': 'T6',
                      'T7 (deg F)': 'T7',
                      'T8 (deg F)': 'T8',
           },
           'Flow Rate (gal/min)': {
                     'Flow Rate (gal/min)': 'Flow Rate'
                    },
           'Electric Power (W)': {
                      'P_Elec (W)': 'Electric Power'
                     }
          }

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

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

for key in columns.keys():

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

for key in columns.keys():
    for parameter in columns[key].keys():

Этот код теперь будет перебирать каждый из ключей в словаре верхнего уровня («Температура (градус F)», «Температура воды (градус F)» и т. Д.), А затем перебирать словари, содержащиеся в нем («T_In (deg F) ',' T_Out (deg F) 'и т. Д.). Если вы хотите увидеть, как это работает, вы можете добавить ключ и параметр отчета о печати, а затем запустить код.

Эта структура цикла for позволяет выполнять итерацию кода для построения каждого набора данных, указанного в словаре. Единственный необходимый шаг - добавить для этого оператор .plot (). Если мы это сделаем, наш код будет таким:

for key in columns.keys():
    for parameter in columns[key].keys():
        axs[row].plot(data[parameter])

Итак, здесь есть проблема, которую некоторые из вас, возможно, заметили. Этот код включает ссылку на переменную «row», сообщающую matplotlib, какой график данные следует заполнить, без определения строки. Так как наш словарь начинается с верхнего графика и постепенно движется вниз, мы можем просто установить строку так, чтобы она начиналась с нуля и увеличивалась на один шаг за график, пока мы не закончим. Если мы это сделаем, код станет:

row = 0
for key in columns.keys():
    for parameter in columns[key].keys():
        axs[row].plot(data[parameter])
    row +=1

Это построит все данные на правильном графике и отобразит график. Ура! Теперь наш график показывает данные и предоставляет некоторую информацию. Теперь он должен выглядеть, как показано ниже.

Однако это все еще не лучший сюжет. У него нет меток осей x или y. Никаких легенд об этом не сложилось. У него нет названия. Слишком много данных, что затрудняет чтение. И он использует линии вместо точек для измерений (Custom означает использовать точки для измеренных значений, линии для имитированных значений).

К счастью, мы можем позаботиться обо всех этих вещах по очереди.

Добавление описательной информации

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

  1. Легенды к каждому графику, включая метки для каждой серии данных,
  2. метки оси x,
  3. метки оси Y и
  4. Название полного изображения.

Легенду добавить легко. Для этого нам нужно указать метку для каждой серии данных при ее построении, и мы делаем это, задав параметр «label» для этой команды построения графика. К счастью, мы также добавили желаемые метки в качестве значений во вложенный словарь выше, чтобы мы могли просто ссылаться на них! Для этого нам нужно покопаться в нашем словаре столбцов с ключом верхнего уровня (представленным ключом) и ключом второго уровня (представленным параметром), чтобы получить значение, хранящееся там, и установить параметр метки на это значение. Другими словами, нам нужно изменить код построения:

row = 0
for key in columns.keys():
    for parameter in columns[key].keys():
        axs[row].plot(data_reduced[parameter], label = columns[key][parameter])
    row += 1

Теперь каждой команде построения назначается правильный ярлык.

Легенды могут быть добавлены к графику путем вызова функции .legend () для каждого индекса осей во время итерации по графикам. Другими словами, на каждом сюжете будут легенды.

row = 0
for key in columns.keys():
    for parameter in columns[key].keys():
        axs[row].plot(data_reduced[parameter], label = columns[key][parameter])
    axs[row].legend()
    row += 1

Чтобы добавить метки осей x и y, нам нужно вызвать функцию .set () для каждого индекса оси и установить параметры xlabel и ylabel. К счастью, ключи в словаре верхнего уровня содержат информацию, которую мы хотим разместить на каждом графике, а метка оси x всегда указывает, что это datetime, и указывает формат. Таким образом, мы можем добавить метки осей, изменив наш код следующим образом.

row = 0
for key in columns.keys():
    for parameter in columns[key].keys():
        axs[row].plot(data_reduced[parameter], label = columns[key][parameter])
    axs[row].legend()
    axs[row].set(ylabel = key, xlabel = 'DateTime (MM-DD HH)')
    row += 1

Последняя часть описательной информации - это заголовок всего изображения. Это делается путем вызова функции .suptitle (), которая помещает заголовок вверху изображения. Напомним, что именно поэтому мы ранее установили constrained_layout = True. Без этого комментария заголовок может оказаться в странном положении. Не стесняйтесь попробовать запустить код без установки constrained_layout, просто чтобы посмотреть, что произойдет.

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

row = 0
for key in columns.keys():
    for parameter in columns[key].keys():
        axs[row].plot(data_reduced[parameter], label = columns[key][parameter])
    axs[row].legend()
    axs[row].set(ylabel = key, xlabel = 'DateTime (MM-DD HH)')
    row += 1

Это дает следующее изображение.

Это конечно лучше! Данные отображаются на 4 различных подзаголовках, обеспечивая четкое отображение и видимость набора данных. Оси x и y помечены, чтобы читатель знал, что представляют собой данные. Легенды идентифицируют каждую отдельную серию данных. А вверху есть красивый заголовок, в котором указано, откуда проверяются данные.

Но мы все еще можем сделать это лучше.

Сокращение набора данных

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

  1. Отфильтруйте данные с помощью правил индексации панд,
  2. Измените заголовок, чтобы представить текущий тест, и
  3. Постройте данные.

В этом примере я покажу, как создать первый график, представляющий испытание при температуре окружающей среды 50 градусов по Фаренгейту. Если вы хотите создать все три графика, вы можете написать цикл for, используя приведенный выше пример или советы из Основы потока управления в Python и Разделение наборов данных.

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

В итоге я обнаружил, что правильное количество строк, которое нужно сохранить, было 3400. Как только я это обнаружил, я смог отфильтровать данные с помощью следующего кода:

index = 3400
data_reduced = data[data.index < data.index[index]]

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

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

axs[row].plot(data_reduced[parameter], label = columns[key][parameter])

С этим изменением каждый раз, когда код строит данные, он извлекает их из сокращенного набора данных вместо исходного.

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

plt.suptitle('All Data from the 50 deg F Ambient Temperature Test')

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

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

Но есть еще несколько небольших изменений, которые мы можем внести, чтобы улучшить его.

Визуальный стиль

Мы можем внести два изменения в визуальный стиль, чтобы сделать наш сюжет лучшим средством коммуникации. Эти:

  1. Обычно измерения отображаются в виде точек, а моделируемые данные - в виде линий, поэтому мы должны изменить наши наборы данных на точки и удалить линии (все столбцы данных представляют измеренные данные), и
  2. Мы должны настроить цвета, чтобы они соответствовали нашим цветовым предпочтениям или желаемому шаблону.

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

axs[row].plot(data_reduced[parameter], label = columns[key][parameter], marker = '.', linestyle = '')

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

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

Для этого примера я создам словарь, используя стандартные справочные цвета matplotlib. Хотя есть много способов реализовать цвета в matplotlib, именованные цвета - это простой способ начать работу. Затем я хочу сохранить несколько из этих цветов в словаре, который позже можно будет просмотреть, чтобы указать разные цвета для каждого набора данных. Для этого примера я сделал следующий словарь:

colors = {
          '1': 'limegreen',
          '2': 'teal',
          '3': 'dodgerblue',
          '4': 'darkviolet',
          '5': 'black',
          '6': 'darkgray',
          '7': 'red',
          '8': 'sandybrown'
         }

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

i = 1
    for parameter in columns[key].keys():
        axs[row].plot(data_reduced[parameter], label = columns[key]   [parameter], marker = '.', linestyle = '', color = colors[str(i)])
        i += 1

В этом случае наш итератор - «i». Первоначально мы устанавливаем его на «1», чтобы он соответствовал первому ключу в словаре. Затем мы передаем его в код построения, где преобразуем его в строку, а затем говорим matplotlib построить набор данных, используя цвет, соответствующий этому ключу. Наконец, после построения графика, но все еще в цикле for, мы добавляем 1 к итератору, таким образом переходя к следующему итератору в словаре для следующего цвета. Затем код строит следующую серию данных вторым цветом и переходит к третьему цвету, прежде чем продолжить цикл. И он продолжает делать это до тех пор, пока не закончатся ряды данных.

Следует иметь в виду, что если вы используете этот метод, вы должны указать в словаре столько цветов, сколько у вас есть рядов данных. Если вы попытаетесь построить девять рядов данных с указанием восьми цветов, у вас будут плохие времена.

С этими двумя изменениями выполнение кода дает следующий график.

И этот сюжет - хорошее средство общения!

Больше контента на plainenglish.io