{"id":2750,"date":"2022-12-21T06:49:24","date_gmt":"2022-12-21T06:49:24","guid":{"rendered":"http:\/\/optimumsportsperformance.com\/blog\/?p=2750"},"modified":"2022-12-21T12:51:58","modified_gmt":"2022-12-21T12:51:58","slug":"box-dotplots-for-performance-visuals-creating-an-interactive-plot-with-plotly","status":"publish","type":"post","link":"https:\/\/optimumsportsperformance.com\/blog\/box-dotplots-for-performance-visuals-creating-an-interactive-plot-with-plotly\/","title":{"rendered":"Box &#038; Dotplots for Performance Visuals &#8211; Creating an Interactive Plot with plotly"},"content":{"rendered":"<p><strong><span style=\"color: #0000ff;\"><a style=\"color: #0000ff;\" href=\"https:\/\/optimumsportsperformance.com\/blog\/box-dotplots-for-performance-visuals\/\">Yesterday<\/a><\/span><\/strong>, I provided some code to make a simple boxplot with doplot in order to visualize an athlete&#8217;s performance relative to their peers.<\/p>\n<p>Today, we will try and make this plot interactive. To do so, we will use the {<strong>plotly<\/strong>} package and save the plots as html files that can be sent to our coworkers or decision-makers so that they can interact directly with the data.<\/p>\n<p><span style=\"text-decoration: underline;\"><strong>Data<\/strong><\/span><\/p>\n<p>We will use the same simulated data from <strong><span style=\"color: #0000ff;\"><a style=\"color: #0000ff;\" href=\"https:\/\/optimumsportsperformance.com\/blog\/box-dotplots-for-performance-visuals\/\">yesterday<\/a> <\/span><\/strong><span style=\"color: #000000;\">and also load the {<strong>plotly<\/strong>} library.<br \/>\n<\/span><\/p>\n<pre class=\"brush: r; title: ; notranslate\" title=\"\">\r\n### Load libraries -----------------------------------------------\r\nlibrary(tidyverse)\r\nlibrary(randomNames)\r\nlibrary(plotly)\r\n\r\n### Data -------------------------------------------------------\r\nset.seed(2022)\r\ndat &lt;- tibble( participant = randomNames(n = 20), performance = rnorm(n = 20, mean = 100, sd = 10)) <\/pre>\n<p><span style=\"text-decoration: underline;\"><strong>Interactive plotly plot<\/strong><\/span><\/p>\n<p>Our first two plots will be the same, one vertical and one horizontal. Plotly is a little different than ggplot2 in syntax.<\/p>\n<ul>\n<li>I start by creating a base plot, indicating I want the plot to be a boxplot. I also tell plotly that I want to group by participant, so that the dots will show up alongside the boxplot, as they did in yesterday&#8217;s visual.<\/li>\n<li>Once I&#8217;ve specified the base plot, I indicate that I want <strong>boxpoints<\/strong> to add the points next to the boxplot and set some colors (again, using a colorblind friendly palette)<\/li>\n<li>Finally, I add axis labels and a title.<\/li>\n<li>For easy, I use the <strong>subplot() <\/strong>function to place the two plots next to each other so that you can compare the vertical and horizontal plot and see which you prefer.<\/li>\n<\/ul>\n<pre class=\"brush: r; title: ; notranslate\" title=\"\">\r\n### Build plotly plot -------------------------------------------\r\n# Set plot base\r\nperf_plt &lt;- plot_ly(dat, type = &quot;box&quot;) %&gt;%\r\n  group_by(participant)\r\n\r\n# Vertical plot\r\nvert_plt &lt;- perf_plt %&gt;%\r\n  add_boxplot(y = ~performance,\r\n              boxpoints = &quot;all&quot;,\r\n              line = list(color = 'black'),\r\n              text = ~participant,\r\n              marker = list(color = '#56B4E9',\r\n                            size = 15)) %&gt;% \r\n  layout(xaxis = list(showticklabels = FALSE)) %&gt;%\r\n  layout(yaxis = list(title = &quot;Performance&quot;)) %&gt;%\r\n  layout(title = &quot;Team Performance&quot;)       \r\n\r\n# Horizontal plot\r\nhz_plt &lt;- perf_plt %&gt;%\r\n  add_boxplot(x = ~performance,\r\n              boxpoints = &quot;all&quot;,\r\n              line = list(color = 'black'),\r\n              text = ~participant,\r\n              marker = list(color = '#E69F00',\r\n                            size = 15)) %&gt;% \r\n  layout(yaxis = list(showticklabels = FALSE)) %&gt;%\r\n  layout(xaxis = list(title = &quot;Performance&quot;)) %&gt;%\r\n  layout(title = &quot;Team Performance&quot;) \r\n\r\n## put the two plots next to each other\r\nsubplot(vert_plt, hz_plt)\r\n\r\n\r\n\r\n<\/pre>\n<p>&nbsp;<\/p>\n<ul>\n<li>Statically, we can see the plot below and if you click on the <span style=\"color: #ff0000;\"><strong>red<\/strong><\/span> link beneath it you will be taken to the interactive version, where you can hover over the points and see the individual athlete&#8217;s name and performance on the test.<\/li>\n<\/ul>\n<p><a href=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2022\/12\/Screen-Shot-2022-12-20-at-10.22.32-PM.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-2753\" src=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2022\/12\/Screen-Shot-2022-12-20-at-10.22.32-PM.png\" alt=\"\" width=\"798\" height=\"576\" srcset=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2022\/12\/Screen-Shot-2022-12-20-at-10.22.32-PM.png 798w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2022\/12\/Screen-Shot-2022-12-20-at-10.22.32-PM-300x217.png 300w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2022\/12\/Screen-Shot-2022-12-20-at-10.22.32-PM-768x554.png 768w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2022\/12\/Screen-Shot-2022-12-20-at-10.22.32-PM-624x450.png 624w\" sizes=\"auto, (max-width: 798px) 100vw, 798px\" \/><\/a><\/p>\n<p><strong><span style=\"color: #ff0000;\"><a style=\"color: #ff0000;\" href=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2022\/12\/interactive_plt1.html\">interactive_plt1<\/a><\/span><\/strong><\/p>\n<p>&nbsp;<\/p>\n<p><strong><span style=\"text-decoration: underline;\">Interactive plotly with selector option<\/span><br \/>\n<\/strong><\/p>\n<p>Next, we build the same plot but add a selector box so that the user can select the individual of interest and see their point relative to the boxplot (the population data).<\/p>\n<p>This approach requires a few steps:<\/p>\n<ul>\n<li>I have to create a highlight key to explicitly tell plotly that I want to be able to highlight the participants.<\/li>\n<li>Next I create the base plot but this time instead of using the original data, I pass in the highlight key that I created in step 1.<\/li>\n<li>I build the plot just like before.<\/li>\n<li>Once the plot has been built I use the <strong>highlight()<\/strong> function to tell plotly how I want the plot to behave.<\/li>\n<\/ul>\n<p><strong>NOTE:<\/strong> This approach is super useful and easy and doesn&#8217;t require a shiny server to share the results. That said, I find this aspect of plotly to be a bit clunky and, when given the choice between this or using shiny, I take shiny because it has a lot more options to customize it exactly how you want. The downside is that you&#8217;d need a shiny server to share your results with colleagues or decision-makers, so there is a trade off.<\/p>\n<pre class=\"brush: r; title: ; notranslate\" title=\"\">\r\n### plotly with selection box -------------------------------------------\r\n# set 'particpant' as the group to select\r\nperson_of_interest &lt;- highlight_key(dat, ~participant)\r\n\r\n# create a new base plotly plot using the person_of_interest_element\r\nselection_perf_plt &lt;- plot_ly(person_of_interest, type = &quot;box&quot;) %&gt;%\r\n  group_by(participant)\r\n\r\n# build the plot\r\nplt_selector &lt;- selection_perf_plt %&gt;%\r\n  group_by(participant) %&gt;%\r\n  add_boxplot(x = ~performance,\r\n              boxpoints = &quot;all&quot;,\r\n              line = list(color = 'black'),\r\n              text = ~participant,\r\n              marker = list(color = '#56B4E9',\r\n                            size = 15)) %&gt;% \r\n  layout(yaxis = list(showticklabels = FALSE)) %&gt;%\r\n  layout(xaxis = list(title = &quot;Performance&quot;)) %&gt;%\r\n  layout(title = &quot;Team Performance&quot;)   \r\n\r\n# create the selector tool\r\nplt_selector %&gt;%\r\n  highlight(on = 'plotly_click',\r\n              off = 'plotly_doubleclick',\r\n              selectize = TRUE,\r\n              dynamic = TRUE,\r\n              persistent = TRUE)\r\n<\/pre>\n<p>&nbsp;<\/p>\n<ul>\n<li>Statically, we can see what the plot looks like below.<\/li>\n<li>Below the static image you can click the <span style=\"color: #ff0000;\"><strong>red<\/strong><\/span> link to see me walk through the interactive plot. Notice that as I select participants it selects them out. I can add as many as I want and change color to highlight certain participants over others. Additionally, once I begin to remove participants you&#8217;ll notice that plotly will create a boxplot for the selected sub population, which may be useful when communicating performance results.<\/li>\n<li>Finally, the last <span style=\"color: #ff0000;\"><strong>red<\/strong><\/span> link will allow you to open the interactive tool yourself and play around with it.<\/li>\n<\/ul>\n<p><a href=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2022\/12\/Screen-Shot-2022-12-20-at-10.29.08-PM.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-large wp-image-2754\" src=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2022\/12\/Screen-Shot-2022-12-20-at-10.29.08-PM-1024x513.png\" alt=\"\" width=\"625\" height=\"313\" srcset=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2022\/12\/Screen-Shot-2022-12-20-at-10.29.08-PM-1024x513.png 1024w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2022\/12\/Screen-Shot-2022-12-20-at-10.29.08-PM-300x150.png 300w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2022\/12\/Screen-Shot-2022-12-20-at-10.29.08-PM-768x384.png 768w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2022\/12\/Screen-Shot-2022-12-20-at-10.29.08-PM-624x312.png 624w, https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2022\/12\/Screen-Shot-2022-12-20-at-10.29.08-PM.png 1626w\" sizes=\"auto, (max-width: 625px) 100vw, 625px\" \/><\/a><\/p>\n<p><strong><span style=\"color: #ff0000;\"><a style=\"color: #ff0000;\" href=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2022\/12\/interactive_plt2_video.mov\">interactive_plt2_video<\/a><\/span><\/strong><\/p>\n<p><strong><span style=\"color: #ff0000;\"><a style=\"color: #ff0000;\" href=\"https:\/\/optimumsportsperformance.com\/blog\/wp-content\/uploads\/2022\/12\/interactive_plt2.html\">interactive_plt2<\/a><\/span><\/strong><\/p>\n<p><span style=\"text-decoration: underline;\"><strong>Wrapping Up<\/strong><\/span><\/p>\n<p>Today&#8217;s article provided some interactive options for the static plots that were created in yesterday&#8217;s blog article.<\/p>\n<p>As always, the complete code for this article is available on my <span style=\"color: #0000ff;\"><strong><a style=\"color: #0000ff;\" href=\"https:\/\/github.com\/pw2\/R-Tips-Tricks\/blob\/master\/boxplot_with_points_for_performance_visual_plotly_interactive.R\">GITHUB page<\/a><\/strong><\/span>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Yesterday, I provided some code to make a simple boxplot with doplot in order to visualize an athlete&#8217;s performance relative to their peers. Today, we will try and make this plot interactive. To do so, we will use the {plotly} package and save the plots as html files that can be sent to our coworkers [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[45,43,42,27],"tags":[],"class_list":["post-2750","post","type-post","status-publish","format-standard","hentry","category-r-tips-tricks","category-sports-analytics","category-sports-science","category-strength-and-conditioning"],"_links":{"self":[{"href":"https:\/\/optimumsportsperformance.com\/blog\/wp-json\/wp\/v2\/posts\/2750","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/optimumsportsperformance.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/optimumsportsperformance.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/optimumsportsperformance.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/optimumsportsperformance.com\/blog\/wp-json\/wp\/v2\/comments?post=2750"}],"version-history":[{"count":7,"href":"https:\/\/optimumsportsperformance.com\/blog\/wp-json\/wp\/v2\/posts\/2750\/revisions"}],"predecessor-version":[{"id":2762,"href":"https:\/\/optimumsportsperformance.com\/blog\/wp-json\/wp\/v2\/posts\/2750\/revisions\/2762"}],"wp:attachment":[{"href":"https:\/\/optimumsportsperformance.com\/blog\/wp-json\/wp\/v2\/media?parent=2750"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/optimumsportsperformance.com\/blog\/wp-json\/wp\/v2\/categories?post=2750"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/optimumsportsperformance.com\/blog\/wp-json\/wp\/v2\/tags?post=2750"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}