Homemade візуалізація. Частина-1. Теплокарта

Petro Ivanyuk
8 min readNov 18, 2021

В цій та, можливо, кількох інших статтях я спробую описати програмування візуалізацій. Я навіть не впевнений, чи є такий термін в українській мові, але кращого наразі підібрати не можу.

Мотивація

Все моє програмування якимось чином пов’язане із графіками. Вони дуже рідко бувають доведеними до красивого вигляду, інколи — не зовсім інформативні. Дуже часто це просто якісь лінії, сигнали чи розподіли певної величини, інколи це можуть бути агреговані таблиці, мапи чи навіть 3D об’єкти.

Кілька тижнів тому, переглядаючи тижневу збірку візуалізації даних, в мене виникла думка, що багато схожих графіків я вже колись отримував. В той же час, таких, що хотів би вміти робити, є ще більше. Ця думка переросла в ширшу ідею — спробувати відтворити з нуля цікаві, на мій погляд, приклади візуалізацій, використовуючи тільки засоби програмування.

Отож, як можна сформулювати завдання? Взяти загальнодоступну реальну візуалізацію та отримати максимально схожу на неї. При цьому я не знаю яким чином її побудували автори. Якщо є доступ до оригінальних даних, то буду їх використовувати. В той же час, якщо дані відсутні, то пробую їх створити чи на зовсім інших будую схожий графік, щоб зберегти його основне функціональне призначення.

Вступ

Для цієї публікації я вибрав статтю із відомого спортивного ресурсу fivethirtyeight про візуалізацію видів спорту, що мали місце протягом всієї історії Олімпійських ігор. Ви можете знайти статтю за посиланням Every Olympic ‘Sport,’ In One Chart.

Тут кожний вертикальний стовпець відповідає року проведення Олімпійських ігор, а кожний рядок — за конкретний вид спорту, наприклад, бокс, стрільба із лука чи легка атлетика. Якщо медалі із виду спорту розігрувались, то квадратик зафарбований, в той же час, якщо він білий — медалі не розігрувались (рис. 1).

Як видно із рисунку, ця візуалізація нагадує теплокарту (heatmap), хоча і дещо спрощену через відсутність гамми кольорів. Я розгляну один із можливих способів програмування візуалізації такого типу мовою python. Для оброблення даних я використовую бібліотеку pandas (впевнений, що справжній гуру зможе обійтися excel), a для візуалізації — бібліотеку seaborn, яка є надбудовою вищого рівня над matplotlib. Як бонус, в кінці статті розміщу візуалізацію зі змінною гамою кольорів.

Повний код оброблення та візуалізації даних можна знайти в репозиторії проекту на Github та ноутбуці набору даних на Kaggle. В самій статті я пропоную тільки ключові частини коду із коротким описом.

Рис. 1. Часова діаграма видів спорту присутніх на Олімпійських іграх. Скріншот частини візуалізації зі статті Every Olympic ‘Sport,’ In One Chart.

Причин вибору саме цієї візуалізації, для першої спроби, є кілька:

  1. Такого типу візуалізації можна доволі часто побачити в різних областях знань, де потрібно відобразити зміну параметру в часі.
  2. Кілька місяців тому я створив кілька наборів даних, які описують Олімпійські ігри: Olympic Games, 1986–2021, Tokyo 2020 Olympics, Tokyo 2020 Paralympics.
  3. Я цікавлюся спортом. Не вважаю себе експертом, але в багатьох видах спорту розбираюся до дрібниць.
  4. Я вже маю досвід програмування схожих візуалізацій.

Що буде в дописі?
Буде спроба пояснити власні міркування щодо розбору та побудови вибраної візуалізації, аналіз даних та трохи програмування.

Чого ви не знайдете в дописі?
Згадування про види теплокарт та їх використання в інших задачах, опису отриманої візуалізації з боку спорту. Напевно, відповіді на ці питання можуть слугувати матеріалами для двох інших публікацій

Дані

Для цього завдання я буду використовувати власноруч створений набір даних Olympic Games, 1986–2021, який найближчим часом планую розширити атлетами із командних видів спорту та доповнити інформацією про найближчі зимові Олімпійські ігри (Пекін-2022). Він складається із 4-ох таблиць у форматі csv та містить достатньо інформації про змагання та спортсменів, щоб робити різноманітні типи аналізу змагань.

Я не буду зупинятися на всьому наборі, а зверну увагу тільки на ті дані, які є необхідними для виконання поставленого завдання. Як видно із рисунку 1, для цього нам потрібна інформація тільки про види спорту, роки змагань та те чи вони відбувались в конкретний рік. Щоб отримати такі дані, достатньо об’єднати таблиці olympic_medals.csv та olympic_hosts.csv і зробити кілька відносно простих операцій оброблення даних.

Надалі я використовуватиму вже підготовлену таблицю, яка, як на мене, є інтуїтивно зрозумілою (рис. 2). Таблиця містить інформацію про всі розіграні на Олімпійських іграх медалі і це близько 20 тисяч рядків. Кожний із них відповідає окремому атлету чи команді, що виграла медаль. Давайте розглянемо перший рядок таблиці та витягнемо із нього всю доступну інформацію. Кубинський спортсмен Арлен Лопез (чоловік, індивідуальні змагання) здобув золоту медаль із боксу у ваговій категорії 75–81 кг на літніх олімпійських іграх Токіо 2020, Японія.

Для створення візуалізації достатньо 4-ох стовпців із таблиці:

  • game_season — тип Олімпійських ігор (можуть бути літні або зимові);
  • discipline_title— вид спорту;
  • game_year— рік проведення змагань (1986, …, 2020);
  • participant_type—тип учасника (може бути атлет або команда).
Рис. 2. Таблиця всіх медалей розіграних на Олімпійських іграх (10 випадково вибраних рядків).

Аналіз та візуалізація

На основі вхідної візуалізації (рис. 1) та підготовленої таблиці (рис. 2 ), я роблю доволі просте припущення: якщо була розіграна хоча б одна медаль у котромусь із видів спорту, то це означає — він був присутнім на Олімпійських іграх. Отже, спробуймо перевірити це.

Давайте уявимо, що в нас є тільки аркуш паперу, олівець та дані. Було б зручно накреслити сітку, в котрій кожному із рядків відповідає певний вид спорту, а кожній колонці — рік проведення Олімпійських ігор. Тоді взяти один із видів спорту, для прикладу, бокс та перевірити в таблиці із даними чи були в цьому виді спорту розіграні медалі в кожному із років проведення змагань, починаючи 1986 (перші ігри) та закінчуючи 2020 роками.

Кожна знайдена нами медаль є індикатором того, що потрібно взяти олівець та замалювати клітинку на перетині рядка, що відповідає виду спорту та колонки, що відповідає року проведення Олімпійських ігор. І так слід повторювати для кожного виду спорту. Цей спосіб є доволі повільним, оскільки є більше 60-ти видів спорту та близько 20-ти тисяч рядків таблиці. Його можна дещо спростити, якщо спочатку відсортувати дані за видом спорту та роком проведення змагань. Після цього перша замальована клітинка дає можливість пропустити всі решту рядків в таблиці аж до іншого виду спорту чи наступних Олімпійських ігор.

Якби ми не вміли програмувати, то нічого іншого не залишалось, як робити візуалізацію на папері за допомогою вищеописаного способу. Та з тим самим успіхом можна застосувати описаний хід думок до написання коду. Єдина відмінність, яка буде в коді ми одночасно із сортуванням даних виконаємо групування. Це надасть нам додаткові можливості на кроці візуалізації.

Крок 1. Фільтрування

Почнемо з того, що розділимо Олімпійські ігри за типом на зимові та літні. Це доволі просто зробити за допомогою простого фільтру в стовпці game_season. Залишимо дані тільки для літніх змагань. Можна обійтися і без цього кроку тільки тоді всі види спорту перемішаютья. А таким чином зможемо отримати дві різні візуалізації.

df[df['game_season']=='Summer'].reset_index(drop=True)

Крок 2. Групування

Згруповуємо дані, як обговорювали раніше, за видом спорту та роком проведення змагань. В результаті отримаємо значно меншу таблицю, яка містить близько 700-та рядків та всього 3-ох стовпців.

df.groupby(['discipline_title', 'game_year'])['participant_type'].count().reset_index()
Рис. 3. Таблиця медалей зі стрільби з лука. Дані згруповані за видом спорту та роком проведення змагань.

Як видно (рис. 3), зараз перша колонка містить інформацію про вид спорту, друга — про рік проведення змагань, а третя — вже агреговані дані про кількість розіграних медалей. Для кращого наочного сприйняття я залишив тільки ті рядки, які відносяться до одного виду спорту — стрільби із лука.

Ми майже наблизились до кінцевої мети. Якщо уважно глянути, то в нас вже є всі необхідні дані і залишається зробити одне перетворення.

Коректна агрегація даних — це вже половина справи.

Крок 3. Перетворення

Давайте переформатуємо таблицю таким чином, щоб один вид спорту був в одному рядку, а стовпці відповідали рокам проведення змагання. Тоді стовпець #medals відповідно стане рядком та розміститься на перетині перших двох. Для цього достатньо виконати просту операцію:

data.pivot('discipline_title', 'game_year', '#medals').fillna(0).astype(int)

Зараз вже чітко простежується схожість між отриманою таблицею (рис. 4) та вхідною візуалізацією (рис. 1). Тут рядками є види спорту, а колонками — роки проведення змагань. Жовтим кольором я виділив стрільбу з лука, щоб показати, як легко всю табличку (рис. 3) перетворити в один рядок іншої таблиці. Нулі пурпурового кольору позначають роки, в яких змагання не проводились. Для прикладу, з легкої атлетики змагання проводились завжди, a стрільба з лука була відсутня в олімпійській програмі протягом 52-ох років із 1920 до 1972.

Варто відзначити, що 2-ий та 3-ій кроки можна виконати за допомогою однієї функції pivot_table(), але вона дещо складніша для розуміння.

Рис. 4. Таблиця медалей.

Крок 4. Візуалізація

Форма таблиці та наявна інформація (рис. 4) є достатніми умовами для того, щоб повторити початкову інфографіку. Насправді, ми наперед приводили дані до такого формату, щоб побудувати візуалізацією.

sns.heatmap(data, annot=False, cbar=False, 
linewidths=0.8, linecolor='black',
square=True, cmap='Spectral')

Звісно, цей рядок коду не дозволить отримати точно таку саму візуалізацію (рис. 5). Вона буде просто жахлива, якщо не налаштувати інші параметри, хоча ззовні буде доволі схожа. Повний код, як я вже згадував раніше, розміщено в репозиторії проекту на Github.

Давайте порівняємо та поговоримо про основні відмінності між отриманими (рис. 5 та рис. 6) та початковою (рис. 1) візуалізаціями:

  1. Колір. Доступна повна кольорова гамма, за неї відповідає всього один параметр cmap і його легко змінити. Все на свій смак.
  2. Шрифти та додаткові анотації. Можна змінювати та добавляти надписи. Зараз використовуються стандартні шрифти.
  3. Сітка. Краще допомагає побачити перетин виду спорту із роком проведення змагань.
  4. Сортування. Мені більше подобається, коли зверху ті види спорту, які є актуальними зараз, а внизу ті, що раніше були виключені із списку олімпійських видів.
  5. Розділення на літні (рис. 5) та зимові (рис. 6) види спорту. Мені доречніше виглядає мати дві картинки ніж одну.
Рис. 5. Часова діаграма видів спорту присутніх на літніх Олімпійських іграх (1986–2020).
Рис. 6. Часова діаграма видів спорту присутніх на зимових Олімпійських іграх (1924–2018).

Бонус. Візуалізація

Як вже згадувалось у вступі, я б хотів показати ще одну візуалізацію теплокарти. Вона описує медальні досягнення України в часі на Олімпійських іграх за всю історію (рис. 7). Можна легко отримати схожу теплокарту для будь якої іншої країни. Для цього варто скористатися вже готовим кодом із репозиторію. Хоча сама візуалізація доволі схожа до двох попередніх, проте з точки зору візуального сприйняття є кілька особливостей:

  • до кольору додане додаткове кодування числами, що вказує на кількість медалей;
  • присутня гамма кольорів, колір змінюється в залежності від кількості медалей;
  • додано колонку та рядок, які відповідають за загальні кількості медалей у окремому виді спорту чи Олімпійських іграх.
  • форма і розмір комірки залежить від кількості стовпців. В даному випадку це прямокутники.
Рис. 7. Часова діаграма медалей серед різних видів спорту на літніх Олімпійських іграх (1996–2018) для України 🇺🇦 .

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

Статтю, набір даних, проект чи пост можна підтримати, натиснувши на відповідну іконку вподобань для кожного із ресурсів. Для Medium це оплески 🖐 , а для Github — зірочка ⭐️ . І так, це важливо!

Якщо Вам цікава тема спортивної аналітики чи програмування візуалізацій, то буду радий отримати питання тут в коментарях чи в особистих повідомленнях соціальних мереж. Дякую!

--

--