В първата публикация от поредицата за обучение DS4CS споделих кода, използван за създаването на първата ми история за Субсидията за заплати в Канада при извънредни ситуации, която беше корпоративна лудост с исторически мащаби. В тази публикация ще демонстрирам как да създам визуални елементи за историята на CEWS с помощта на ggplot2, като се фокусирам върху диаграми с водещи точки. По пътя ще споделя и няколко съвета за много по-ефективна работа с R, включително итерация с map и как да автоматизирате създаването на диаграми с персонализирани функции.

Ако искате да пресъздадете диаграмите точно както са, можете или да посетите първата публикация и да следвате или да изтеглите архива от .rds файла, използвани за създаване на диаграмите точно тук. Ако сте тук само за функциите, използвани за създаване на диаграмите с водещи точки в статията, не се колебайте да изтеглите R скрипта тук.

Дръж се! Какво е диаграма с куршуми?

Диаграмата с водещи точки е „надстроена версия на стълбовидна диаграма тип бар-в-лента“, създадена от експерта по визуализация на данни и табло за управление Стивън Фю. Булетните диаграми са подходящо надграждане на стълбовидна диаграма в случаи, които изискват сравнение между две количествени променливи, често когато се отнасят до трета групираща променлива. Какво отличава диаграмата с водещи точки от конвенционалната стълбовидна диаграма?

Първо, диаграмите с водещи точки имат много по-висока плътност на информацията в сравнение с подобна групирана стълбовидна диаграма. Допълнителен слой от количествени данни се налага върху данните, представени в лентата, с възможност за „кодиране на още повече информация“ чрез добавяне на отметка за сравнение и попълване на лентите въз основа на качествена мярка.

Сравнението на две количествени променливи в трета променлива за групиране е точно това, което беше необходимо, за да се визуализира корпоративната безплатна за всички, която беше канадската спешна субсидия за заплати. В този случай искаме да сравним две количествени променливи, нетните корпоративни печалби и сумата на получените CEWS, през трета категорична променлива, обозначаваща всяка индустрия.

От Data Viz до Data Storytelling

Би било напълно възможно и валидно – също вероятно по подразбиране в много програми като Excel – тези данни да се визуализират като групирана стълбовидна диаграма, както е показано по-долу, като жълтите ленти означават net_profits, а червените ленти представляващи subsidy, получени от индустрията. Той предава основното послание, повечето индустрии са получили милиарди субсидии, като същевременно са спечелили много повече чиста печалба. Но това не е визуализация с особено силно въздействие във всяко отношение.

Визуализирането на същите данни като диаграма с водещи точки е много по-ефективен начин за извършване на това сравнение. Първо, фината промяна във „визуалното наслояване“ на данните закотвя втората променлива за сравнение в средата на лентата на първата. Това незабавно сигнализира за визуално сравнение за окото на зрителя.

Визуалното наслояване и разликата в ширината на лентата може да се използва за подчертаване на подчинения или йерархичен характер на много сравнения, което в този случай е, че subsidy винаги ще бъде по-малко от net_profits за тази конкретна диаграма. Погледнете нагоре стълбовата диаграма и забележете, че ширината и визуалното тегло на стълбовете са еднакви. Диаграмата с куршуми, от друга страна, придава много по-голяма визуална тежест на лентата, представляваща печалби. Вътрешната лента, представяща държавните субсидии, формира визуалната основа на дебелата лента, представяща капиталистическите печалби. По този начин диаграмата с водещи точки предава визуално истинската история, че печалбата е приоритет в капиталистическия отговор на кризата с COVID.

Освен това форматът на диаграмата с водещи точки позволява добавяне на етикети за стойност, обозначаващи вътрешната лента като процент от външната лента. Гледайки групирана стълбовидна диаграма, често се опитваме да направим това изчисление наум: „Тази лента е какъв процент от тази лента?“ В диаграма с водещи символи, наслояването на стълбовете и начина, по който вътрешната лента закрепва основата на лентата, която вече е насочена към окото на зрителя, за да я види. Този вид етикетиране е интуитивен за лента с куршуми, но би било трудно да се изведе в конвенционална групирана стълбовидна диаграма.

Извличане и подготовка на данните

Използване на map и анонимни функции за итерация в ефективни работни процеси за наука за данни

Първо, започнете както повечето работни потоци за наука за данни, като заредите пакетите, от които се нуждаете, преди повечето от другия ви код. Добра практика е да заредите всички пакети предварително, така че да могат да бъдат споделени в списък със зависимости на пакети, ако искате другите да могат да възпроизвеждат вашия код.

Едно от страхотните неща при преминаването от работни потоци „насочи и щракни“ в софтуер като Excel към функционален скриптов език като R е потенциалът да увеличиш значително ефикасността и ефикасността на работата си, като същевременно намалиш тежестта на прекалено досадни, но общи данни задачи по наука. „Не се повтаряй“ е основен принцип на „доброто кодиране“. Ако дадена част от кода ще бъде репликирана повече от няколко пъти, почти винаги е по-добър избор да използвате функции и/или итерация. Това не само ще ви спести време и усилия чрез автоматизация, но и много главоболия надолу по пътя, тъй като по-сбитият код е много по-малко вероятно да се счупи и по-лесно за отстраняване на грешки, когато това стане.

Итерацията е невероятно често срещана и полезна задача в кодирането и науката за данни. В този контекст „итерация просто означава набор от инструкции“ (напр. извикване на функция, операции), които се повтарят последователно. Използвайки R, е възможно да обхождате почти всеки обект, включително вектори, списъци, променливи на средата, колони и редове на рамки с данни, диаграми и графики, пътеки на файлове, URL адреси, каквото и да е.

Ето прост пример за DRY в действие, използвайки функцията map от абсолютно необходимия purrr пакет. Функцията map приема произволен вектор или списък като първи аргумент .x, а вторият аргумент .f е извикване на функция, която итерира всеки елемент в .x. Вместо да въвеждаме извикването към read_rds и here с пълния път на файла три пъти, можем да използваме анонимна функция в рамките на map до paste вектор от низове cews_paths във файловите пътища, за да импортираме и трите таблици в едно обаждане. Анонимна функция може да бъде дефинирана в движение, без да се налага да я присвоявате на обект в средата. Ако концепцията за анонимна функция е нова за вас, струва си да прочетете кратко въведение тук.

purrr има специален съкратен синтаксис ~, който прави използването на анонимни функции в рамките на извиквания към map още по-лесно и по-сбито. Поставете ~ непосредствено преди извикването на функция .f в map и използвайте .x, за да контролирате къде във функцията ще бъдат поставени елементите, които искате да повторите. Ако това върне грешка обект .x не е намерен, вероятно сте забравили да използвате ~, за да кажете на R, че това е анонимна функция, така че търси действителен обект с име .x и не итерира през елементите, предоставени на .x.

Работа със списъци в R

По подразбиране map ще върне изхода на предоставената функция като list с един елемент за всяка итерация над .x. В този случай, един тибл за всеки път към файла.

## [1] "list"

Работата със списъци може да бъде трудна в началото, но си струва да свикнете с невероятните ползи за работния процес, които ще отключите по пътя. Използвайки purrr:set_names, на всеки тибъл в списъка се присвоява име, което прави работата със списъка малко по-лесна.

## $profits 
## # A tibble: 13 x 4 
## naics_final net_profits subsidy pct_profits 
## <fct> <dbl> <dbl> <dbl> 
## 1 Manufacturing 66407000000 16398789000 0.247 
## 2 Construction 51026000000 11274636000 0.221 
## 3 Arts/Acc/Food/Ent/Rec -5013000000 10584779000 -2.11 
## 
## $size 
## # A tibble: 3 x 6 
## claim_period size_of_applicant applications subsidy pct_total pct_total_subsi~ 
## <chr> <chr> <dbl> <dbl> <dbl> <dbl> 
## 1 All Periods Small (25 or few~ 3352710 2.37e10 0.776 0.256 
## 2 All Periods Medium (26 to 25~ 901540 3.88e10 0.209 0.419 
## 3 All Periods Large (over 250 ~ 56920 3.01e10 0.013 0.325 
## 
## $lobby 
## # A tibble: 50 x 6 
## id ref_date corp ref_year source subsidy 
## <dbl> <date> <chr> <dbl> <chr> <dbl> 
## 1 914017 2021-07-15 Air Canada 2021 Canada Revenue Ag~ 5.86e8 
## 2 911084 2021-04-15 Suncor Energy Inc. 2021 Canada Revenue Ag~ 
## 
# ... with 40 more rows

След като данните бъдат импортирани, се правят някои бързи корекции в последния момент, за да се подготвят данните за чертане. Един от начините за работа със списъци е използването на оператора за подмножество $ за достъп до елементи от списъка по име. В profits tibble нерентабилните индустрии се филтрират (въпреки че могат да бъдат включени в диаграмата с допълнителни усилия) и се задават нивата на факторите в низходящ ред от net_profits. Ние правим последното, защото когато използваме ggplot2 за чертане на фактор, нивата ще бъдат редът на чертане по подразбиране на елементите.

Елементите от списъка също могат да бъдат достъпни чрез цифров индекс list[[n]], както е направено, за да се вземат първите 15 най-големи получатели на CEWS от lobby tibble по-долу.

Майсторска изработка на диаграми с куршуми с ggplot2

Основна структура от данни за диаграма с водещи точки

Основната структура на данните, необходима за създаване на диаграма с водещи точки с ggplot2, е следната:

  • Данните трябва да бъдат под формата на рамка с данни или тибъл
  • Категорична променлива x, която формира категориите на оста
  • Категорична променлива z с етикети за двете количествени променливи
  • Числова променлива y със стойности, свързани с x и z
  • Колона за ширина, обозначаваща променливите ширини на лентите на диаграмата с водещи символи.

Вижте чист пример за данните, създадени от нулата с функцията tibble::tribble, която може да бъде доста полезна, когато трябва да излезете с малки количества ръчно изработени данни набързо.

## # A tibble: 2 x 4 
## x z y width 
## <chr> <chr> <dbl> <dbl> 
## 1 Total, all industries profits 301022000000 0.7 
## 2 Total, all industries subsidy 92794229000 0.3

Използване на граматиката на графиките за изграждане на основна диаграма с топчета

Ако за първи път се доближавате до ggplot2, силно бих препоръчал да се запознаете с „граматиката на графиката“, философия на дизайна, която разбива визуализациите на комбинации от слоеве, съпоставяния, мащаби, координирани и аспекти. Компонентите на графиката могат да се добавят един по един с оператора +, като винаги започват с първоначално извикване на функцията ggplot().

Променливите, които искате да картографирате към естетически резултати, за да направите диаграми, трябва да бъдат предадени на функцията aes() в рамките на извикването на ggplot(). След като естетиката е картографирана с aes, фигурите се добавят към графиката с помощта на geom_ функции, в този случай добавяне на ленти с geom_col() и грабване на ширините на лентите от оригиналния тибъл с $width.

Координатната система на графиката може да се променя с функциите coord_. Видът на произведения график ще варира в зависимост от различните комбинации от геометрия и координати. След като добавите ленти към диаграмата, променете координатите, за да я превърнете в хоризонтална лентова диаграма с coord_flip(). Няма ограничение за броя на geoms, които ggplot може да има, стига те да се съпоставят с вашите данни по валидни начини, но диаграмата (обикновено) може да побере само една координатна система.

Изходът на диаграмата по подразбиране без никакви промени в стила и мащабите обикновено няма да изглежда страхотно. Мащабите на осите и мащабите, нанесени на естетически променливи (напр. цвят, запълване, размер, прозрачност) могат да се добавят и коригират с scale_ функциите от всички типове. Сега можем да добавим персонализирани цветове за запълване с scale_fill_manual и да коригираме единиците на етикетите на мащаба на осите с scale_y_continuous. Вече изглежда малко по-добре.

Добавяне на етикети за стойност към лентови диаграми с водещи символи

Етикети със стойности могат да се добавят към лентови диаграми чрез използване на geom_text и предаване на числовите стойности към естетиката label. За тези диаграми с водещи точки искаме да добавим етикет със стойност, показващ вътрешната лента като процент от външната лента. По подразбиране geom_text ще вмъкне етикети със стойности за всяка серия, но ние искаме да покажем само един етикет за вътрешната лента. Често се случва, когато правите лентови диаграми, да искате да добавите етикети на стойност само към определени ленти, което може да се постигне чрез промяна на аргумента data на извикването на geom_text и филтриране на рамката с данни само за стойностите, които да бъдат изобразени като етикети.

Бързо подобрете външния вид на диаграмата, като приложите функция theme_ от пакета hrbrthemes. Имаме основна диаграма с топчета. Общо канадските корпорации са спечелили над 300 милиарда долара печалби от 2020 г. до третото тримесечие на 2021 г., като същевременно са поели малко под една трета от тази обща сума в CEWS.

Радостта от създаването на диаграми чрез функционално програмиране

Така че вече знаете как да направите диаграма с куршуми от нулата. Но какво ще стане, ако трябва да създадете диаграма с водещи точки за всяка отделна двойка променливи в отчет? Ще трябва ли да копирате и поставите кода за всяка диаграма? Без пот, избягвайте да губите време с дублиране, като напишете функция за автоматизиране на задачата.

Като функционален език за програмиране, функциите са звездата на шоуто в R. Персонализирана функция може да бъде дефинирана чрез присвояване на извикване на function (самата тя е функция) към обект в среда с оператора <-.

По-долу дефинирах функция, която приема рамка с данни като вход, транспонира колоната за сравнение в дълга форма с pivot_longer и вмъква ширините на лентата по група с mutate и rep. Оттам функцията автоматично създава основна стълбовидна диаграма, като поставя входа, уловен от точките ... в третия аргумент, който приема произволен брой входове, в естетическите съпоставяния на ggplot2 до aes.

Когато пишете извикването към function, можете да посочите аргументите, които функцията ще приема като входни данни. Ето как може да се извика функцията на bullet chart с избраните аргументи:

  1. df приема кадър с данни или тибъл
  2. pivot_by обозначава колони с цифров индекс, за да се завърти в по-дълга в една колона за сравнение
  3. ... взема разделени със запетаи имена на променливи като входни данни към aes, за да създаде диаграмата
  4. widths контролира ширината съответно на външната и вътрешната лента. Това е незадължителен аргумент, тъй като му е дадена стойност по подразбиране.

Използване на подредена оценка и персонализирани функции с ggplot2

Нека сдвоим функцията за диаграма с водещи точки с друга функция, за да автоматизираме добавянето на етикетите на стойността с geom_text.

Първо, кратка бележка относно използването на пакети от незаменимия tidyverse (включително ggplot2) във вашите собствени персонализирани функции. За мен разбирането как R оценява аргументите на функциите и след това как да накарам това да работи в tidyverse беше основно препятствие, което трябваше да преодолея при научаването как да пиша и използвам функции. Ако сте начинаещи във функционалното програмиране с R и tidyverse, струва си да прочетете по-подробно за оценката на tidy.

В базата R е необходимо да се използва df$var или df["var"] за препратка към колона от рамка с данни. Това наистина бързо става досадно и объркано. В tidyverse, благодарение на маскирането на данни, можем просто директно да използваме имената на променливите, без да се налага всеки път да подмножаваме рамката с данни с $ или [. За да използваме имена на голи променливи като входове в персонализирани функции, първо трябва да поставим входа в кавички с enquo и след това да го премахнем, за да го използваме в тялото на функцията с оператора за премахване на кавички !!.

Оттам входът към filter_var, също име на променлива без кавички, се преобразува в низ, който да се подаде в filter с помощта на deparse и substitute. Оригиналните данни, използвани за пресъздаване на диаграмата, могат да бъдат извлечени от всеки ggplot обект чрез достъп до ggplot$data, така че ние грабваме оригиналните данни за филтриране от оригиналната диаграма, предадена на plot.

Поставете черешката на тортата със собствената си функция theme

ggplot2 предлага невероятно ниво на персонализиране и контрол върху тематичните елементи на сюжета чрез функцията theme, която може да контролира над 100 различни елемента на сюжета. Използвайте theme, за да приложите финалните щрихи, като контролирате елементи като хоризонтална или вертикална ос, етикети, мрежи, легенди, полета и много други. Също така е възможно да се използва функция за съхраняване и ефективно прилагане на персонализирана тема ggplot, като по-долу.

Добавяне на всичко заедно сега

Тук ще нанижем и трите извиквания на функции, заедно с канали %>%, за да създадем диаграма с водещи символи с различен вид количествени данни, сравнявайки процента CEWS, получен в червено спрямо процента от общите приложения на CEWS в жълтопо размер на предприятието. За да завършите, преобразувайте хоризонталната ос в процентен формат и използвайте анонимна функция (~ няма да работи извън функциите purrr), за да обвиете дългите текстови етикети.

БОНУСНА ТАБЛИЦА и изхвърляне на легенди за фантастичен текст в сюжетни заглавия и субтитри

Но почакай! Все още има още една класация; тази не е нищо като диаграма с куршуми, така че ще я наречем бонус диаграма. Наистина не съм виждал някой да използва диаграма като тази преди, така че не съм сигурен как да я нарека. Стълбовата диаграма с текст като лента може би? Форматът на данните за тази диаграма е идентичен с обикновена стълбовидна диаграма, но вместо да добавяте стълбове с geom_col или geom_bar, използвайте geom_text, за да поставите етикетите на стойностите директно там, където трябва да бъдат стълбовете.

И накрая, но не на последно място, още един горещ съвет относно фантастичния текст на заглавието и легендите за стойността. Обичам да използвам много персонализиран текст в заглавията и подзаглавията на класациите за сайта. Когато е подходящо за данните и визуализацията, обичам да се откажа от използването на цветова легенда и вместо това кодирам стойностите на цветовата скала директно в заглавието или подзаглавието на диаграмата.

Това е възможно с прекрасния пакет ggtext, който значително подобрява поддръжката за изобразяване на текст за ggplot. Използвайки element_markdown, е възможно да включите както markdown, така и html в текста на графиката.

Първоначално публикувано на адрес https://ds4cs.netlify.app на 3 декември 2021 г.