Добавление средней или срединной линии к графику плотности, которая заканчивается внутри области графика

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

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

Вот код для демонстрации:

iris <- as.data.table(iris)

iris_summary <- iris[, .(sepal_mean = mean(Sepal.Length),
                                   sepal_se_low = mean(Sepal.Length) - sd(Sepal.Length) / sqrt(length(Sepal.Length)),
                                   sepal_se_high = mean(Sepal.Length) + sd(Sepal.Length) / sqrt(length(Sepal.Length))),
                                    Species]
unique(iris$Species)
x.dens.s <- density(iris[Species == "setosa", Sepal.Length])
x.dens.ve <- density(iris[Species == "versicolor", Sepal.Length])
x.dens.vi <- density(iris[Species == "virginica", Sepal.Length])
df.dens <- data.table(x = c(x.dens.s$x, x.dens.ve$x, x.dens.vi$x), y = c(x.dens.s$y, x.dens.ve$y, x.dens.vi$y))
df.dens$Species <- c(rep("setosa", length(x.dens.s$y)), rep("versicolor", length(x.dens.ve$y)),
                 rep("virginica", length(x.dens.vi$y)))

iris_density <- 
  ggplot() +
  geom_density(data=iris, aes(x=Sepal.Length,fill=Species),alpha=0.5) +
  geom_area(data = df.dens[Species == "setosa" & 
                             x %between% c(iris_summary[Species == "setosa", sepal_se_low], 
                                           iris_summary[Species == "setosa", sepal_se_high]),],  
            aes(x=x,y=y), fill = "white", alpha = 0.5) +
  geom_area(data = df.dens[Species == "versicolor" & 
                             x %between% c(iris_summary[Species == "versicolor", sepal_se_low], 
                                           iris_summary[Species == "versicolor", sepal_se_high]),],  
            aes(x=x,y=y), fill = "white", alpha = 0.5) +
  geom_area(data = df.dens[Species == "virginica" & 
                             x %between% c(iris_summary[Species == "virginica", sepal_se_low], 
                                           iris_summary[Species == "virginica", sepal_se_high]),],  
            aes(x=x,y=y), fill = "white", alpha = 0.5)  + 
  geom_vline(data = iris_summary, 
             aes(xintercept = sepal_mean, color = Species), linetype = 2, 
             linewidth = 0.7, color = "black")
  
iris_density

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
0
55
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

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

library(data.table)
library(ggplot2)
library(dplyr)
#> 
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:data.table':
#> 
#>     between, first, last
#> The following objects are masked from 'package:stats':
#> 
#>     filter, lag
#> The following objects are masked from 'package:base':
#> 
#>     intersect, setdiff, setequal, union

iris <- as.data.table(iris)

iris_summary <- iris[, .(sepal_mean = mean(Sepal.Length),
                                   sepal_se_low = mean(Sepal.Length) - sd(Sepal.Length) / sqrt(length(Sepal.Length)),
                                   sepal_se_high = mean(Sepal.Length) + sd(Sepal.Length) / sqrt(length(Sepal.Length))),
                                    Species]

unique(iris$Species)
#> [1] setosa     versicolor virginica 
#> Levels: setosa versicolor virginica
x.dens.s <- density(iris[Species == "setosa", Sepal.Length])
x.dens.ve <- density(iris[Species == "versicolor", Sepal.Length])
x.dens.vi <- density(iris[Species == "virginica", Sepal.Length])
df.dens <- data.table(x = c(x.dens.s$x, x.dens.ve$x, x.dens.vi$x), y = c(x.dens.s$y, x.dens.ve$y, x.dens.vi$y))
df.dens$Species <- c(rep("setosa", length(x.dens.s$y)), rep("versicolor", length(x.dens.ve$y)),
                 rep("virginica", length(x.dens.vi$y)))

## Add mean value to density dataset
df.dens <- left_join(df.dens, iris_summary)
#> Joining with `by = join_by(Species)`

## Find y-value at mean value
yend <- df.dens |> 
  group_by(Species) |> 
  filter(round(x, 2) == round(sepal_mean, 2)) |> 
  summarise(yend = mean(y))

## Plot
iris_density <- 
  ggplot() +
  geom_density(data=iris, aes(x=Sepal.Length,fill=Species),alpha=0.5) +
  geom_area(data = df.dens[Species == "setosa" & 
                             x %between% c(iris_summary[Species == "setosa", sepal_se_low], 
                                           iris_summary[Species == "setosa", sepal_se_high]),],  
            aes(x=x,y=y), fill = "white", alpha = 0.5) +
  geom_area(data = df.dens[Species == "versicolor" & 
                             x %between% c(iris_summary[Species == "versicolor", sepal_se_low], 
                                           iris_summary[Species == "versicolor", sepal_se_high]),],  
            aes(x=x,y=y), fill = "white", alpha = 0.5) +
  geom_area(data = df.dens[Species == "virginica" & 
                             x %between% c(iris_summary[Species == "virginica", sepal_se_low], 
                                           iris_summary[Species == "virginica", sepal_se_high]),],  
            aes(x=x,y=y), fill = "white", alpha = 0.5)  + 
  geom_segment(aes(x = iris_summary$sepal_mean, y = 0, yend = yend$yend), linetype = 2)

  
iris_density

Created on 2024-08-29 with reprex v2.1.0

Красивый! Если кому-то нужно решение data.table, оно имеет те же принципы, но определяет строку, для которой y наиболее близок к sepal_mean (без округления) ## Add mean value to density dataset df.dens <- merge(df.dens, iris_summary) ## Find y-value closest to sepal_mean yend <- df.dens[, .SD[which.min(abs(x - sepal_mean))], by = Species][, .(yend = y), Species]

HarD 29.08.2024 15:38

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

library(dplyr)
Maximums_statistic <- iris %>% group_by(Species) %>% 
    #Calculate your desired statistic (mean, median) and the densities
      reframe(Mean = mean(Sepal.Length), 
             density.x = (density(Sepal.Length))$x,
             density.y = (density(Sepal.Length))$y) %>%
    #Select the closest x value to your mean 
      mutate(Closest_x = abs(Mean - density.x)) %>% 
      group_by(Species) %>% 
#Which height value corresponds to this x value?
mutate(Corresponding_y = density.y[which(Closest_x == min(Closest_x))]) %>% 
      select(Species, Mean, Height = Corresponding_y) %>% distinct()

С помощью этого фрейма данных теперь вы можете заново построить график, используя geom_segment, а не полную вертикальную линию:

iris_density <- 
    ggplot() +
    geom_density(data=iris, aes(x=Sepal.Length,fill=Species),alpha=0.5) +
    geom_area(data = df.dens[Species == "setosa" & 
                                 x %between% c(iris_summary[Species == "setosa", sepal_se_low], 
                                               iris_summary[Species == "setosa", sepal_se_high]),],  
              aes(x=x,y=y), fill = "white", alpha = 0.5) +
    geom_area(data = df.dens[Species == "versicolor" & 
                                 x %between% c(iris_summary[Species == "versicolor", sepal_se_low], 
                                               iris_summary[Species == "versicolor", sepal_se_high]),],  
              aes(x=x,y=y), fill = "white", alpha = 0.5) +
    geom_area(data = df.dens[Species == "virginica" & 
                                 x %between% c(iris_summary[Species == "virginica", sepal_se_low], 
                                               iris_summary[Species == "virginica", sepal_se_high]),],  
              aes(x=x,y=y), fill = "white", alpha = 0.5)  + 
# This part is new
    geom_segment(data = Maximums_statistic, 
aes(x = Mean, xend = Mean, y = Height, yend = 0),
 linetype = 2, linewidth = 0.7, color = "black")

Надеюсь, это поможет!

Другие вопросы по теме