Устранение препятствий при создании графика дождевых облаков

Вступление

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

Выглядит потрясающе, не правда ли? Я был поражен тем, как получился сюжет, хотя я его и сделал!

Обратите внимание, что этот пост построен на великих работах Паулы Андреа Мартинес, Dr. Мика Аллен и Дэвид Робинсон . Таким образом, я не буду изобретать велосипед, описывая все детали сюжета; скорее, я расскажу о некоторых возможных приемах, которые могут вам понадобиться, чтобы такой сюжет соответствовал вашим потребностям.

Подготовка

В качестве примера я буду использовать набор данных из World Value Survey Wave 5. Я убрал набор данных, который вы могли просто git clone отсюда. Краткий обзор набора данных здесь:

Столбец страны содержит 22 уникальных значения страны:

Аргентина, Австралия, Бразилия, Болгария, Канада, Чили, Финляндия, Франция, Грузия, Венгрия, Япония, Мексика, Нидерланды, Норвегия, Польша, Румыния, Сербия, Словения, Швеция, Великобритания, США и Уругвай.

Остальные столбцы соответствуют ответам респондентов на 6 вопросов, касающихся основных характеристик демократии, по шкале от 1 до 10. Например, для каждой переменной, приведенной выше, был вопрос, подобный этому:

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

(1) Правительство налоги для богатых для субсидирования бедных;

(2) Религиозные власти толкуют законы;

Используйте эту шкалу, где 1 означает «совсем не существенная характеристика демократии», а 10 означает, что она определенно является «важной характеристикой демократии».

Еще одна вещь, которая вам понадобится для создания сюжета, - это R-пакет RColorBrewer.

RColorBrewer - это пакет R, который позволяет пользователям создавать красочные графики с предварительно созданными цветовыми палитрами, которые визуализируют данные в четкой и различимой форме. Есть 3 категории палитр: качественные, расходящиеся и последовательные.

Проблема 1

Образец кода, представленный в приведенных выше ссылках, будет работать в большинстве случаев, если у вас нет большого набора данных с множеством групп (в данном случае страны). Однако, когда у вас «много» групп, он обязательно сломается. Значение отсечки составляет около 8–12 в зависимости от конкретной цветовой палитры, которую вы выбираете и вводите в следующий код.

# borrowed from Paula Andrea Martinez's post mentioned above
g <- 
  ggplot(data = name_of_your_data, 
         aes(x = EmotionCondition, y = Sensitivity, fill = EmotionCondition)) +
  geom_flat_violin(position = position_nudge(x = .2, y = 0), alpha = .8) +
  geom_point(aes(y = Sensitivity, color = EmotionCondition), 
             position = position_jitter(width = .15), size = .5, alpha = 0.8) +
  geom_point(data = sumld, aes(x = EmotionCondition, y = mean), 
             position = position_nudge(x = 0.3), size = 2.5) +
  geom_errorbar(data = sumld, aes(ymin = lower, ymax = upper, y = mean), 
                position = position_nudge(x = 0.3), width = 0) +
  expand_limits(x = 5.25) +
  guides(fill = FALSE) +
  guides(color = FALSE) +
  coord_flip() + 
  scale_color_brewer(palette = "Spectral") +
  scale_fill_brewer(palette = "Spectral") +
  theme_bw() +
  raincloud_theme

Таким образом, если у вас есть набор данных, подобный нашему примеру здесь, который много раз вы будете иметь в реальных аналитических настройках, приведенный выше код R сломается и приведет к этой неприятной ошибке:

> g
Error: Insufficient values in manual scale. 22 needed but only 1 provided.

Вы увидите это, потому что ggplot не смог получить достаточно цветов из выбранной нами цветовой палитры (в данном случае «Spectral») для наших 22 групп / стран. Однако все палитры по умолчанию содержали только 8–12 цветов. Таким образом, нам нужно «разрезать» палитру на меньшие интервалы, чтобы создать больше цветов, подходящих для наших групп. Мы могли бы сделать это, вручную «вырезав» палитру по умолчанию и создав новую палитру с помощью функции colorRampPalette.

getPalette = colorRampPalette(RColorBrewer::brewer.pal(8, "Set2"))(22)  
# I set (26) when creating the plot above for better transition of colors.

Это сократит нашу исходную палитру на 22 небольших интервала и извлечет соответствующий цвет. Я пробовал некоторые палитры по умолчанию, и мне больше всего нравится палитра «Set2». На самом деле я создал 26 цветов, а не 22, потому что это позволило бы последним нескольким группам иметь цвета более яркие и насыщенные.

Попробуйте разные палитры и сочетания цветов, которые вам больше всего нравятся :)

Проблема 2

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

Позвольте мне показать вам пример. Сравните следующие цифры с налогом в качестве переменной на первом рисунке и civil_rights на втором.

Рисунок 1 выглядит так, как ожидалось, и мы видим хорошее изображение разброса наших данных.

Рисунок 2 выглядит странно, не правда ли? График плотности выглядит тонким и сжатым, и кажется, что они находятся не в том же масштабе, что и рисунок 1. Но позвольте мне сказать вам, что код для генерации обоих рисунков точно такой же, без каких-либо ошибок!

Проблема заключается в распределении данных и особенностях графика плотности. Переменная civil_rights на рис. 2 намного больше смещена в сторону вершины, чем переменная tax, а это означает, что больше людей считают, что защита гражданских прав определенно является важной характеристикой демократии; чем они думают, что правительство облагает налогами богатых, чтобы субсидировать бедных, как определенно важную характеристику демократии. Медиана для определенной страны в переменной civil_rights составляет почти 9. Такая асимметрия напрямую приводит к тому, что оценка плотности PDF-файла выходит за пределы диапазона 10 и достигает даже 12! Однако график дождевых облаков по умолчанию ограничивает / сокращает плотность на уровне 10, что приводит к потере области плотностей за пределами диапазона 10, в результате чего график плотности выглядит как сжатый и сжатый.

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

g <- 
  ggplot(data = name_of_your_data, 
         aes(x = factor(country), y = tax, fill = factor(country))) +
  geom_flat_violin(position = position_nudge(x = .2, y = 0), trim = TRUE, alpha = .8, scale = "width") +
  geom_point(aes(y = tax, color = factor(country)), 
             position = position_jitter(width = .15), size = .5, alpha = 0.8) +
  geom_boxplot(width = .1, outlier.shape = NA, alpha = 0.5) +
  geom_point(data = sumld, aes(x = factor(country), y = mean), 
             position = position_nudge(x = 0.3), size = 2.5) +
  geom_errorbar(data = sumld, aes(ymin = lower, ymax = upper, y = mean), 
                position = position_nudge(x = 0.3), width = 0)+
  expand_limits(x = 5.25) +
  guides(fill = FALSE) +
  guides(color = FALSE) +
  scale_color_manual(values = getPalette) +
  scale_fill_manual(values = getPalette) +
  #coord_flip() + # flip or not
  theme_bw() +
  raincloud_theme +
  theme(axis.title = element_text(size = 42),
        axis.text=element_text(size=42))

Ключевым моментом здесь является параметр scale = "width". Этот параметр задокументирован здесь. И согласно этому документу:

если «площадь» (по умолчанию), все скрипки имеют одинаковую площадь (до обрезки хвостов). Если «подсчитать», площади масштабируются пропорционально количеству наблюдений. Если «width», все скрипки имеют одинаковую максимальную ширину.

Если мы установим scale = "width", эти две цифры будут выглядеть так:

Мы могли видеть, что графики, особенно рисунок 4, больше не так сжаты, как рисунок 2, и распределение переменной ВНУТРИ каждой страны становится более очевидным. Это именно то, что мы хотим здесь, чтобы понять распределение ВНУТРИ каждой страны. Одно предостережение заключается в том, что, поскольку мы настраиваем одинаковую ширину наибольшей плотности, площадь плотностей не одинакова (даже если это не было на рисунке 2, учитывая, что обрезанная площадь не является постоянной для разных стран). Этот недостаток особенно очевиден в Швеции на рисунке 4. Однако, учитывая, что наша цель - просмотреть распределение ВНУТРИ, а не МЕЖДУ странами, я думаю, что скорректированная версия работает для нас лучше.

Заключение

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

В заключение отметим, что реализацию графика дождевых облаков в Python и Matlab также можно найти здесь.

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

Удачного кодирования!