{"id":3569,"date":"2023-03-15T01:51:35","date_gmt":"2023-03-15T01:51:35","guid":{"rendered":"https:\/\/hub.salford.ac.uk\/psytech\/?page_id=3569"},"modified":"2023-03-15T17:03:23","modified_gmt":"2023-03-15T17:03:23","slug":"data-visualisation-performance-visualisation-in-r","status":"publish","type":"page","link":"https:\/\/hub.salford.ac.uk\/psytech\/psytechsalford\/learn-programming\/performance-visualisation-r\/data-visualisation-performance-visualisation-in-r\/","title":{"rendered":"Data Visualisation &#8211; Performance Visualisation in R"},"content":{"rendered":"<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"255\" height=\"198\" src=\"https:\/\/hub.salford.ac.uk\/psytech\/wp-content\/uploads\/sites\/95\/2022\/06\/image-15.png\" alt=\"\" class=\"wp-image-2988\" \/><\/figure>\n<\/div>\n\n\n<p>  <\/p>\n\n\n\n<h2 class=\"has-large-font-size wp-block-heading\">Lesson tasks:<\/h2>\n\n\n\n<ul class=\"bold wp-block-list\" style=\"font-size:25px\">\n<li><strong>Create a scatterplot<\/strong><\/li>\n\n\n\n<li class=\"bold\"><strong>Create a shot map<\/strong><\/li>\n<\/ul>\n\n\n\n<p class=\"has-text-align-center\"><em>If you are visiting this lesson independently, at the bottom of the page is the code in full with more detailed comments.<\/em><\/p>\n\n\n\n<p class=\"has-medium-font-size\">Get started by downloading and opening the R project file from the <a href=\"https:\/\/testlivesalfordac.sharepoint.com\/:f:\/s\/PsyTech\/Ektl32BpbsRFlElCods0R1gBcWgOncCtnUmKzZKwzbq_iQ?e=8LtcBM\" target=\"_blank\" rel=\"noreferrer noopener\">course files (opens in new tab)<\/a>. <\/p>\n\n\n\n<p class=\"has-medium-font-size\">As always, the first thing we need to do is load the packages we&#8217;ll be using. We&#8217;ve used the tidyverse before. Previously we&#8217;ve not used ggrepel or ggsoccer before, these packages assist with creating visualisations.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Load packages\nif (require(\"tidyverse\") == FALSE) {\n  install.packages(\"tidyverse\")\n}\nlibrary(tidyverse)\n#--\nif (require(\"ggrepel\") == FALSE) {\n  install.packages(\"ggrepel\")\n}\nlibrary(ggrepel)\n#--\nif (require(\"ggsoccer\") == FALSE) {\n  install.packages(\"ggsoccer\")\n}\nlibrary(ggsoccer)<\/code><\/pre>\n\n\n\n<p class=\"has-medium-font-size\">Let&#8217;s store the data sets we processed in the last lesson into variables for us to use. The data is from the UEFA Women&#8217;s Euro 2022. <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Load data sets\nshot_data &lt;- read.csv(\"shot_data.csv\", encoding = \"latin1\")\nsummary &lt;- read.csv(\"summary.csv\", encoding = \"latin1\")<\/code><\/pre>\n\n\n\n<p class=\"has-medium-font-size\">Since this lesson is preplanned, I can tell you that the is_goal column needs to be a factor data type. We used the class() function in the first lesson to find out the data type and we can do that again!<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># find out the data type of is_goal using class()\n# The dollar $ sign is used to specify a column  in a dataframe. \n# shot_data$is_goal is assessing the is_goal column from the shot_data variable.\nclass(shot_data$is_goal)\n# class() will return that is_goal is a interger \n# We can change the data type of is_goal to a factor \n#with the as.factor() function.\nshot_data$is_goal &lt;- as.factor(shot_data$is_goal) <\/code><\/pre>\n\n\n\n<p class=\"has-medium-font-size\">Everything is *almost* done to start creating a scatterplot. We can, of course, plot the whole data set. Although it&#8217;s not in the spirit of creating visualisations that can easily be interpreted. For ease to begin with, let&#8217;s take the first 15 rows of the summary data set and plot them. Note how we&#8217;re saving those 15 rows into a new variable, this is so we can preserve the summary dataset as a whole for future manipulations.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>scatterplot_summary &lt;- head(summary, n = 15)  <\/code><\/pre>\n\n\n\n<p class=\"has-medium-font-size\">We have our data for the plot sorted, now let&#8217;s create the plot! We&#8217;re going to start basic and built up. Below is the minimum you need for a very basic (and not very helpful) scatterplot. Think of ggplot() as a canvas on which we put the data then we add geom_point() which are the dots that appear on the canvas.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># The minimum requirements you need to make a scatterplot\nggplot(data = scatterplot_summary,  # Using the data we filtered \n       aes(x = shots,               # On the x axis shots will be plot\n           y = goals)) +            # On the y axis goals will be plot\n  geom_point() \n\n# Save the plot\nggsave(\n  plot = last_plot(),\n  \"bare_scatter_plot.png\",\n  dpi = 320,\n  height = 10,\n  width = 12)<\/code><\/pre>\n\n\n\n<p class=\"has-text-align-center\"><em>Note: In this example, we are plotting shots and goals in their absolute value form which as mentioned in the previous lesson isn&#8217;t ideal data to use to compare players since it doesn&#8217;t account for differences in time each player has had on the pitch. When you create your own scatterplot please use the per 90 columns of data!<\/em><\/p>\n\n\n\n<p class=\"has-medium-font-size\">The scatterplot created from the above code while being a scatterplot doesn&#8217;t tell us any useful information. Let&#8217;s add some labels, we do that by adding the geom_text_repel() function <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ggplot(data = scatterplot_summary, #using same data, x, and y as above.\n       aes(x = shots,\n           y = goals)) +\n  geom_point() +\n  geom_text_repel(\n    aes(label = player.name), # Labels the data point with the player name.\n    max.overlaps = getOption(\"ggrepel.max.overlaps\", default = 20), # Here we\n    # state how many points of the plot can have overlaping values.\n    box.padding = unit(0.35, \"lines\"), # Increasing the 0.35 value will create\n    # more space around the player name label.\n    point.padding = unit(0.3, \"lines\"), # Will increase the space around\n    # the data points.\n    arrow = arrow(length = unit(0.01, 'npc')) # Adds an arrow if the label is\n    # far away from the data point.\n  ) \n\n# Save the plot\nggsave(\n  plot = last_plot(),\n  \"labeled_scatter_plot.png\",\n  dpi = 320,\n  height = 10,\n  width = 12)<\/code><\/pre>\n\n\n\n<p class=\"has-medium-font-size\">One of the reasons R is so popular for creating visualisation is because of the amount of customisability you have. We can change the colour of the points, add labels, add a regression line, and this only touches the surface. <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ggplot(data = scatterplot_summary, #using same data, x, and y as before.\n       aes(x = shots,\n           y = goals)) +\n  geom_point(color = 'blue') + # We can change the data points to be blue.\n  geom_smooth(method = lm, color = \"red\") + # This line of code adds a \n  # regression line.\n  geom_text_repel(\n    aes(label = player.name), # Labels the data point with the player name.\n    max.overlaps = getOption(\"ggrepel.max.overlaps\", default = 20), # Here we\n    # state how many points of the plot can have overlaping values.\n    box.padding = unit(0.35, \"lines\"), # Increasing the 0.35 value will create\n    # more space around the player name label.\n    point.padding = unit(0.3, \"lines\"), # Will increase the space around\n    # the data points.\n    arrow = arrow(length = unit(0.01, 'npc')) # Adds an arrow if the label is\n    # far away from the data point.\n  )  +\n  labs( # We can add labels that give the plot a title and a caption.\n    title = \"UEFA Women's Euro 2022\",\n    caption = \"Data: StatsBomb\")\n\n# Save the plot\nggsave(\n  plot = last_plot(),\n  \"customised_scatter_plot.png\",\n  dpi = 320,\n  height = 10,\n  width = 12)<\/code><\/pre>\n\n\n\n<p class=\"has-medium-font-size\">Hopefully, you&#8217;re seeing that using ggplot() is more friendly than it may initially look. We will do one more example together before you create your own. Let&#8217;s say we want to compare the shots and goals of players on different teams. Let&#8217;s apply a different filter to the data being stored in the scatterplot_summary variable. <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># Filter data that will be used in the scatterplot.\nscatterplot_summary &lt;- summary %&gt;% \n  filter(shots &gt; 0) %&gt;% # Removing players who =haven't made any shots.\n  # Keeping plays that are in Sweden's or England's team.\n  # The | operator is the or operator. Therefore the code keeps \n  # plays in the data set that belong to Sweden or England.\n  filter(team.name == \"Sweden Women's\" | team.name == \"England Women's\")\n\n \n# Create the scatterplot\nggplot(data = scatterplot_summary, # Using same data variable (although \n                                   #filtered differently this time!)\n                                   # Still using same variables in x, \n           aes(x = shots,          # and y as before.\n           y = goals)) +\n  geom_point((aes(colour = team.name))) + # Setting the colour of the \n                                         # data points to corospond to team.name. \n  # The scale_color_manual() store what colour the each teams data\n  # points will be.\n  scale_color_manual(values = c(\"Sweden Women's\" = \"yellow\", \"England Women's\" = \"red\")) + \n  geom_smooth(method = lm) + \n  geom_text_repel(\n    aes(label = player.name),\n    max.overlaps = getOption(\"ggrepel.max.overlaps\", default = 20),\n    box.padding = unit(0.8, \"lines\"), # really had to fiddle with this \n   # value in order to see the lables\n    point.padding = unit(0.3, \"lines\"),\n    arrow = arrow(length = unit(0.01, 'npc'))\n  ) +\n  labs(title = \"UEFA Women's Euro 2022\",\n       caption = \"Data: StatsBomb\")\n\n# Save the plot\nggsave(\n  plot = last_plot(),\n  \"team_comparison_scatter_plot.png\",\n  dpi = 320,\n  height = 10,\n  width = 12)<\/code><\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\">Challenge!<\/h2>\n\n\n\n<p class=\"has-medium-font-size\">Imagine you are a recruiter and from the data you have, you want to assess what players are performing above what is expected of them. Produce a scatterplot in which you would feel confident explaining players&#8217; performance. <\/p>\n\n\n\n<p>Programming is a lot of problem-solving please do look things up, google is your friend!*<\/p>\n\n\n\n<p><em>*Other search engines available.<\/em><\/p>\n\n\n\n<div class=\"wp-block-pb-accordion-item c-accordion__item js-accordion-item no-js\" data-initially-open=\"false\" data-click-to-close=\"true\" data-auto-close=\"false\" data-scroll=\"false\" data-scroll-offset=\"0\"><h3 id=\"at-35690\" class=\"c-accordion__title js-accordion-controller\" role=\"button\">Click to reveal \u2b07 \u23af\u23af\u23af\u23af\u23af\u23af\u23af\u23af\u23af\u23af\u23af\u23af\u23af\u23af\u23af\u23af\u23af\u23af\u23af\u23af\u23af\u23af\u23af\u23af\u23af\u23af\u23af\u23af\u23af\u23af\u23af\u23af\u23af\u23af\u23af\u23af\u23af\u23af\u23af\u23af\u23af<\/h3><div id=\"ac-35690\" class=\"c-accordion__content\">\n<p class=\"has-medium-font-size\">Nope, this one is all on you. <\/p>\n<\/div><\/div>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<h2 class=\"wp-block-heading\">Shot maps<\/h2>\n\n\n\n<p class=\"has-medium-font-size\">Now we&#8217;ve enjoyed scatterplots suitably, let&#8217;s move on to make some shot maps! Much like we did for the scatterplot, we will be filtering our data down to a more targeted sample. In the optional lessons, you can make an interactive shot map. We are going to program the shot map in a way which will translate into being interactive quite nicely. We&#8217;re going to ask the user to specify how many nineties they want the player to have played and how many of the top players (ranked by npxg_p90) they want to plot shot maps for. The shot map will use these inputs to filter the data and then create the shot maps.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># The user_input_nineties variable holds the amount of nineties the\n# user wants to the player to have played. Since this isn't interactive\n# yet, we are going to specifiy the value.\nuser_input_nineties = 2\n\n# Holds the value the user specifies for how many top ranked players to \n# plot shot maps for.  \nuser_input_top_players = 6 \n\n# Filter summary dataset and save the output into the shot_map_summary variable\nshot_map_summary &lt;- summary %&gt;%\n  filter(nineties &gt;= user_input_nineties) %&gt;%  head(n = user_input_top_players)\n# Note: The &gt;= is the greater than or equal to operator.<\/code><\/pre>\n\n\n\n<p class=\"has-medium-font-size\">We apply the user input to filter the summary data and store the results in the shot_map_summary variable. The <\/p>\n\n\n\n<p class=\"has-medium-font-size\">We apply the user input to filter the summary data and store the results in the shot_map_summary variable. The <\/p>\n\n\n\n<p class=\"has-medium-font-size\">We apply the user input to filter the summary data and store the results in the shot_map_summary variable. The shot_map_summary is then used to pull the relevant player data from the shot_data and store it in the shot_map_plot_data variable.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>shot_map_plot_data &lt;- shot_data %&gt;%\n  # Searches for player name in the shot_map_summary dataframe we \n  # filtered using the user input. The filter will only return players\n  # who appear in the shot_map_summary dataframe.\n  filter(player.name %in% unique(shot_map_summary$player.name)) %&gt;%\n  # select() then specifies which columns to add to the shot_map_summary \n  select(\n    player.name,\n    location.x,\n    location.y,\n    is_goal,\n    shot.outcome.name,\n    shot.statsbomb_xg,\n    team.name) <\/code><\/pre>\n\n\n\n<p class=\"has-medium-font-size\">Our data is ready, let&#8217;s create the plot. Like we did last time, we&#8217;re going to build it up piece by piece. First, let&#8217;s draw a pitch.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ggplot() + # ggplot() is the canvas the shot map will be displayed on\n  annotate_pitch(dimensions = pitch_statsbomb) + # annotate_pitch() draws a pitch\n  theme_pitch() + # applies cosmetic changes so we can view the pitch better.\n  coord_flip(xlim = c(60, 120), # flips the pitch for better visulation of shots.\n             ylim = c(0, 80))\n# Save plot\nggsave(\n  plot = last_plot(),\n  \"empty_pitch.png\",\n  dpi = 320,\n  height = 10,\n  width = 12\n)<\/code><\/pre>\n\n\n\n<p class=\"has-medium-font-size\">Now the pitch is drawn let&#8217;s add some data. We&#8217;re going to use two geom_point() functions to plot our points, one will be for shots that resulted in a goal and the other for all the shots that didn&#8217;t result in a goal.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ggplot() +\n  annotate_pitch(dimensions = pitch_statsbomb) + # draw the pitch\n  theme_pitch() +\n  coord_flip(xlim = c(60, 120),\n             ylim = c(0, 80)) +\n  geom_point(data = shot_map_plot_data %&gt;% # plot the location the  \n               filter(is_goal == 0),       # not goal shots.\n             aes(x = location.x,\n                 y = location.y)) +\n  geom_point(data = shot_map_plot_data %&gt;% # plot the location the \n               filter(is_goal == 1),       # shots that resulted in a goal.\n             aes(x = location.x,\n                 y = location.y)) \n# Save plot\nggsave(\n  plot = last_plot(),\n  \"all_data_shot_map.png\",\n  dpi = 320,\n  height = 10,\n  width = 12\n)<\/code><\/pre>\n\n\n\n<p class=\"has-medium-font-size\">At this stage, the shot map is a shot map, but not a very informative one. Currently, it&#8217;s plotting all the data and not differentiating between players. We can use the facet_wrap() function to create a shot map for each player.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ggplot() +\n  annotate_pitch(dimensions = pitch_statsbomb) + # draw the pitch\n  theme_pitch() +\n  coord_flip(xlim = c(60, 120),\n             ylim = c(0, 80)) +\n  geom_point(data = shot_map_plot_data %&gt;% # plot the location the  \n               filter(is_goal == 0),       # not goal shots.\n             aes(x = location.x,\n                 y = location.y)) +\n  geom_point(data = shot_map_plot_data %&gt;% # plot the location the \n               filter(is_goal == 1),       # shots that resulted in a goal.\n             aes(x = location.x,\n                 y = location.y)) +\n  facet_wrap(~ player.name)  # creates a shot map for each player\n\n# Save plot\nggsave(\n  plot = last_plot(),\n  \"per_player_shot_map.png\",\n  dpi = 320,\n  height = 10,\n  width = 12\n)<\/code><\/pre>\n\n\n\n<p class=\"has-medium-font-size\">Now we have a shot map for each player, we can add some colour to the geom_point() functions so we can see the difference between shots that were a goal or not.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ggplot() +\n  annotate_pitch(dimensions = pitch_statsbomb) + # draw the pitch\n  theme_pitch() +\n  coord_flip(xlim = c(60, 120),\n             ylim = c(0, 80)) +\n  geom_point(\n    data = shot_map_plot_data %&gt;%\n      filter(is_goal == 0),\n    aes(x = location.x,\n        y = location.y),\n    shape = 21,\n    fill = \"#FC8D62\", # Fills non goal data points orange.\n    stroke = 0.6,\n    colour = \"black\" # We will also add a nice outline\n  ) +\n  geom_point(\n    data = shot_map_plot_data %&gt;%\n      filter(is_goal == 1),\n    aes(x = location.x,\n        y = location.y),\n    shape = 21,\n    fill = \"#66C2A5\", # Fills goal data points green.\n    stroke = 0.6,\n    colour = \"black\" # We will also add a nice outline\n  ) +\n  facet_wrap(~ player.name)  # creates a shot map for each player\n\n# Save plot\nggsave(\n  plot = last_plot(),\n  \"per_player_cosmetic_shot_map.png\",\n  dpi = 320,\n  height = 10,\n  width = 12\n)\n<\/code><\/pre>\n\n\n\n<p class=\"has-medium-font-size\">When you have so much data to use, you might as well make the most of it! We are going to scale the shot locations on the shot map using the shot.statsbomb_xg column. The bigger the data point on the shop map, the more expected it was for that shot to be a goal.<\/p>\n\n\n\n<p class=\"has-text-align-center has-medium-font-size\"><em>Before plotting, ask yourself what would you expect to see on the shot map from a good player.<\/em><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ggplot() +\n  annotate_pitch(dimensions = pitch_statsbomb) +\n  theme_pitch() +\n  coord_flip(xlim = c(60, 120),\n             ylim = c(0, 80)) +\n  geom_point(\n    data = shot_map_plot_data %&gt;%\n      filter(is_goal == 0),\n    aes(x = location.x,\n        y = location.y,\n        size = shot.statsbomb_xg),\n # Here is where we scale the data points\n                                   # from the shot.statsbomb_xg column\n    shape = 21,\n    fill = \"#FC8D62\",\n # Fills non goal data points orange.\n    stroke = 0.6,\n    colour = \"black\" # We will also add a nice outline\n  ) +\n  geom_point(\n    data = shot_map_plot_data %&gt;%\n      filter(is_goal == 1),\n    aes(x = location.x,\n        y = location.y,\n        size = shot.statsbomb_xg),\n # Here is where we scale the data points\n                                   # from the shot.statsbomb_xg column\n    shape = 21,\n    fill = \"#66C2A5\",\n # Fills goal data points green.\n    stroke = 0.6,\n    colour = \"black\" # We will also add a nice outline\n  ) +\n  facet_wrap(~ player.name)  # creates a shot map for each player\n\n# Save plot\nggsave(\n  plot = last_plot(),\n  \"weighted_data_points_shot_map.png\",\n  dpi = 320,\n  height = 10,\n  width = 12\n)<\/code><\/pre>\n\n\n\n<p class=\"has-medium-font-size\">Let&#8217;s use the labs() function to add some labels to the shot map. Although, with the aim of adding interactivity. The title uses the paste() function so the user input can be displayed in the title. <\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ggplot() +\n  annotate_pitch(dimensions = pitch_statsbomb) +\n  theme_pitch() +\n  coord_flip(xlim = c(60, 120),\n             ylim = c(0, 80)) +\n  geom_point(\n    data = shot_map_plot_data %&gt;%\n      filter(is_goal == 0),\n    aes(x = location.x,\n        y = location.y,\n        size = shot.statsbomb_xg),\n    shape = 21,\n    fill = \"#FC8D62\",\n    stroke = 0.6,\n    colour = \"black\"\n  ) +\n  geom_point(\n    data = shot_map_plot_data %&gt;%\n      filter(is_goal == 1),\n    aes(x = location.x,\n        y = location.y,\n        size = shot.statsbomb_xg),\n    shape = 21,\n    fill = \"#66C2A5\",\n    \n    stroke = 0.6,\n    colour = \"black\"\n  ) +\n  facet_wrap(~ player.name) +\n  labs(\n    title = paste(\n      \"Top\",\n      user_input_top_players,\n      \"players rated on Non Penalty xG P90, which have played\",\n      user_input_nineties,\n      \"nineties.\"\n    ),\n    subtitle = \"UEFA Women's Euro 2022\",\n    caption = \"Data: StatsBomb\",\n    size = \"Expected goal value\"\n  )\n\n# Save plot\nggsave(\n  plot = last_plot(),\n  \"labeled_shot_map.png\",\n  dpi = 320,\n  height = 10,\n  width = 12\n)<\/code><\/pre>\n\n\n\n<p class=\"has-medium-font-size\">When you think there is nothing else you could possibly add to this shot map&#8230; What about adding the per nineties stats of the player on their shot map? We want our visualisation to pour out useful information! We can add the per nineties stats using geom_text() functions.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>ggplot() +\n  annotate_pitch(dimensions = pitch_statsbomb) +\n  theme_pitch() +\n  coord_flip(xlim = c(60, 120),\n             ylim = c(0, 80)) +\n  geom_point(\n    data = shot_map_plot_data %&gt;%\n      filter(is_goal == 0),\n    aes(x = location.x,\n        y = location.y,\n        size = shot.statsbomb_xg),\n    shape = 21,\n    fill = \"#FC8D62\",\n    stroke = 0.6,\n    colour = \"black\"\n  ) +\n  geom_point(\n    data = shot_map_plot_data %&gt;%\n      filter(is_goal == 1),\n    aes(x = location.x,\n        y = location.y,\n        size = shot.statsbomb_xg),\n    shape = 21,\n    fill = \"#66C2A5\",\n    \n    stroke = 0.6,\n    colour = \"black\"\n  ) +\n  facet_wrap( ~ player.name) +\n  labs(\n    title = paste(\n      \"Top\",\n      user_input_top_players,\n      \"players rated on Non Penalty xG P90, which have played\",\n      user_input_nineties,\n      \"nineties.\"\n    ),\n    subtitle = \"UEFA Women's Euro 2022\",\n    caption = \"Data: StatsBomb\",\n    size = \"Expected goal value\"\n  )  +\n  geom_text(data = shot_map_summary,\n            aes(\n              x = 80,\n              y = 15,\n              label = paste(\"Shots P90:\", round(shots_p90, digits = 2))\n            )) +\n  geom_text(data = shot_map_summary,\n            aes(\n              x = 74,\n              y = 15,\n              label = paste(\"Goals P90:\", round(goals_p90, digits = 2))\n            )) +\n  geom_text(data = shot_map_summary,\n            aes(\n              x = 68,\n              y = 15,\n              label = paste(\"NPxG P90:\", round(npxg_p90, digits = 2))\n            ))\n\n# Save plot\nggsave(\n  plot = last_plot(),\n  \"a_shot_map_masterpiece.png\",\n  dpi = 320,\n  height = 10,\n  width = 12\n)<\/code><\/pre>\n\n\n\n<p class=\"has-text-align-center has-medium-font-size\"><em>If you&#8217;re super eagle-eyed then you may have noticed that the shot maps are arranged in alphabetical order of the player&#8217;s first name. This is due to the facet_wrap() function. If you were presenting this data then you would want to resolve this to ensure effective communication. Do feel free to see this as a challenge to tackle! <\/em><\/p>\n\n\n\n<p class=\"has-medium-font-size\">Wow, would you look at that? How beauty takes such form in a shot map. Certainly, take some time to play around and create some more shot maps. Perhaps you could think about how you might want to filter data in order to target what you&#8217;d like to visualise. For example, you could filter the data based on team as we did for the scatterplot. The data is your oyster.<\/p>\n\n\n\n<div class=\"wp-block-pb-accordion-item c-accordion__item js-accordion-item no-js\" data-initially-open=\"false\" data-click-to-close=\"true\" data-auto-close=\"false\" data-scroll=\"false\" data-scroll-offset=\"0\"><h2 id=\"at-35691\" class=\"c-accordion__title js-accordion-controller\" role=\"button\">Want the code from this lesson in one chunk?   \u2b07\u23af\u23af\u23af\u23af\u23af\u23af\u23af\u23af\u23af\u23af <\/h2><div id=\"ac-35691\" class=\"c-accordion__content\">\n<p class=\"has-medium-font-size\">You can download the whole data processing script from the <a href=\"https:\/\/testlivesalfordac.sharepoint.com\/:f:\/s\/PsyTech\/Ektl32BpbsRFlElCods0R1gBcWgOncCtnUmKzZKwzbq_iQ?e=8LtcBM\" target=\"_blank\" rel=\"noreferrer noopener\">course files (opens in new tab)<\/a>. <\/p>\n\n\n\n<p class=\"has-medium-font-size\">Alternatively, you can copy and paste the below:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#----\n#---------- Load packages\n# An if statment is used to evaluate if the required package is\n# already installed. If the package is not installed the code will \n# install the package. The package will be loaded in the library() function.\nif (require(\"tidyverse\") == FALSE) {\n  install.packages(\"tidyverse\")\n}\nlibrary(tidyverse)\n#--\nif (require(\"ggrepel\") == FALSE) {\n  install.packages(\"ggrepel\")\n}\nlibrary(ggrepel)\n#--\nif (require(\"ggsoccer\") == FALSE) {\n  install.packages(\"ggsoccer\")\n}\nlibrary(ggsoccer)\n##--------------------------- \n\n\n#----\n#------- Load the UEFA Women's Euro 2022 data files created previously into variables.\n#------- The encoding ensures cyrillic, latin, etc, letters are displayed correctly.\nshot_data &lt;- read.csv(\"shot_data.csv\", encoding = \"latin1\")\nsummary &lt;- read.csv(\"summary.csv\", encoding = \"latin1\")\nprint(\"data loaded\")\n##--------------------------- \n\n\n#----\n#-------  An important aspect of programming is ensuring you're using the appropriate\n#------- data type in a function. Later on we will be using the is_goal column which is \n#------- required to be the factor data type. We can acquire the data type of the\n#------- is_goal column using the class() function we used in the first lesson.\n# The dollar $ sign is used to specify a column  in a dataframe. \n# shot_data$is_goal is accessing the is_goal column from the shot_data variable.\n\nclass(shot_data$is_goal)\n\n#------- Currently is_goal is considered an integer, we can change the data type\n#-------with the following code.\n\nshot_data$is_goal &lt;- as.factor(shot_data$is_goal) \n\n##--------------------------- \n\n\n\n#------- First we are going to filter our data so we don't plot everything on the scatterplot. \n#------- Using the head() function I can save the top 15 rows in the summary data set (which is organised by npxg_p90) \n#into a new variable which we will use for the scatterplot.\n# The reason we save to a new variable is so we can preserve the full summary dataset\n# for future manipulations\nscatterplot_summary &lt;- head(summary, n = 15)  \n##--------------------------- \n\n\n#----- Let's create a scatterplot\n# First we call the ggplot() function, this creates a canvas for us to plot on. \n# we specifiy the variable we want to plot from and what data columns do on the x and y axis.\n# The x and y is specified in the aes() function nested inside of ggplot().\n# In this example shots are on the x axis (horizontal) and goals are on the y axis (vertial).\n# Do remember that shots and goals absoulte values, when you make your own plots you can \n# use the per 90 columns we calculated.\n# We then add the geom_point() function to the canvas which will mark our data points.\n# The minimum requirements you need to make a scatterplot\nggplot(data = scatterplot_summary,  # Using the data we filtered \n       aes(x = shots,               # On the x axis shots will be plot\n           y = goals)) +            # On the y axis goals will be plot\n  geom_point() \n\n# Save the plot\nggsave(\n  plot = last_plot(),\n  \"bare_scatter_plot.png\", # Saves image of plot to R project folder.\n  dpi = 320,\n  height = 10,\n  width = 12)\n#----------------\n\n\n#---\n#------- Create labeled scatterplot by adding geom_text_repel()\nggplot(data = scatterplot_summary, #using same data, x, and y as above.\n       aes(x = shots,\n           y = goals)) +\n  geom_point() +\n  geom_text_repel(\n    aes(label = player.name), # Labels the data point with the player name.\n    max.overlaps = getOption(\"ggrepel.max.overlaps\", default = 20), # Here we\n    # state how many points of the plot can have overlaping values.\n    box.padding = unit(0.35, \"lines\"), # Increasing the 0.35 value will create\n    # more space around the player name label.\n    point.padding = unit(0.3, \"lines\"), # Will increase the space around\n    # the data points.\n    arrow = arrow(length = unit(0.01, 'npc')) # Adds an arrow if the label is\n    # far away from the data point.\n  ) \n\n# Save the plot\nggsave(\n  plot = last_plot(),\n  \"labeled_scatter_plot.png\",\n  dpi = 320,\n  height = 10,\n  width = 12)\n#---------------------------\n\n\n#----\n#------- Customise the scatterplot\n# You can go ahead and change the colour of the geom_point(). We can use geom_smooth() to plot \n# a regression line and colour it red The labs() functions allows us to label the plot. There are \n# tons more mays to customise your plot. This is why R has a reputation for being great at producting\n# visulisations.\nggplot(data = scatterplot_summary, #using same data, x, and y as before.\n       aes(x = shots,\n           y = goals)) +\n  geom_point(color = 'blue') + # We can change the data points to be blue.\n  geom_smooth(method = lm, color = \"red\") + # This line of code adds a \n  # regression line.\n  geom_text_repel(\n    aes(label = player.name), # Labels the data point with the player name.\n    max.overlaps = getOption(\"ggrepel.max.overlaps\", default = 20), # Here we\n    # state how many points of the plot can have overlaping values.\n    box.padding = unit(0.35, \"lines\"), # Increasing the 0.35 value will create\n    # more space around the player name label.\n    point.padding = unit(0.3, \"lines\"), # Will increase the space around\n    # the data points.\n    arrow = arrow(length = unit(0.01, 'npc')) # Adds an arrow if the label is\n    # far away from the data point.\n  )  +\n  labs( # We can add labels that give the plot a title and a caption.\n    title = \"UEFA Women's Euro 2022\",\n    caption = \"Data: StatsBomb\")\n\n# Save the plot\nggsave(\n  plot = last_plot(),\n  \"customised_scatter_plot.png\",\n  dpi = 320,\n  height = 10,\n  width = 12)\n#---------------------------\n\n\n#-----\n#-------- Create a scatterplot to compare players in specified teams.\n# Filter data that will be used in the scatterplot.\nscatterplot_summary &lt;- summary %&gt;% \n  filter(shots &gt; 0) %&gt;% # Removing players who =haven't made any shots.\n  # Keeping plays that are in Sweden's or England's team.\n  # The | operator is the or operator. Therefore the code keeps \n  # plays in the data set that belong to Sweden or England.\n  filter(team.name == \"Sweden Women's\" | team.name == \"England Women's\")\n\n# Create the scatterplot.\nggplot(data = scatterplot_summary, # Using same data variable (although \n       #filtered differently this time!)\n       # Still using same variables in x, \n       aes(x = shots,          # and y as before.\n           y = goals)) +\n  geom_point((aes(colour = team.name))) + # Setting the colour of the \n  # data points to corospond to team.name. \n  # The scale_color_manual() store what colour the each teams data\n  # points will be.\n  scale_color_manual(values = c(\"Sweden Women's\" = \"yellow\", \"England Women's\" = \"red\")) + \n  geom_smooth(method = lm) + \n  geom_text_repel(\n    aes(label = player.name),\n    max.overlaps = getOption(\"ggrepel.max.overlaps\", default = 20),\n    box.padding = unit(0.8, \"lines\"), # really had to fiddle with this \n    # value in order to see the lables\n    point.padding = unit(0.3, \"lines\"),\n    arrow = arrow(length = unit(0.01, 'npc'))\n  ) +\n  labs(title = \"UEFA Women's Euro 2022\",\n       caption = \"Data: StatsBomb\")\n\n# Save the plot\nggsave(\n  plot = last_plot(),\n  \"team_comparison_scatter_plot.png\",\n  dpi = 320,\n  height = 10,\n  width = 12)\n#---------------\n\n\n\n########\n########\n#----- Let's make some shot maps!\n########\n########\n\n#----\n#-------- Simulate taking user input and use that to filter the data.\nuser_input_nineties = 2 \nuser_input_top_players = 6 \n#---------------\n\n\n#----\n#-------- Filter summary dataset and save the output into the shot_map_summary variable\nshot_map_summary &lt;- summary %&gt;%\n  filter(nineties &gt;= user_input_nineties) %&gt;%  head(n = user_input_top_players)\n# Note: The &gt;= is the greater than or equal to operator.\n#---------------\n\n\n#----\n#-------- Uses the filtered shot_map_summary data to pull the relevant data.\nshot_map_plot_data &lt;- shot_data %&gt;%\n  # Searches for player name in the shot_map_summary dataframe we\n  # filtered using the user input. The filter will only return players\n  # who appear in the shot_map_summary dataframe.\n  filter(player.name %in% unique(shot_map_summary$player.name)) %&gt;%\n  # select() then specifies which columns to add to the shot_map_summary\n  select(\n    player.name,\n    location.x,\n    location.y,\n    is_goal,\n    shot.outcome.name,\n    shot.statsbomb_xg,\n    team.name\n  ) \n#---------------\n\n#----\n#-------- Draw a pitch for the shot map\nggplot() + # ggplot() is the canvas the shot map will be displayed on\n  annotate_pitch(dimensions = pitch_statsbomb) + # annotate_pitch() draws a pitch\n  theme_pitch() + # applies cosmetic changes so we can view the pitch better.\n  coord_flip(xlim = c(60, 120), # flips the pitch for better visulation of shots.\n             ylim = c(0, 80))\n# Save plot\nggsave(\n  plot = last_plot(),\n  \"empty_pitch.png\",\n  dpi = 320,\n  height = 10,\n  width = 12\n)\n#-----------------\n\n\n#----\n#--------- Shot map, all data\nggplot() +\n  annotate_pitch(dimensions = pitch_statsbomb) + # draw the pitch\n  theme_pitch() +\n  coord_flip(xlim = c(60, 120),\n             ylim = c(0, 80)) +\n  geom_point(data = shot_map_plot_data %&gt;% # plot the location the  \n               filter(is_goal == 0),       # not goal shots.\n             aes(x = location.x,\n                 y = location.y)) +\n  geom_point(data = shot_map_plot_data %&gt;% # plot the location the \n               filter(is_goal == 1),       # shots that resulted in a goal.\n             aes(x = location.x,\n                 y = location.y)) \n# Save plot\nggsave(\n  plot = last_plot(),\n  \"all_data_shot_map.png\",\n  dpi = 320,\n  height = 10,\n  width = 12\n)\n#----------------\n\n\n#----\n#-------- Shot map per player\nggplot() +\n  annotate_pitch(dimensions = pitch_statsbomb) + # draw the pitch\n  theme_pitch() +\n  coord_flip(xlim = c(60, 120),\n             ylim = c(0, 80)) +\n  geom_point(data = shot_map_plot_data %&gt;% # plot the location the  \n               filter(is_goal == 0),       # not goal shots.\n             aes(x = location.x,\n                 y = location.y)) +\n  geom_point(data = shot_map_plot_data %&gt;% # plot the location the \n               filter(is_goal == 1),       # shots that resulted in a goal.\n             aes(x = location.x,\n                 y = location.y)) +\n  facet_wrap(~ player.name)  # creates a shot map for each player\n\n# Save plot\nggsave(\n  plot = last_plot(),\n  \"per_player_shot_map.png\",\n  dpi = 320,\n  height = 10,\n  width = 12\n)\n#----------------\n\n\n#----\n#-------- Shot map with different colours for non goal shots and goals \nggplot() +\n  annotate_pitch(dimensions = pitch_statsbomb) + # draw the pitch\n  theme_pitch() +\n  coord_flip(xlim = c(60, 120),\n             ylim = c(0, 80)) +\n  geom_point(\n    data = shot_map_plot_data %&gt;%\n      filter(is_goal == 0),\n    aes(x = location.x,\n        y = location.y),\n    shape = 21,\n    fill = \"#FC8D62\", # Fills non goal data points orange.\n    stroke = 0.6,\n    colour = \"black\" # We will also add a nice outline\n  ) +\n  geom_point(\n    data = shot_map_plot_data %&gt;%\n      filter(is_goal == 1),\n    aes(x = location.x,\n        y = location.y),\n    shape = 21,\n    fill = \"#66C2A5\", # Fills goal data points green.\n    stroke = 0.6,\n    colour = \"black\" # We will also add a nice outline\n  ) +\n  facet_wrap(~ player.name)  # creates a shot map for each player\n\n# Save plot\nggsave(\n  plot = last_plot(),\n  \"per_player_cosmetic_shot_map.png\",\n  dpi = 320,\n  height = 10,\n  width = 12\n)\n\n#---------------------------\n\n\n#----\n#-------- Shot map with weighted data points\nggplot() +\n  annotate_pitch(dimensions = pitch_statsbomb) +\n  theme_pitch() +\n  coord_flip(xlim = c(60, 120),\n             ylim = c(0, 80)) +\n  geom_point(\n    data = shot_map_plot_data %&gt;%\n      filter(is_goal == 0),\n    aes(x = location.x,\n        y = location.y,\n        size = shot.statsbomb_xg),\n    # Here is where we scale the data points\n    # from the shot.statsbomb_xg column\n    shape = 21,\n    fill = \"#FC8D62\",\n    # Fills non goal data points orange.\n    stroke = 0.6,\n    colour = \"black\" # We will also add a nice outline\n  ) +\n  geom_point(\n    data = shot_map_plot_data %&gt;%\n      filter(is_goal == 1),\n    aes(x = location.x,\n        y = location.y,\n        size = shot.statsbomb_xg),\n    # Here is where we scale the data points\n    # from the shot.statsbomb_xg column\n    shape = 21,\n    fill = \"#66C2A5\",\n    # Fills goal data points green.\n    stroke = 0.6,\n    colour = \"black\" # We will also add a nice outline\n  ) +\n  facet_wrap(~ player.name)  # creates a shot map for each player\n\n# Save plot\nggsave(\n  plot = last_plot(),\n  \"weighted_data_points_shot_map.png\",\n  dpi = 320,\n  height = 10,\n  width = 12\n)\n#---------------------\n\n\n#----\n#------- Shot map with labels\nggplot() +\n  annotate_pitch(dimensions = pitch_statsbomb) +\n  theme_pitch() +\n  coord_flip(xlim = c(60, 120),\n             ylim = c(0, 80)) +\n  geom_point(\n    data = shot_map_plot_data %&gt;%\n      filter(is_goal == 0),\n    aes(x = location.x,\n        y = location.y,\n        size = shot.statsbomb_xg),\n    shape = 21,\n    fill = \"#FC8D62\",\n    stroke = 0.6,\n    colour = \"black\"\n  ) +\n  geom_point(\n    data = shot_map_plot_data %&gt;%\n      filter(is_goal == 1),\n    aes(x = location.x,\n        y = location.y,\n        size = shot.statsbomb_xg),\n    shape = 21,\n    fill = \"#66C2A5\",\n    \n    stroke = 0.6,\n    colour = \"black\"\n  ) +\n  facet_wrap(~ player.name) +\n  labs(\n    title = paste(\n      \"Top\",\n      user_input_top_players,\n      \"players rated on Non Penalty xG P90, which have played\",\n      user_input_nineties,\n      \"nineties.\"\n    ),\n    subtitle = \"UEFA Women's Euro 2022\",\n    caption = \"Data: StatsBomb\",\n    size = \"Expected goal value\"\n  )\n\n# Save plot\nggsave(\n  plot = last_plot(),\n  \"labeled_shot_map.png\",\n  dpi = 320,\n  height = 10,\n  width = 12\n)\n#-------------------\n\n\n#----\n#--------- The final shot map!\nggplot() +\n  annotate_pitch(dimensions = pitch_statsbomb) +\n  theme_pitch() +\n  coord_flip(xlim = c(60, 120),\n             ylim = c(0, 80)) +\n  geom_point(\n    data = shot_map_plot_data %&gt;%\n      filter(is_goal == 0),\n    aes(x = location.x,\n        y = location.y,\n        size = shot.statsbomb_xg),\n    shape = 21,\n    fill = \"#FC8D62\",\n    stroke = 0.6,\n    colour = \"black\"\n  ) +\n  geom_point(\n    data = shot_map_plot_data %&gt;%\n      filter(is_goal == 1),\n    aes(x = location.x,\n        y = location.y,\n        size = shot.statsbomb_xg),\n    shape = 21,\n    fill = \"#66C2A5\",\n    \n    stroke = 0.6,\n    colour = \"black\"\n  ) +\n  facet_wrap( ~ player.name) +\n  labs(\n    title = paste(\n      \"Top\",\n      user_input_top_players,\n      \"players rated on Non Penalty xG P90, which have played\",\n      user_input_nineties,\n      \"nineties.\"\n    ),\n    subtitle = \"UEFA Women's Euro 2022\",\n    caption = \"Data: StatsBomb\",\n    size = \"Expected goal value\"\n  )  +\n  geom_text(data = shot_map_summary,\n            aes(\n              x = 80,\n              y = 15,\n              label = paste(\"Shots P90:\", round(shots_p90, digits = 2))\n            )) +\n  geom_text(data = shot_map_summary,\n            aes(\n              x = 74,\n              y = 15,\n              label = paste(\"Goals P90:\", round(goals_p90, digits = 2))\n            )) +\n  geom_text(data = shot_map_summary,\n            aes(\n              x = 68,\n              y = 15,\n              label = paste(\"NPxG P90:\", round(npxg_p90, digits = 2))\n            ))\n\n# Save plot\nggsave(\n  plot = last_plot(),\n  \"a_shot_map_masterpiece.png\",\n  dpi = 320,\n  height = 10,\n  width = 12\n)\n#-----------------\n\nprint(\"taaa daaaaa!\")<\/code><\/pre>\n<\/div><\/div>\n\n\n\n<div class=\"wp-block-columns is-layout-flex wp-container-core-columns-is-layout-9d6595d7 wp-block-columns-is-layout-flex\">\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\" style=\"flex-basis:25%\">\n<h2 class=\"wp-block-heading\"><a href=\"https:\/\/hub.salford.ac.uk\/psytech\/psytechsalford\/learn-programming\/performance-visualisation-r\/data-processing-performance-visualisation-in-r\/\">\u2b05 Previous<\/a><\/h2>\n<\/div>\n\n\n\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\" style=\"flex-basis:50%\">\n<h2 class=\"has-text-align-center wp-block-heading\">&nbsp;<a href=\"https:\/\/hub.salford.ac.uk\/psytech\/psytechsalford\/learn-programming\/performance-visualisation-r\">? Return to Overview<\/a> <\/h2>\n<\/div>\n\n\n\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\" style=\"flex-basis:25%\">\n<h2 class=\"wp-block-heading\"><a href=\"https:\/\/hub.salford.ac.uk\/psytech\/psytechsalford\/learn-programming\/performance-visualisation-r\/introduction-to-shiny-performance-visualisation-in-r\/\">Next \u27a1\ufe0f<\/a><\/h2>\n<\/div>\n<\/div>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\" \/>\n\n\n\n<div class=\"wp-block-columns is-layout-flex wp-container-core-columns-is-layout-9d6595d7 wp-block-columns-is-layout-flex\">\n<div class=\"wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow\" style=\"flex-basis:25%\"><div class=\"wp-block-image\">\n<figure class=\"aligncenter is-resized\"><img decoding=\"async\" src=\"https:\/\/r4ds.hadley.nz\/cover.png\" alt=\"\" width=\"-29\" height=\"-43\" \/><\/figure>\n<\/div><\/div>\n\n\n\n<div class=\"wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow\" style=\"flex-basis:50%\">\n<h2 class=\"wp-block-heading\">Further resources:<\/h2>\n\n\n\n<p>If you wish to pursue R independently, I recommend the following online resources to aid you on your learning journey. <\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/www.w3schools.com\/r\/default.asp\">https:\/\/www.w3schools.com\/r\/default.asp <\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/r4ds.had.co.nz\/index.html\">https:\/\/r4ds.had.co.nz\/index.html<\/a><\/li>\n<\/ul>\n<\/div>\n\n\n\n<div class=\"wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow\" style=\"flex-basis:25%\"><div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/yt3.googleusercontent.com\/dW6to0x5Crmeh7yi-YPLcQRqVrBtx2BSh8eoKTJbE8NbjloQ0sqlmdszIlxokJU_97-ndOt_=s900-c-k-c0x00ffffff-no-rj\" alt=\"\" width=\"238\" height=\"238\" \/><\/figure>\n<\/div><\/div>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Lesson tasks: If you are visiting this lesson independently, at the bottom of the page is the code in full with more detailed comments. Get started by downloading and opening the R project file from the course files (opens in new tab). As always, the first thing we need to do is load the packages [&hellip;]<\/p>\n","protected":false},"author":177,"featured_media":0,"parent":3430,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_acf_changed":false,"footnotes":""},"class_list":["post-3569","page","type-page","status-publish","hentry"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.4 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Data Visualisation - Performance Visualisation in R - Salford PsyTech Home \u2192\u2302<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/hub.salford.ac.uk\/psytech\/psytechsalford\/learn-programming\/performance-visualisation-r\/data-visualisation-performance-visualisation-in-r\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Data Visualisation - Performance Visualisation in R - Salford PsyTech Home \u2192\u2302\" \/>\n<meta property=\"og:description\" content=\"Lesson tasks: If you are visiting this lesson independently, at the bottom of the page is the code in full with more detailed comments. Get started by downloading and opening the R project file from the course files (opens in new tab). As always, the first thing we need to do is load the packages [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/hub.salford.ac.uk\/psytech\/psytechsalford\/learn-programming\/performance-visualisation-r\/data-visualisation-performance-visualisation-in-r\/\" \/>\n<meta property=\"og:site_name\" content=\"Salford PsyTech Home \u2192\u2302\" \/>\n<meta property=\"article:modified_time\" content=\"2023-03-15T17:03:23+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/hub.salford.ac.uk\/psytech\/wp-content\/uploads\/sites\/95\/2022\/06\/image-15.png\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data1\" content=\"23 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/hub.salford.ac.uk\\\/psytech\\\/psytechsalford\\\/learn-programming\\\/performance-visualisation-r\\\/data-visualisation-performance-visualisation-in-r\\\/\",\"url\":\"https:\\\/\\\/hub.salford.ac.uk\\\/psytech\\\/psytechsalford\\\/learn-programming\\\/performance-visualisation-r\\\/data-visualisation-performance-visualisation-in-r\\\/\",\"name\":\"Data Visualisation - Performance Visualisation in R - Salford PsyTech Home \u2192\u2302\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/hub.salford.ac.uk\\\/psytech\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/hub.salford.ac.uk\\\/psytech\\\/psytechsalford\\\/learn-programming\\\/performance-visualisation-r\\\/data-visualisation-performance-visualisation-in-r\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/hub.salford.ac.uk\\\/psytech\\\/psytechsalford\\\/learn-programming\\\/performance-visualisation-r\\\/data-visualisation-performance-visualisation-in-r\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/hub.salford.ac.uk\\\/psytech\\\/wp-content\\\/uploads\\\/sites\\\/95\\\/2022\\\/06\\\/image-15.png\",\"datePublished\":\"2023-03-15T01:51:35+00:00\",\"dateModified\":\"2023-03-15T17:03:23+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/hub.salford.ac.uk\\\/psytech\\\/psytechsalford\\\/learn-programming\\\/performance-visualisation-r\\\/data-visualisation-performance-visualisation-in-r\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/hub.salford.ac.uk\\\/psytech\\\/psytechsalford\\\/learn-programming\\\/performance-visualisation-r\\\/data-visualisation-performance-visualisation-in-r\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/hub.salford.ac.uk\\\/psytech\\\/psytechsalford\\\/learn-programming\\\/performance-visualisation-r\\\/data-visualisation-performance-visualisation-in-r\\\/#primaryimage\",\"url\":\"https:\\\/\\\/hub.salford.ac.uk\\\/psytech\\\/wp-content\\\/uploads\\\/sites\\\/95\\\/2022\\\/06\\\/image-15.png\",\"contentUrl\":\"https:\\\/\\\/hub.salford.ac.uk\\\/psytech\\\/wp-content\\\/uploads\\\/sites\\\/95\\\/2022\\\/06\\\/image-15.png\",\"width\":255,\"height\":198},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/hub.salford.ac.uk\\\/psytech\\\/psytechsalford\\\/learn-programming\\\/performance-visualisation-r\\\/data-visualisation-performance-visualisation-in-r\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/hub.salford.ac.uk\\\/psytech\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Salford PsyTech\",\"item\":\"https:\\\/\\\/hub.salford.ac.uk\\\/psytech\\\/\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Learn Programming\",\"item\":\"https:\\\/\\\/hub.salford.ac.uk\\\/psytech\\\/psytechsalford\\\/learn-programming\\\/\"},{\"@type\":\"ListItem\",\"position\":4,\"name\":\"Performance Visualisation in R\",\"item\":\"https:\\\/\\\/hub.salford.ac.uk\\\/psytech\\\/psytechsalford\\\/learn-programming\\\/performance-visualisation-r\\\/\"},{\"@type\":\"ListItem\",\"position\":5,\"name\":\"Data Visualisation &#8211; Performance Visualisation in R\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/hub.salford.ac.uk\\\/psytech\\\/#website\",\"url\":\"https:\\\/\\\/hub.salford.ac.uk\\\/psytech\\\/\",\"name\":\"Salford PsyTech Home\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\\\/\\\/hub.salford.ac.uk\\\/psytech\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/hub.salford.ac.uk\\\/psytech\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/hub.salford.ac.uk\\\/psytech\\\/#organization\",\"name\":\"Salford PsyTech Home\",\"url\":\"https:\\\/\\\/hub.salford.ac.uk\\\/psytech\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/hub.salford.ac.uk\\\/psytech\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/hub.salford.ac.uk\\\/psytech\\\/wp-content\\\/uploads\\\/sites\\\/95\\\/2025\\\/02\\\/university-salford-logo-400x250-1.png\",\"contentUrl\":\"https:\\\/\\\/hub.salford.ac.uk\\\/psytech\\\/wp-content\\\/uploads\\\/sites\\\/95\\\/2025\\\/02\\\/university-salford-logo-400x250-1.png\",\"width\":400,\"height\":250,\"caption\":\"Salford PsyTech Home\"},\"image\":{\"@id\":\"https:\\\/\\\/hub.salford.ac.uk\\\/psytech\\\/#\\\/schema\\\/logo\\\/image\\\/\"}}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Data Visualisation - Performance Visualisation in R - Salford PsyTech Home \u2192\u2302","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/hub.salford.ac.uk\/psytech\/psytechsalford\/learn-programming\/performance-visualisation-r\/data-visualisation-performance-visualisation-in-r\/","og_locale":"en_US","og_type":"article","og_title":"Data Visualisation - Performance Visualisation in R - Salford PsyTech Home \u2192\u2302","og_description":"Lesson tasks: If you are visiting this lesson independently, at the bottom of the page is the code in full with more detailed comments. Get started by downloading and opening the R project file from the course files (opens in new tab). As always, the first thing we need to do is load the packages [&hellip;]","og_url":"https:\/\/hub.salford.ac.uk\/psytech\/psytechsalford\/learn-programming\/performance-visualisation-r\/data-visualisation-performance-visualisation-in-r\/","og_site_name":"Salford PsyTech Home \u2192\u2302","article_modified_time":"2023-03-15T17:03:23+00:00","og_image":[{"url":"https:\/\/hub.salford.ac.uk\/psytech\/wp-content\/uploads\/sites\/95\/2022\/06\/image-15.png","type":"","width":"","height":""}],"twitter_card":"summary_large_image","twitter_misc":{"Est. reading time":"23 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/hub.salford.ac.uk\/psytech\/psytechsalford\/learn-programming\/performance-visualisation-r\/data-visualisation-performance-visualisation-in-r\/","url":"https:\/\/hub.salford.ac.uk\/psytech\/psytechsalford\/learn-programming\/performance-visualisation-r\/data-visualisation-performance-visualisation-in-r\/","name":"Data Visualisation - Performance Visualisation in R - Salford PsyTech Home \u2192\u2302","isPartOf":{"@id":"https:\/\/hub.salford.ac.uk\/psytech\/#website"},"primaryImageOfPage":{"@id":"https:\/\/hub.salford.ac.uk\/psytech\/psytechsalford\/learn-programming\/performance-visualisation-r\/data-visualisation-performance-visualisation-in-r\/#primaryimage"},"image":{"@id":"https:\/\/hub.salford.ac.uk\/psytech\/psytechsalford\/learn-programming\/performance-visualisation-r\/data-visualisation-performance-visualisation-in-r\/#primaryimage"},"thumbnailUrl":"https:\/\/hub.salford.ac.uk\/psytech\/wp-content\/uploads\/sites\/95\/2022\/06\/image-15.png","datePublished":"2023-03-15T01:51:35+00:00","dateModified":"2023-03-15T17:03:23+00:00","breadcrumb":{"@id":"https:\/\/hub.salford.ac.uk\/psytech\/psytechsalford\/learn-programming\/performance-visualisation-r\/data-visualisation-performance-visualisation-in-r\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/hub.salford.ac.uk\/psytech\/psytechsalford\/learn-programming\/performance-visualisation-r\/data-visualisation-performance-visualisation-in-r\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/hub.salford.ac.uk\/psytech\/psytechsalford\/learn-programming\/performance-visualisation-r\/data-visualisation-performance-visualisation-in-r\/#primaryimage","url":"https:\/\/hub.salford.ac.uk\/psytech\/wp-content\/uploads\/sites\/95\/2022\/06\/image-15.png","contentUrl":"https:\/\/hub.salford.ac.uk\/psytech\/wp-content\/uploads\/sites\/95\/2022\/06\/image-15.png","width":255,"height":198},{"@type":"BreadcrumbList","@id":"https:\/\/hub.salford.ac.uk\/psytech\/psytechsalford\/learn-programming\/performance-visualisation-r\/data-visualisation-performance-visualisation-in-r\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/hub.salford.ac.uk\/psytech\/"},{"@type":"ListItem","position":2,"name":"Salford PsyTech","item":"https:\/\/hub.salford.ac.uk\/psytech\/"},{"@type":"ListItem","position":3,"name":"Learn Programming","item":"https:\/\/hub.salford.ac.uk\/psytech\/psytechsalford\/learn-programming\/"},{"@type":"ListItem","position":4,"name":"Performance Visualisation in R","item":"https:\/\/hub.salford.ac.uk\/psytech\/psytechsalford\/learn-programming\/performance-visualisation-r\/"},{"@type":"ListItem","position":5,"name":"Data Visualisation &#8211; Performance Visualisation in R"}]},{"@type":"WebSite","@id":"https:\/\/hub.salford.ac.uk\/psytech\/#website","url":"https:\/\/hub.salford.ac.uk\/psytech\/","name":"Salford PsyTech Home","description":"","publisher":{"@id":"https:\/\/hub.salford.ac.uk\/psytech\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/hub.salford.ac.uk\/psytech\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/hub.salford.ac.uk\/psytech\/#organization","name":"Salford PsyTech Home","url":"https:\/\/hub.salford.ac.uk\/psytech\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/hub.salford.ac.uk\/psytech\/#\/schema\/logo\/image\/","url":"https:\/\/hub.salford.ac.uk\/psytech\/wp-content\/uploads\/sites\/95\/2025\/02\/university-salford-logo-400x250-1.png","contentUrl":"https:\/\/hub.salford.ac.uk\/psytech\/wp-content\/uploads\/sites\/95\/2025\/02\/university-salford-logo-400x250-1.png","width":400,"height":250,"caption":"Salford PsyTech Home"},"image":{"@id":"https:\/\/hub.salford.ac.uk\/psytech\/#\/schema\/logo\/image\/"}}]}},"_links":{"self":[{"href":"https:\/\/hub.salford.ac.uk\/psytech\/wp-json\/wp\/v2\/pages\/3569","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/hub.salford.ac.uk\/psytech\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/hub.salford.ac.uk\/psytech\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/hub.salford.ac.uk\/psytech\/wp-json\/wp\/v2\/users\/177"}],"replies":[{"embeddable":true,"href":"https:\/\/hub.salford.ac.uk\/psytech\/wp-json\/wp\/v2\/comments?post=3569"}],"version-history":[{"count":27,"href":"https:\/\/hub.salford.ac.uk\/psytech\/wp-json\/wp\/v2\/pages\/3569\/revisions"}],"predecessor-version":[{"id":3640,"href":"https:\/\/hub.salford.ac.uk\/psytech\/wp-json\/wp\/v2\/pages\/3569\/revisions\/3640"}],"up":[{"embeddable":true,"href":"https:\/\/hub.salford.ac.uk\/psytech\/wp-json\/wp\/v2\/pages\/3430"}],"wp:attachment":[{"href":"https:\/\/hub.salford.ac.uk\/psytech\/wp-json\/wp\/v2\/media?parent=3569"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}