首页 > 解决方案 > 如何将 geom_point 创建的散点图的所有点相互连接?

问题描述

我正在尝试在足球场上绘制传球网络。清理数据后它看起来像这样

structure(list(surname_sender = c("Ajite", "Dikmen", "Dikmen", 
"Dikmen", "Dikmen", "Jylmaz", "Jylmaz", "Jylmaz", "Kandejas", 
"Kandejas", "Kandejas", "Kandejas", "Kizildag", "Kizildag", "Kizildag", 
"Kizildag", "Kizildag", "Motta", "Motta", "Motta", "Motta", "Motta", 
"Motta", "Nordfel'dt", "Nordfel'dt", "Poloma", "Sio", "Ture", 
"Ture", "Ture", "Ture", "Ture", "Uhansson", "Uhansson", "Uhansson", 
"Uhansson"), surname_receiver = c("Poloma", "Kizildag", "Poloma", 
"Ture", "Uhansson", "Kandejas", "Poloma", "Uhansson", "Motta", 
"Nordfel'dt", "Ture", "Uhansson", "Dikmen", "Motta", "Nordfel'dt", 
"Ture", "Uhansson", "Dikmen", "Jylmaz", "Kizildag", "Poloma", 
"Ture", "Uhansson", "Ture", "Uhansson", "Ture", "Dikmen", "Jylmaz", 
"Kandejas", "Kizildag", "Motta", "Poloma", "Kandejas", "Kizildag", 
"Sio", "Uhansson"), passes = c(4L, 4L, 4L, 4L, 6L, 4L, 5L, 4L, 
4L, 5L, 4L, 9L, 10L, 6L, 4L, 5L, 8L, 5L, 4L, 6L, 4L, 4L, 5L, 
4L, 6L, 13L, 5L, 5L, 4L, 9L, 8L, 7L, 14L, 8L, 5L, 4L), mean_passer_x = c(64.7, 
44.41875, 44.41875, 44.41875, 44.41875, 68.725, 68.725, 68.725, 
75.2919444444445, 75.2919444444445, 75.2919444444445, 75.2919444444445, 
29.5423333333333, 29.5423333333333, 29.5423333333333, 29.5423333333333, 
29.5423333333333, 44.31, 44.31, 44.31, 44.31, 44.31, 44.31, 8.60416666666667, 
8.60416666666667, 58.6384615384615, 52.46, 38.2090952380952, 
38.2090952380952, 38.2090952380952, 38.2090952380952, 38.2090952380952, 
51.7642857142857, 51.7642857142857, 51.7642857142857, 51.7642857142857
), mean_passer_y = c(46.9, 38.7083333333333, 38.7083333333333, 
38.7083333333333, 38.7083333333333, 35.3533333333333, 35.3533333333333, 
35.3533333333333, 10.7833333333333, 10.7833333333333, 10.7833333333333, 
10.7833333333333, 23.6785, 23.6785, 23.6785, 23.6785, 23.6785, 
34.6552777777778, 34.6552777777778, 34.6552777777778, 34.6552777777778, 
34.6552777777778, 34.6552777777778, 32.2166666666667, 32.2166666666667, 
65.3, 25.7, 46.9388571428571, 46.9388571428571, 46.9388571428571, 
46.9388571428571, 46.9388571428571, 7.25, 7.25, 7.25, 7.25)), row.names = c(NA, 
-36L), class = c("tbl_df", "tbl", "data.frame"))

我发现的解决方案似乎很无聊和愚蠢:)

library(tidyverse)
library(ggsoccer)
library(ggrepel)

 ggplot(df2, aes(mean_passer_x, mean_passer_y)) +
   annotate_pitch(dimensions = pitch_custom) +
  geom_point(color = "red") +
  geom_line(aes(mean_passer_x, mean_passer_y, size = passes, alpha = 0.2),
              data = . %>% filter(surname_sender %in% c("Motta", "Kizildag"))) +
  geom_line(aes(mean_passer_x, mean_passer_y, size = passes, alpha = 0.2),
            data = . %>% filter(surname_sender %in% c("Motta", "Uhansson"))) +
  geom_line(aes(mean_passer_x, mean_passer_y, size = passes, alpha = 0.2),
            data = . %>% filter(surname_sender %in% c("Motta", "Ture"))) +
  geom_line(aes(mean_passer_x, mean_passer_y, size = passes, alpha = 0.2),
            data = . %>% filter(surname_sender %in% c("Motta", "Sio"))) +
  geom_line(aes(mean_passer_x, mean_passer_y, size = passes, alpha = 0.2),
            data = . %>% filter(surname_sender %in% c("Motta", "Dikmen"))) +
  geom_line(aes(mean_passer_x, mean_passer_y, size = passes, alpha = 0.2),
            data = . %>% filter(surname_sender %in% c("Motta", "Kandejas"))) +
  geom_line(aes(mean_passer_x, mean_passer_y, size = passes, alpha = 0.2),
            data = . %>% filter(surname_sender %in% c("Motta", "Jylmaz"))) +
  geom_line(aes(mean_passer_x, mean_passer_y, size = passes, color= "red", alpha = 0.2),
            data = . %>% filter(surname_sender %in% c("Kizildag", "Ture"))) +
  geom_line(aes(mean_passer_x, mean_passer_y, size = passes, color= "red", alpha = 0.2),
            data = . %>% filter(surname_sender %in% c("Nordfel'dt", "Ture"))) +
  geom_line(aes(mean_passer_x, mean_passer_y, size = passes, color= "red", alpha = 0.2),
            data = . %>% filter(surname_sender %in% c("Nordfel'dt", "Kizildag"))) +
  geom_text(aes(label = surname_sender) ) +
  theme_pitch() 

最终结果是

在此处输入图像描述

我要做的就是通过线将所有点(玩家)相互连接,并根据传球次数定义线的大小。

非常感谢

标签: rggplot2

解决方案


不完全确定您的最终结果。但是,据我所知,在您绘制传递网络之前,您的数据需要进行一些额外的处理。问题是您的 df 的每一行仅包含“发送者”的位置,而不包含接收者的位置。所以

  1. 我首先提取了所有玩家的姓名和(平均)位置
  2. 我加入数据集,位置回到你原来的df,我加入接收球员的名字。因此,每一行现在都包含发送和接收玩家的位置。
  3. 这样做之后,您可以通过使用geom_segment和映射passeson size 的数量来轻松绘制网络。此外,我映射了surname_receiver颜色以使通道的方向可见。
library(ggplot2)
library(ggsoccer)
library(ggrepel)
library(dplyr)

pos_player <- df2 %>% 
  select(name = surname_sender, pos_x = mean_passer_x, pos_y = mean_passer_y) %>% 
  distinct()

df2 %>% 
  left_join(pos_player, by = c("surname_receiver" = "name")) %>% 
  group_by(surname_sender) %>% 
  mutate(is_label = row_number() == 1) %>% 
  arrange(desc(passes)) %>% 
  ggplot(aes(x = mean_passer_x, y = mean_passer_y)) +
  annotate_pitch() +
  geom_segment(aes(xend = pos_x, yend = pos_y, size = passes, color = surname_sender), alpha = 0.5) +
  geom_point(color = "red") +
  ggrepel::geom_text_repel(aes(label = ifelse(is_label, surname_sender, "")) ) +
  scale_color_brewer(type = "qual", palette = "Set3") +
  theme_pitch()


推荐阅读