Візуалізація багатьох змінних в одному графіку


25

Я хотів би показати, як змінюються значення певних змінних (~ 15) з часом, але я також хотів би показати, як змінні відрізняються один від одного в кожному році. Тому я створив цей сюжет:

введіть тут опис зображення

Але навіть при зміні колірної гами або додаванні різних типів ліній / форм це виглядає безладним. Чи є кращий спосіб візуалізації такого роду даних?

Дані тестування з кодом R:

structure(list(Var = structure(c(1L, 2L, 2L, 2L, 2L, 2L, 2L, 
2L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 6L, 
6L, 6L, 6L, 6L, 6L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 8L, 8L, 8L, 8L, 
8L, 8L, 8L, 9L, 9L, 9L, 9L, 9L, 9L, 9L, 11L, 11L, 11L, 11L, 11L, 
11L, 11L, 12L, 12L, 12L, 12L, 12L, 12L, 13L, 14L, 14L, 14L, 14L, 
14L, 14L, 14L, 16L, 16L, 16L, 16L, 16L, 16L, 17L, 17L, 17L, 17L, 
17L, 17L, 17L, 18L, 18L, 18L, 18L, 18L, 18L, 18L), .Label = c("A", 
"B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", 
"O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"), class = "factor"), 
    Year = c(2015L, 1991L, 1993L, 1996L, 2000L, 2004L, 2011L, 
    2015L, 1991L, 1993L, 1996L, 2000L, 2004L, 2011L, 2015L, 1991L, 
    1993L, 1996L, 2000L, 2004L, 2011L, 2015L, 1993L, 1996L, 2000L, 
    2004L, 2011L, 2015L, 1991L, 1993L, 1996L, 2000L, 2004L, 2011L, 
    2015L, 1991L, 1993L, 1996L, 2000L, 2004L, 2011L, 2015L, 1991L, 
    1993L, 1996L, 2000L, 2004L, 2011L, 2015L, 1991L, 1993L, 1996L, 
    2000L, 2004L, 2011L, 2015L, 1993L, 1996L, 2000L, 2004L, 2011L, 
    2015L, 2015L, 1991L, 1993L, 1996L, 2000L, 2004L, 2011L, 2015L, 
    1991L, 1993L, 1996L, 2000L, 2011L, 2015L, 1991L, 1993L, 1996L, 
    2000L, 2004L, 2011L, 2015L, 1991L, 1993L, 1996L, 2000L, 2004L, 
    2011L, 2015L), Val = c(25.6, 22.93, 20.82, 24.1, 24.5, 29, 
    25.55, 24.5, 24.52, 20.73, 25.8, 25.5, 29.5, 27.7, 25.1, 
    25, 24.55, 26.75, 25, 30.5, 27.25, 25.1, 22.4, 27.07, 26, 
    29, 27.2, 24.2, 23, 24.27, 27.68, 27, 30.5, 28.1, 24.9, 23.75, 
    22.75, 27.25, 25, 29, 28.45, 24, 20.25, 17.07, 24.45, 25, 
    28.5, 26.75, 24.9, 21.25, 20.65, 25.1, 24.5, 26.5, 25.35, 
    23.5, 21.93, 26.5, 24.5, 29, 29.1, 26.4, 28.1, 23.75, 26.5, 
    28.05, 27, 30.5, 25.65, 23.3, 23.25, 24.57, 26.07, 27.5, 
    28.85, 27.7, 22, 23.43, 26.88, 27, 30.5, 29.25, 28.1, 23, 
    23.8, 28.32, 27, 29.5, 29.15, 27.6)), row.names = c(1L, 4L, 
5L, 6L, 7L, 8L, 9L, 10L, 13L, 14L, 15L, 16L, 17L, 18L, 19L, 20L, 
21L, 22L, 23L, 24L, 25L, 26L, 27L, 28L, 29L, 30L, 31L, 32L, 35L, 
36L, 37L, 38L, 39L, 40L, 41L, 44L, 45L, 46L, 47L, 48L, 49L, 50L, 
53L, 54L, 55L, 56L, 57L, 58L, 59L, 62L, 63L, 64L, 65L, 66L, 67L, 
68L, 69L, 70L, 71L, 72L, 73L, 74L, 75L, 78L, 79L, 80L, 81L, 82L, 
83L, 84L, 87L, 88L, 89L, 90L, 91L, 92L, 95L, 96L, 97L, 98L, 99L, 
100L, 101L, 104L, 105L, 106L, 107L, 108L, 109L, 110L), na.action = structure(c(2L, 
3L, 11L, 12L, 33L, 34L, 42L, 43L, 51L, 52L, 60L, 61L, 76L, 77L, 
85L, 86L, 93L, 94L, 102L, 103L), .Names = c("2", "3", "11", "12", 
"33", "34", "42", "43", "51", "52", "60", "61", "76", "77", "85", 
"86", "93", "94", "102", "103"), class = "omit"), class = "data.frame", .Names = c("Var", 
"Year", "Val"))

2
Чи можете ви розмістити дані? Досить просто знайти приблизно подібні приклади, але щоб тримати різьблення між собою, люди, які мають ту саму пісочницю, допоможуть. Також, яке значення має зелена зона?
Нік Кокс

Дивіться також пропозиції в stats.stackexchange.com/questions/126480/…
Нік Кокс

@NickCox Звичайно, мав би подумати про це раніше! Я залишив зелену зону, оскільки вона не є істотною (вона показує лише діапазон значень, який вважається "достатнім")

Відповіді:


42

На щастя чи інакше ваш приклад має оптимальну величину (до 7 значень для кожної з 15 груп) спочатку, щоб показати, що існує проблема в графічному плані; по-друге, допускати інші і досить прості рішення. Графік має такий тип , який люди часто називають спагетті у різних сферах, хоча не завжди зрозуміло, чи розуміється цей термін як ласкавий чи образливий. Графік показує колективну чи сімейну поведінку всіх груп, але це досить безнадійно, показуючи деталі, які слід вивчити.

Одна із стандартних альтернатив - просто показати окремі групи на окремих панелях, але це, в свою чергу, може ускладнити точні порівняння груп до групи; кожна група відокремлена від свого контексту від інших груп.

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

введіть тут опис зображення

У цьому випадку висвітлюються деталі можливого практичного чи наукового значення чи інтересу:

  1. У нас є лише одне значення для A і M.

  2. У нас немає всіх значень за всі дані роки у всіх інших випадках.

  3. Деякі групи задумують високі, деякі низькі тощо.

Я не буду намагатися тлумачити тут: дані анонімні, але це стосується дослідника у будь-якому випадку.

Залежно від того, що легко чи можливо у вашому програмному забезпеченні, тут є можливість змінити дрібні деталі, наприклад, чи повторюються мітки та заголовки осей (є прості аргументи "за" і "проти".

Більш важливим питанням є те, наскільки ця стратегія працюватиме в цілому. Кількість груп є основним рушієм, більше, ніж кількість балів у кожній групі. Грубо кажучи, підхід може працювати приблизно до 25 груп (наприклад, 5 x 5 дисплеїв): з більшою кількістю груп графіки не тільки стають меншими та складнішими для читання, але навіть дослідник втрачає схильність сканувати всі панелі. Якби було сотні (тисячі, ...) груп, зазвичай було б важливо вибрати невелику кількість груп для показу. Потрібна деяка суміш критеріїв, таких як вибір деяких "типових" та деяких "крайніх" панелей; що має залежати від цілей проекту та певного уявлення про те, що має сенс для кожного набору даних. Ще один підхід, який може бути ефективним, - це підкреслити невелику кількість серій на кожній панелі. Так, якби було 25 широких груп, кожна широка група могла бути показана разом із усіма іншими як фон. Крім того, може бути деяке усереднення або інше узагальнення. Використання (наприклад) основних або незалежних компонентів також може бути хорошою ідеєю.

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

Деякі посилання на цей підхід [інші вітаються]:

Cox, NJ 2010. Графічні підмножини. Статистичний журнал 10: 670-681.

Knaflic, CN 2015. Розповідь з даними: Посібник із візуалізації даних для бізнес-професіоналів. Hoboken, NJ: Wiley.

Koenker, R. 2005. Квантильна регресія. Кембридж: Кембриджський університетський прес. Див. Pp.12-13.

Schwabish, JA 2014. Посібник економіста щодо візуалізації даних. Журнал економічних перспектив 28: 209-234.

Юнвін, А. 2015. Аналіз графічних даних з Р. Бока Ратон, Флорида: CRC Press.

Wallgren, A., B. Wallgren, R. Persson, U. Jorner, J.-A. Хааланд. 1996. Графічна статистика та дані: Створення кращих графіків. Ньюбері-Парк, Каліфорнія: Сейдж.

Примітка. Графік створено в Stata. subsetplotповинні бути встановлені спочатку за допомогою ssc inst subsetplot. Дані були скопійовані та вставлені з R, а мітки значень були визначені для відображення років як 90 95 00 05 10 15. Основна команда -

subsetplot connected Val Year, by(Var) c(L) lcolor(gs12) backdrop(line) xtitle("") combine(imargin(small)) subset(lcolor(blue) mcolor(blue))

EDIT Додаткові посилання травень, вересень, грудень 2016 року; Квітень, червень 2017, грудень 2018, квітень 2019:

Каїр, А. 2016. Істинне мистецтво: дані, графіки та карти для спілкування. Сан-Франциско, Каліфорнія: Нові вершники. с.211

Camões, J. 2016. Дані на роботі: кращі практики створення ефективних графіків та інформаційної графіки в Microsoft Excel . Сан-Франциско, Каліфорнія: Нові вершники. с.354

Carr, DB та Pickle, LW 2010. Візуалізація шаблонів даних за допомогою мікроскопів. Бока Ратон, штат Флорида: Преса CRC. стор.85.

Грант, Р. 2019. Візуалізація даних: графіки, карти та інтерактивна графіка. Бока Ратон, штат Флорида: Преса CRC. стор.52.

Koponen, J. and Hildén, J. 2019. Довідник з візуалізації даних. Espoo: Aalto ARTS Книги. Див. Стор.101.

Kriebel, A. та Murray, E. 2018. #MakeoverMonday: Покращення того, як ми візуалізуємо та аналізуємо дані, по одній діаграмі за раз. Хобокен, штат Нью-Джерсі: Джон Вілі. с.303.

Rougier, NP, Droettboom, M. and Bourne, PE 2014. Десять простих правил для кращих цифр. Комп'ютерна біологія PLOS 10 (9): e1003833. doi: 10.1371 / journal.pcbi.1003833 посилання тут

Швабіш, Дж. 2017. Кращі презентації: Посібник для науковців, дослідників та виграшів. Нью-Йорк: Columbia University Press. Див. Стор.98.

Wickham, H. 2016. ggplot2: Елегантна графіка для аналізу даних. Чам: Спрінгер. Див. С.157.


+1, чудово, чи є R або SAS функція, яка здатна робити такий тип діаграми? Це справді чудово.
синоптик

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

2
Вибачте, я не маю уявлення про те, як зробити що-небудь в SAS. Безумовно, все, що може зробити Stata, R може зробити це добре чи краще, інакше його користувачі продовжують мені говорити ....
Nick Cox

@NickCox Це зовсім не проблема, я зрозумів, це виглядає дуже добре і ідеально підходить для моєї мети.

@NickCox, ще два посилання: 1. Елементи графічних даних WS Cleveland . Нова книга, 2. Розповідь з даними: Посібник із візуалізації даних для професіоналів бізнесу Коула Нуссбаумера Кнафліка . У цій книзі (№2) є тематичне дослідження глава під назвою "Стратегії уникнення графіка спагетті".
синоптик

22

Як доповнення до відповіді Ніка, ось кілька кодів R для створення подібного сюжету з використанням імітованих даних:

library(ggplot2)

get_df <- function(label="group A", n_obs=10, drift=runif(1)) {
    df <- data.frame(time=seq(1, n_obs), label=label)
    df$y <- df$time * drift + cumsum(rnorm(n_obs))
    return(df)
}
df_list <- lapply(sprintf("group %s", toupper(letters[1:9])),
                  function(label) { get_df(label) })
df <- do.call(rbind, df_list)
df$label2 <- df$label

p <- (ggplot(df, aes(x=time, y=y, group=label2)) +
      geom_line(size=0.9, alpha=0.8,
                data=df[, c("time", "y", "label2")], color="grey") +
      geom_line(size=1.1, color="black") +
      ylab("") +
      theme_bw() +
      theme(panel.border=element_blank()) +
      theme(strip.background=element_blank()) +
      facet_wrap(~ label))
p
ggsave("example_facet.png", p, width=10, height=8)

Приклад сюжету


6

Для тих, хто хоче використовувати ggplot2підхід в R, розглянемо facetshadeфункцію в пакеті extracat. Це пропонує загальний підхід, а не лише для сюжетних ліній. Ось приклад із розсіювачами (з підніжжя цієї сторінки ):

data(olives, package="extracat")
library(scales)
fs1 <- facetshade(data = olives,
                  aes(x = palmitic, y = palmitoleic), f = .~Area)
fs1 + geom_point(colour = alpha("black", 0.05)) +
      geom_point(data = olives, colour = "red") +
      facet_wrap(f=~Area, nrow=3) + theme(legend.position="none")

введіть тут опис зображення


EDIT: Використання модельованого набору даних Адріана з його попередньої відповіді:

library(extracat)
facetshade(df, aes(x=time, y=y), f = .~label, bg.all = FALSE, keep.orig = TRUE) +
           geom_line(aes(x=time, y=y, group=orig.label),colour = alpha(1,0.3)) +
           geom_line(data=df, aes(colour=label), size = 1.2) + xlab("") + ylab("")

Інший підхід - намалювати два окремих шари, один для фону та один для виділених випадків. Хитрість полягає в тому, щоб намалювати фоновий шар за допомогою набору даних без змінної грані. Для даних оливкової олії код:

data(olives, package="extracat")
ggplot(olives, aes(palmitic, palmitoleic)) + 
  facet_wrap(~Area, nrow=3) + 
  geom_point(data=olives %>% select(-Area), colour=alpha("black", 0.05)) + 
  geom_point(data=olives, colour="red") + 
  theme(legend.position="none")

1
Це здається приємним загальним підходом (+1), але конкретний приклад більше стосується іншої проблеми. Купа повторних сюжетних розкидів з різно виділеними регіонами не допоможе на питання, яке стосується часового ряду.
Секст Емпірік

@martin Насправді це так, і це теж рішення Адріана. Зауважте, що він використовує дві однакові змінні мітки, щоб можна було скинути їх у фоновий шар. Ідея кодування є більш очевидною внизу нотатками підрядності, і, як це часто, елегантне форматування графіки може замаскувати важливі частини коду. ggplot(df %>% select(-label), aes(x=time, y=y, group=label2)) + geom_line(alpha=0.8, color="grey") + labs(y=NULL) + geom_line(data=df, color="red") + facet_wrap(~ label)
Ентоні Юнвін

5

Ось рішення, натхнене гл. 11.3, розділ "Дані про житло в Техасі", в книзі Хедлі Вікхема про ggplot2 . Тут я підганяю лінійну модель до кожного часового ряду, беру залишки (які зосереджені навколо середнього значення 0) і малюю підсумкову лінію іншим кольором.

library(ggplot2)
library(dplyr)
#works with dplyr version 0.4.3.9000 from Github (hadley/dplyr@4f2d7f8), or higher

df1 <- as.data.frame(list(Var = structure(c(1L, 2L, 2L, 2L, 2L, 2L, 2L, 
                                 2L, 3L, 3L, 3L, 3L, 3L, 3L, 3L, 5L, 5L, 5L, 5L, 5L, 5L, 5L, 6L, 
                                 6L, 6L, 6L, 6L, 6L, 7L, 7L, 7L, 7L, 7L, 7L, 7L, 8L, 8L, 8L, 8L, 
                                 8L, 8L, 8L, 9L, 9L, 9L, 9L, 9L, 9L, 9L, 11L, 11L, 11L, 11L, 11L, 
                                 11L, 11L, 12L, 12L, 12L, 12L, 12L, 12L, 13L, 14L, 14L, 14L, 14L, 
                                 14L, 14L, 14L, 16L, 16L, 16L, 16L, 16L, 16L, 17L, 17L, 17L, 17L, 
                                 17L, 17L, 17L, 18L, 18L, 18L, 18L, 18L, 18L, 18L), .Label = c("A", 
                                                                                               "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", 
                                                                                               "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"), class = "factor"), 
               Year = c(2015L, 1991L, 1993L, 1996L, 2000L, 2004L, 2011L, 
                        2015L, 1991L, 1993L, 1996L, 2000L, 2004L, 2011L, 2015L, 1991L, 
                        1993L, 1996L, 2000L, 2004L, 2011L, 2015L, 1993L, 1996L, 2000L, 
                        2004L, 2011L, 2015L, 1991L, 1993L, 1996L, 2000L, 2004L, 2011L, 
                        2015L, 1991L, 1993L, 1996L, 2000L, 2004L, 2011L, 2015L, 1991L, 
                        1993L, 1996L, 2000L, 2004L, 2011L, 2015L, 1991L, 1993L, 1996L, 
                        2000L, 2004L, 2011L, 2015L, 1993L, 1996L, 2000L, 2004L, 2011L, 
                        2015L, 2015L, 1991L, 1993L, 1996L, 2000L, 2004L, 2011L, 2015L, 
                        1991L, 1993L, 1996L, 2000L, 2011L, 2015L, 1991L, 1993L, 1996L, 
                        2000L, 2004L, 2011L, 2015L, 1991L, 1993L, 1996L, 2000L, 2004L, 
                        2011L, 2015L), 
               Val = c(25.6, 22.93, 20.82, 24.1, 24.5, 29, 
                       25.55, 24.5, 24.52, 20.73, 25.8, 25.5, 29.5, 27.7, 25.1, 
                       25, 24.55, 26.75, 25, 30.5, 27.25, 25.1, 22.4, 27.07, 26, 
                       29, 27.2, 24.2, 23, 24.27, 27.68, 27, 30.5, 28.1, 24.9, 23.75, 
                       22.75, 27.25, 25, 29, 28.45, 24, 20.25, 17.07, 24.45, 25, 
                       28.5, 26.75, 24.9, 21.25, 20.65, 25.1, 24.5, 26.5, 25.35, 
                       23.5, 21.93, 26.5, 24.5, 29, 29.1, 26.4, 28.1, 23.75, 26.5, 
                       28.05, 27, 30.5, 25.65, 23.3, 23.25, 24.57, 26.07, 27.5, 
                       28.85, 27.7, 22, 23.43, 26.88, 27, 30.5, 29.25, 28.1, 23, 
                       23.8, 28.32, 27, 29.5, 29.15, 27.6)), 
               row.names = c(1L, 4L, 
                           5L, 6L, 7L, 8L, 9L, 10L, 13L, 14L, 15L, 16L, 17L, 18L, 19L, 20L, 
                           21L, 22L, 23L, 24L, 25L, 26L, 27L, 28L, 29L, 30L, 31L, 32L, 35L, 
                           36L, 37L, 38L, 39L, 40L, 41L, 44L, 45L, 46L, 47L, 48L, 49L, 50L, 
                           53L, 54L, 55L, 56L, 57L, 58L, 59L, 62L, 63L, 64L, 65L, 66L, 67L, 
                           68L, 69L, 70L, 71L, 72L, 73L, 74L, 75L, 78L, 79L, 80L, 81L, 82L, 
                           83L, 84L, 87L, 88L, 89L, 90L, 91L, 92L, 95L, 96L, 97L, 98L, 99L, 
                           100L, 101L, 104L, 105L, 106L, 107L, 108L, 109L, 110L), 
               na.action = structure(c(2L, 
                          3L, 11L, 12L, 33L, 34L, 42L, 43L, 51L, 52L, 60L, 61L, 76L, 77L, 
                          85L, 86L, 93L, 94L, 102L, 103L), 
                .Names = c("2", "3", "11", "12","33", "34", "42", "43", "51", "52", "60", 
                           "61", "76", "77", "85", "86", "93", "94", "102", "103"), class = "omit"), 
                class = "data.frame", .Names = c("Var","Year", "Val"))


df1 %>%
        group_by(Var) %>%
        do(mutate(.,resid = resid(lm(Val ~ Year, data=., na.action = na.exclude)))) %>%
        ggplot(aes(Year, resid)) +
        labs(y=paste0("Val "), x="Year") +
        geom_line(aes(group = Var), alpha = 1/5) +
        geom_line(stat = "summary", fun.y = "mean", colour = "red")

введіть тут опис зображення


1
Головною ідеєю тут здається, що ви можете додати якусь підсумкову криву, щоб допомогти зору та розуму. Погодились, але у своїй відповіді ви могли прописати компроміс при зміщенні на середній (або контрольний рівень) 0, а не залишати початкові одиниці та значення. Експерти з тематики та / або клієнти цілком можуть подумати з точки зору 24 або 28 або будь-яких цінностей. Звичайно, дані тут є лише засобом для обговорення, але питання є загальним.
Нік Кокс
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.