{"id":110,"date":"2021-05-02T15:34:41","date_gmt":"2021-05-02T15:34:41","guid":{"rendered":"http:\/\/aurimas.eu\/blog\/?p=110"},"modified":"2022-07-23T04:58:34","modified_gmt":"2022-07-23T04:58:34","slug":"football-field-variable-width-bar-charts","status":"publish","type":"post","link":"https:\/\/aurimas.eu\/blog\/2021\/05\/football-field-variable-width-bar-charts\/","title":{"rendered":"&#8220;Football field&#8221; (variable-width bar) charts in R \/ Power BI"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">An interesting way to present long-term contracts and an opportunity to try our R visuals in Power BI<\/h2>\n\n\n\n<p>On a recent project, our team was asked if we can visualize long term real estate contracts on a &#8220;football field&#8221; chart. Now, I&#8217;ve heard of snowball charts, waterfall charts, but a football field chart was something new. A quick search, however, showed that I was missing out.  <\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/i0.wp.com\/aurimas.eu\/a\/wp-content\/uploads\/Screenshot-from-2021-04-29-23-26-00.png\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"435\" src=\"https:\/\/i0.wp.com\/aurimas.eu\/a\/wp-content\/uploads\/Screenshot-from-2021-04-29-23-26-00-1024x435.png?resize=1024%2C435\" alt=\"\" class=\"wp-image-111\" srcset=\"https:\/\/i0.wp.com\/aurimas.eu\/a\/wp-content\/uploads\/Screenshot-from-2021-04-29-23-26-00.png?resize=1024%2C435&amp;ssl=1 1024w, https:\/\/i0.wp.com\/aurimas.eu\/a\/wp-content\/uploads\/Screenshot-from-2021-04-29-23-26-00.png?resize=300%2C127&amp;ssl=1 300w, https:\/\/i0.wp.com\/aurimas.eu\/a\/wp-content\/uploads\/Screenshot-from-2021-04-29-23-26-00.png?resize=768%2C326&amp;ssl=1 768w, https:\/\/i0.wp.com\/aurimas.eu\/a\/wp-content\/uploads\/Screenshot-from-2021-04-29-23-26-00.png?w=1426&amp;ssl=1 1426w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><\/a><figcaption>Yup, it&#8217;s a thing.<\/figcaption><\/figure>\n\n\n\n<p>What exactly is a football field chart? It effectively is a column\/bar chart where the individual bars are used to indicate range (and thus start\/end in arbitrary places). Most examples on the internet relate to valuation ranges. In our case, the idea was to display contracts over time as discreet bars, varying the bar width with contract value changes.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/i0.wp.com\/aurimas.eu\/a\/wp-content\/uploads\/IMG_20210502_155841-scaled.jpg\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"505\" src=\"https:\/\/i0.wp.com\/aurimas.eu\/a\/wp-content\/uploads\/IMG_20210502_155841-1024x505.jpg?resize=1024%2C505\" alt=\"\" class=\"wp-image-117\" srcset=\"https:\/\/i0.wp.com\/aurimas.eu\/a\/wp-content\/uploads\/IMG_20210502_155841-scaled.jpg?resize=1024%2C505&amp;ssl=1 1024w, https:\/\/i0.wp.com\/aurimas.eu\/a\/wp-content\/uploads\/IMG_20210502_155841-scaled.jpg?resize=300%2C148&amp;ssl=1 300w, https:\/\/i0.wp.com\/aurimas.eu\/a\/wp-content\/uploads\/IMG_20210502_155841-scaled.jpg?resize=768%2C379&amp;ssl=1 768w, https:\/\/i0.wp.com\/aurimas.eu\/a\/wp-content\/uploads\/IMG_20210502_155841-scaled.jpg?resize=1536%2C758&amp;ssl=1 1536w, https:\/\/i0.wp.com\/aurimas.eu\/a\/wp-content\/uploads\/IMG_20210502_155841-scaled.jpg?resize=2048%2C1010&amp;ssl=1 2048w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><\/a><figcaption>Something along these lines<\/figcaption><\/figure>\n\n\n\n<p>We were planning to deliver our insights via Power BI reports, so my immediate reaction was to look whether we could create these sort of charts using <a href=\"https:\/\/docs.microsoft.com\/en-us\/power-bi\/create-reports\/desktop-r-visuals\">Power BI&#8217;s R visuals<\/a> and <a href=\"https:\/\/ggplot2.tidyverse.org\/index.html\">ggplot2<\/a>. Turns out, ggplot2 includes exactly what we needed in this scenario. Its <a href=\"https:\/\/ggplot2.tidyverse.org\/reference\/geom_tile.html\"><kbd>geom_tile() \/ geom_rect()<\/kbd><\/a> allow drawing arbitrary rectangles. If you prefer Python, the ggplot2-inspired <a href=\"https:\/\/plotnine.readthedocs.io\">plotnine package<\/a> supports the same geoms, and, admittedly has way more impressive examples.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/i0.wp.com\/aurimas.eu\/a\/wp-content\/uploads\/geom_tile_34_0.png\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"488\" src=\"https:\/\/i0.wp.com\/aurimas.eu\/a\/wp-content\/uploads\/geom_tile_34_0-1024x488.png?resize=1024%2C488\" alt=\"\" class=\"wp-image-118\" srcset=\"https:\/\/i0.wp.com\/aurimas.eu\/a\/wp-content\/uploads\/geom_tile_34_0.png?resize=1024%2C488&amp;ssl=1 1024w, https:\/\/i0.wp.com\/aurimas.eu\/a\/wp-content\/uploads\/geom_tile_34_0.png?resize=300%2C143&amp;ssl=1 300w, https:\/\/i0.wp.com\/aurimas.eu\/a\/wp-content\/uploads\/geom_tile_34_0.png?resize=768%2C366&amp;ssl=1 768w, https:\/\/i0.wp.com\/aurimas.eu\/a\/wp-content\/uploads\/geom_tile_34_0.png?w=1183&amp;ssl=1 1183w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><\/a><figcaption>This is an example of what you can achieve with the ggplot2 \/ plotnine packages. Technically, this is a bar chart!<br>Credit: <a href=\"https:\/\/plotnine.readthedocs.io\/en\/stable\/generated\/plotnine.geoms.geom_tile.html\">Plotnine geom_tile() documentation<\/a><\/figcaption><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Getting to the right visual in R<\/h3>\n\n\n\n<p>For the purpose of this blog post, I generated some synthetic data representing a real estate portfolio in Germany. In case you are interested in how it was created, check out the <a href=\"https:\/\/github.com\/kamicollo\/football-field-charts\/blob\/main\/generate_data.py\">python script with details<\/a> (it was a lot of fun to play around with various probability distributions, I may write up a blog post about that separately one day). <\/p>\n\n\n\n<p>We effectively had: 1) a list of contracts 2) a list of terms associated with each contract and 3) a monthly rental portfolio data set derived from the contract\/term information. <\/p>\n\n\n\n<figure class=\"wp-block-gallery columns-2 is-cropped wp-block-gallery-1 is-layout-flex wp-block-gallery-is-layout-flex\"><ul class=\"blocks-gallery-grid\"><li class=\"blocks-gallery-item\"><figure><a href=\"https:\/\/i0.wp.com\/aurimas.eu\/a\/wp-content\/uploads\/Screenshot-from-2021-05-02-16-41-48.png\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"575\" height=\"359\" src=\"https:\/\/i0.wp.com\/aurimas.eu\/a\/wp-content\/uploads\/Screenshot-from-2021-05-02-16-41-48.png?resize=575%2C359\" alt=\"\" data-id=\"119\" data-full-url=\"http:\/\/aurimas.eu\/a\/wp-content\/uploads\/Screenshot-from-2021-05-02-16-41-48.png\" data-link=\"https:\/\/aurimas.eu\/blog\/?attachment_id=119\" class=\"wp-image-119\" srcset=\"https:\/\/i0.wp.com\/aurimas.eu\/a\/wp-content\/uploads\/Screenshot-from-2021-05-02-16-41-48.png?w=575&amp;ssl=1 575w, https:\/\/i0.wp.com\/aurimas.eu\/a\/wp-content\/uploads\/Screenshot-from-2021-05-02-16-41-48.png?resize=300%2C187&amp;ssl=1 300w\" sizes=\"auto, (max-width: 575px) 100vw, 575px\" \/><\/a><\/figure><\/li><li class=\"blocks-gallery-item\"><figure><a href=\"https:\/\/i0.wp.com\/aurimas.eu\/a\/wp-content\/uploads\/Screenshot-from-2021-05-02-16-41-20.png\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"634\" height=\"366\" src=\"https:\/\/i0.wp.com\/aurimas.eu\/a\/wp-content\/uploads\/Screenshot-from-2021-05-02-16-41-20.png?resize=634%2C366\" alt=\"\" data-id=\"120\" data-full-url=\"http:\/\/aurimas.eu\/a\/wp-content\/uploads\/Screenshot-from-2021-05-02-16-41-20.png\" data-link=\"https:\/\/aurimas.eu\/blog\/?attachment_id=120\" class=\"wp-image-120\" srcset=\"https:\/\/i0.wp.com\/aurimas.eu\/a\/wp-content\/uploads\/Screenshot-from-2021-05-02-16-41-20.png?w=634&amp;ssl=1 634w, https:\/\/i0.wp.com\/aurimas.eu\/a\/wp-content\/uploads\/Screenshot-from-2021-05-02-16-41-20.png?resize=300%2C173&amp;ssl=1 300w, https:\/\/i0.wp.com\/aurimas.eu\/a\/wp-content\/uploads\/Screenshot-from-2021-05-02-16-41-20.png?resize=400%2C230&amp;ssl=1 400w\" sizes=\"auto, (max-width: 634px) 100vw, 634px\" \/><\/a><\/figure><\/li><\/ul><figcaption class=\"blocks-gallery-caption\">Our key datasets<\/figcaption><\/figure>\n\n\n\n<p>Getting to the desired visualization was surprisingly easy. First, let&#8217;s select top 10 contracts by their future value (you don&#8217;t really want to visualize all contracts at once unless you intend to print it on A0 size paper..)<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: r; title: ; notranslate\" title=\"\">\nlibrary(tidyverse)\nlibrary(data.table)\nlibrary(RColorBrewer)\n\n#read in the table that contains individual contract terms with associated start\/end dates\nterms = fread(&quot;~\/coding\/real-estate\/terms.csv&quot;)\n\n#read in the table that contains monthly information for each term (SQM \/ rent income in a month)\n#add proper year\/month columns to the dataframe\nPL = fread(&quot;~\/coding\/real-estate\/monthly_data.csv&quot;) %&gt;% \n  mutate(date = as.Date(strptime(paste0(month,&quot;-01&quot;), format=&quot;%Y-%m-%d&quot;))) %&gt;%\n  mutate(year = year(date), month = month(date))\n\n#calculate future value per contract (assuming we're at the end of 2020)\n# filter it down to top10 contracts only\ntop_10_contracts = PL %&gt;% filter(date &gt; &quot;2020-12-31&quot;) %&gt;% \n  inner_join(terms, by='term_id') %&gt;%\n  inner_join(contracts, by=&quot;contract_id&quot;) %&gt;% \n  group_by(contract_id) %&gt;% summarize(future_value = sum(rent), .groups='drop_last') %&gt;% \n  arrange(desc(future_value)) %&gt;% head(10)\n<\/pre><\/div>\n\n\n<p>Then, we can proceed to get the first iteration of the chart. As geom_tile() requires &#8220;central&#8221; positions and width\/height of the rectangles, let&#8217;s calculate the mid-period of each term to be used as the x-axis position, width will be equal to number of days, and height to monthly rent. Let&#8217;s try with one contract.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: r; title: ; notranslate\" title=\"\">\nchart_df = \n  #filter to 1 contract\n  top_10_contracts&#x5B;1,] %&gt;% \n  #get terms of contract\n  inner_join(terms, by=&quot;contract_id&quot;) %&gt;% \n  #calculate # of days of each term\n  mutate(width = as.numeric(difftime(end, start, units=&quot;days&quot;))) %&gt;% \n  #calculate the mid-point of each term\n  mutate(mid_point = start + width\/2) %&gt;% \n  #extensions are numeric, make sure they are treated as discrete variables\n  mutate(extension = as.factor(extension)) \n\nggplot(chart_df) + \n  geom_tile(aes(\n    x=mid_point, \n    y=contract_id, \n    width=width, \n    height=monthly_rent, \n    fill=extension\n  ))\n<\/pre><\/div>\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/i0.wp.com\/aurimas.eu\/a\/wp-content\/uploads\/Rplot01.png\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1001\" height=\"507\" src=\"https:\/\/i0.wp.com\/aurimas.eu\/a\/wp-content\/uploads\/Rplot01.png?resize=1001%2C507\" alt=\"\" class=\"wp-image-124\" srcset=\"https:\/\/i0.wp.com\/aurimas.eu\/a\/wp-content\/uploads\/Rplot01.png?w=1001&amp;ssl=1 1001w, https:\/\/i0.wp.com\/aurimas.eu\/a\/wp-content\/uploads\/Rplot01.png?resize=300%2C152&amp;ssl=1 300w, https:\/\/i0.wp.com\/aurimas.eu\/a\/wp-content\/uploads\/Rplot01.png?resize=768%2C389&amp;ssl=1 768w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><\/a><figcaption>Not bad for an initial attempt.<\/figcaption><\/figure>\n\n\n\n<p>Seems like we&#8217;re on the right track, even if not beautiful. We can fix that later. Let&#8217;s try with 10 contracts.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/i0.wp.com\/aurimas.eu\/a\/wp-content\/uploads\/Rplot2.png\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1001\" height=\"507\" src=\"https:\/\/i0.wp.com\/aurimas.eu\/a\/wp-content\/uploads\/Rplot2.png?resize=1001%2C507\" alt=\"\" class=\"wp-image-125\" srcset=\"https:\/\/i0.wp.com\/aurimas.eu\/a\/wp-content\/uploads\/Rplot2.png?w=1001&amp;ssl=1 1001w, https:\/\/i0.wp.com\/aurimas.eu\/a\/wp-content\/uploads\/Rplot2.png?resize=300%2C152&amp;ssl=1 300w, https:\/\/i0.wp.com\/aurimas.eu\/a\/wp-content\/uploads\/Rplot2.png?resize=768%2C389&amp;ssl=1 768w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><\/a><figcaption>Accidental art?<\/figcaption><\/figure>\n\n\n\n<p>Right. That&#8217;s not that great. While initially I thought that R, for some reason, places each series on top of each other (i.e. ignores Y-axis parameter), I later realized the real issue was bar heights. They needed to be re-scaled. Here&#8217;s a fixed version where each bar height is scaled to maximum of 1 (and some formatting tweaks).<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: r; highlight: [6]; title: ; notranslate\" title=\"\">\nggplot(chart_df) + \n  geom_tile(aes(\n    x=mid_point, \n    y=contract_id, \n    width=width, \n    height=monthly_rent\/max(monthly_rent), #that's the fix\n    fill=extension)\n  ) +\n  ylab(&quot;&quot;) + xlab(&quot;Year&quot;) + theme_bw() + \n  theme(panel.grid.minor.y = element_blank(), panel.grid.major.y = element_blank())\n<\/pre><\/div>\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/i0.wp.com\/aurimas.eu\/a\/wp-content\/uploads\/Rplot3.png\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1001\" height=\"507\" src=\"https:\/\/i0.wp.com\/aurimas.eu\/a\/wp-content\/uploads\/Rplot3.png?resize=1001%2C507\" alt=\"\" class=\"wp-image-126\" srcset=\"https:\/\/i0.wp.com\/aurimas.eu\/a\/wp-content\/uploads\/Rplot3.png?w=1001&amp;ssl=1 1001w, https:\/\/i0.wp.com\/aurimas.eu\/a\/wp-content\/uploads\/Rplot3.png?resize=300%2C152&amp;ssl=1 300w, https:\/\/i0.wp.com\/aurimas.eu\/a\/wp-content\/uploads\/Rplot3.png?resize=768%2C389&amp;ssl=1 768w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><\/a><figcaption>Much better.<\/figcaption><\/figure>\n\n\n\n<p>Almost perfect. Just need to add labels that indicate total value and sort the contracts from the highest value to the lowest. Here&#8217;s the final code that achieves all that.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: r; title: ; notranslate\" title=\"\">\nchart_df = \n  top_10_contracts %&gt;%\n  #get terms of top 10 contracts\n  inner_join(terms, by=&quot;contract_id&quot;) %&gt;% \n  #calculate # of days of each term\n  mutate(width = as.numeric(difftime(end, start, units=&quot;days&quot;))) %&gt;% \n  #calculate the mid-point of each term\n  mutate(mid_point = start + width\/2) %&gt;% \n  #extensions are numeric, make sure they are treated as discrete variables\n  mutate(extension = as.factor(extension)) %&gt;% \n  #reorder contracts\n  mutate(contract_id = reorder(as.character(contract_id), future_value, mean)) \n\nlabels = \n  #group by contract\n  chart_df %&gt;% group_by(contract_id) %&gt;% \n  #calculate total value and get end date\n  summarize(end_date = max(end), value = max(future_value), .groups=&quot;drop_last&quot;) %&gt;% \n  #format total value\n  mutate(label = paste0(round(value \/ 1000000, 1), &quot;M&quot;)) \n\nggplot(chart_df) + \n  #create rectangle geoms\n  geom_tile(aes(\n    x=mid_point, \n    y=contract_id, \n    width=width, \n    height=monthly_rent\/max(monthly_rent), \n    fill=extension\n  )) + \n  #deal with axis labels\n  ylab(&quot;&quot;) + xlab(&quot;Year&quot;) + theme_bw() + \n  #remove gridlines on Y-axis\n  theme(panel.grid.minor.y = element_blank(), panel.grid.major.y = element_blank()) +\n  #add labels at the end of each contract bar\n  geom_label(data = labels, mapping=aes(end_date + 400, contract_id, label=label)) +\n  #apply a better color palette\n  scale_fill_brewer(palette = &quot;RdYlGn&quot;)\n<\/pre><\/div>\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/i0.wp.com\/aurimas.eu\/a\/wp-content\/uploads\/Rplot4.png\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1001\" height=\"507\" src=\"https:\/\/i0.wp.com\/aurimas.eu\/a\/wp-content\/uploads\/Rplot4.png?resize=1001%2C507\" alt=\"\" class=\"wp-image-127\" srcset=\"https:\/\/i0.wp.com\/aurimas.eu\/a\/wp-content\/uploads\/Rplot4.png?w=1001&amp;ssl=1 1001w, https:\/\/i0.wp.com\/aurimas.eu\/a\/wp-content\/uploads\/Rplot4.png?resize=300%2C152&amp;ssl=1 300w, https:\/\/i0.wp.com\/aurimas.eu\/a\/wp-content\/uploads\/Rplot4.png?resize=768%2C389&amp;ssl=1 768w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><\/a><figcaption>Here we are.<\/figcaption><\/figure>\n\n\n\n<p><em>Edit: I<\/em> received a comment (thanks Q!) that the chart may look more intuitive if there is a shadow behind each bar indicating the maximum monthly value on the chart for reference. Here is how that could look like (code-wise, that is just another geom_tile() layer).<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1001\" height=\"507\" src=\"https:\/\/i0.wp.com\/aurimas.eu\/a\/wp-content\/uploads\/Rplot_5_background.png?resize=1001%2C507\" alt=\"\" class=\"wp-image-150\" srcset=\"https:\/\/i0.wp.com\/aurimas.eu\/a\/wp-content\/uploads\/Rplot_5_background.png?w=1001&amp;ssl=1 1001w, https:\/\/i0.wp.com\/aurimas.eu\/a\/wp-content\/uploads\/Rplot_5_background.png?resize=300%2C152&amp;ssl=1 300w, https:\/\/i0.wp.com\/aurimas.eu\/a\/wp-content\/uploads\/Rplot_5_background.png?resize=768%2C389&amp;ssl=1 768w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Putting it all together in Power BI<\/h3>\n\n\n\n<p>Power BI&#8217;s R visual integration is incredibly simple. Effectively, all you need to do is to use their built-in R visual, drop in the fields that you want to have available as part of the dataframe in R (Power BI does all the aggregation for you, it&#8217;s effectively passing the same dataset as if it was a matrix visual) and then adjust R code accordingly (some of the data transforms were no longer required). <\/p>\n\n\n\n<p>While not applicable in this case, a couple of caveats about R Visuals in Power BI:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>R visuals can be cross-filtered but are not interactive themselves and do not cross-filter other visuals in the report;<\/li><li>When published to Power BI Service, they will work as long as you use (a long list) of <a rel=\"noreferrer noopener\" href=\"https:\/\/docs.microsoft.com\/en-us\/power-bi\/connect-data\/service-r-packages-support\" target=\"_blank\">supported packages<\/a>;<\/li><li>There are <a href=\"https:\/\/docs.microsoft.com\/en-us\/power-bi\/create-reports\/desktop-r-visuals#known-limitations\" target=\"_blank\" rel=\"noreferrer noopener\">certain limitations<\/a> to number of data points, processing time and etc.<\/li><\/ul>\n\n\n\n<p>Combine it with a <a href=\"https:\/\/www.sqlbi.com\/articles\/filtering-the-top-products-alongside-the-other-products-in-power-bi\/\">dynamic TopN selection<\/a>, and voil\u00e0. Click to see it in action.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/i0.wp.com\/aurimas.eu\/a\/wp-content\/uploads\/football-powerbi.gif\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"521\" src=\"https:\/\/i0.wp.com\/aurimas.eu\/a\/wp-content\/uploads\/football-powerbi-1024x521.gif?resize=1024%2C521\" alt=\"\" class=\"wp-image-135\" srcset=\"https:\/\/i0.wp.com\/aurimas.eu\/a\/wp-content\/uploads\/football-powerbi.gif?resize=1024%2C521&amp;ssl=1 1024w, https:\/\/i0.wp.com\/aurimas.eu\/a\/wp-content\/uploads\/football-powerbi.gif?resize=300%2C153&amp;ssl=1 300w, https:\/\/i0.wp.com\/aurimas.eu\/a\/wp-content\/uploads\/football-powerbi.gif?resize=768%2C391&amp;ssl=1 768w, https:\/\/i0.wp.com\/aurimas.eu\/a\/wp-content\/uploads\/football-powerbi.gif?resize=1536%2C782&amp;ssl=1 1536w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><\/a><figcaption>A quick Power BI mock-up with dynamic interactions<\/figcaption><\/figure>\n\n\n\n<p>All code used in this blog post is available at <a href=\"https:\/\/github.com\/kamicollo\/football-field-charts\">https:\/\/github.com\/kamicollo\/football-field-charts<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Displaying long-term contract value evolution via &#8220;football field&#8221; charts made with ggplot2 and integrated in Power BI.<\/p>\n","protected":false},"author":1,"featured_media":127,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[67],"tags":[71,68,69,70],"class_list":["post-110","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-data-analytics","tag-data-visualization","tag-football-field-charts","tag-power-bi","tag-r-visuals-in-power-bi"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/aurimas.eu\/a\/wp-content\/uploads\/Rplot4.png?fit=1001%2C507&ssl=1","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/paWzzQ-1M","_links":{"self":[{"href":"https:\/\/aurimas.eu\/blog\/wp-json\/wp\/v2\/posts\/110","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/aurimas.eu\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/aurimas.eu\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/aurimas.eu\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/aurimas.eu\/blog\/wp-json\/wp\/v2\/comments?post=110"}],"version-history":[{"count":14,"href":"https:\/\/aurimas.eu\/blog\/wp-json\/wp\/v2\/posts\/110\/revisions"}],"predecessor-version":[{"id":151,"href":"https:\/\/aurimas.eu\/blog\/wp-json\/wp\/v2\/posts\/110\/revisions\/151"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/aurimas.eu\/blog\/wp-json\/wp\/v2\/media\/127"}],"wp:attachment":[{"href":"https:\/\/aurimas.eu\/blog\/wp-json\/wp\/v2\/media?parent=110"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/aurimas.eu\/blog\/wp-json\/wp\/v2\/categories?post=110"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/aurimas.eu\/blog\/wp-json\/wp\/v2\/tags?post=110"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}