{"id":1493,"date":"2026-04-03T18:42:26","date_gmt":"2026-04-03T18:42:26","guid":{"rendered":"https:\/\/inphronesys.com\/?p=1493"},"modified":"2026-04-03T18:42:26","modified_gmt":"2026-04-03T18:42:26","slug":"your-line-chart-is-hiding-8-patterns-how-to-find-them-with-fpp3","status":"publish","type":"post","link":"https:\/\/inphronesys.com\/?p=1493","title":{"rendered":"Your Line Chart Is Hiding 8 Patterns: How to Find Them with fpp3"},"content":{"rendered":"<p>Four datasets. Same mean. Same variance. Same correlation. Same regression line.<\/p>\n<p>Completely different shapes.<\/p>\n<p>This is Anscombe&#8217;s Quartet \u2014 a famous statistical demonstration from 1973, and the single best argument for why you should <em>plot your data before you do anything else with it.<\/em> All four datasets produce identical summary statistics: mean of X = 9, mean of Y \u2248 7.5, variance nearly identical, and a correlation coefficient of r \u2248 0.816 across all four. Your ERP&#8217;s summary dashboard would show you the same numbers for each one and tell you everything is fine.<\/p>\n<p>Now look at what happens when you actually plot them:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/inphronesys.com\/wp-content\/uploads\/2026\/04\/tsgraphics_anscombe-1.png\" alt=\"Anscombe's Quartet: four datasets with identical statistics but completely different shapes\" \/><\/p>\n<p>Dataset I is the only one that fits a linear model. Dataset II is a perfect curve \u2014 the linear model is completely wrong. Dataset III has a single outlier dragging the line off course. And Dataset IV? The entire correlation is driven by one extreme point. Remove it and the relationship disappears.<\/p>\n<p>Same numbers. Four completely different stories. And if you hadn&#8217;t plotted them, you&#8217;d have treated all four identically \u2014 with a straight line and a confident MAPE.<\/p>\n<p>This is what happens in supply chain forecasting every single day. Someone pulls 36 months of demand data, calculates an average growth rate, fits a trend, and sends the forecast to the S&amp;OP meeting. Nobody plots it. Nobody checks whether the pattern is linear, curved, seasonal, or driven by a single outlier month when a customer accidentally ordered 10x their normal quantity and then returned half of it.<\/p>\n<p>&quot;The first thing to do in any data analysis task is to plot the data. Graphs enable many features of the data to be visualised, including patterns, unusual observations, changes over time, and relationships between variables.&quot; \u2014 Hyndman &amp; Athanasopoulos, <em>Forecasting: Principles and Practice<\/em><\/p>\n<p>Hyndman is right. And today, I&#8217;m going to show you the visual toolkit that makes plotting supply chain data not just easy, but genuinely fun. By the end of this post, you&#8217;ll have eight chart types in your arsenal \u2014 five from fpp3 and three bonus ones that go beyond the textbook \u2014 and you&#8217;ll never look at a demand summary table the same way again.<\/p>\n<h2>Your Line Chart Is Lying to You<\/h2>\n<p>In <a href=\"\/stop-forecasting-in-excel\">our first post this month<\/a>, we showed why R crushes Excel for forecasting. <a href=\"\/your-first-forecast-in-15-minutes\">Last time<\/a>, you installed R, RStudio, and fpp3, and produced your first real forecast. But we skipped a step. A critical one.<\/p>\n<p>We went straight from data to model. We didn&#8217;t <em>look<\/em> at the data first.<\/p>\n<p>That&#8217;s like a mechanic replacing your engine without popping the hood. Sure, a new engine might fix the problem. But what if the issue was a loose spark plug?<\/p>\n<p>Every forecasting model makes assumptions about your data. ETS assumes a certain error structure. ARIMA assumes stationarity (or that differencing achieves it). Even Seasonal Naive assumes the seasonal pattern is stable. If those assumptions are wrong \u2014 if your data has a structural break, or an outlier, or a changing seasonal pattern \u2014 the model will happily fit itself to garbage and give you a confident-looking garbage forecast.<\/p>\n<p>Visualization is how you check those assumptions <em>before<\/em> you bet your inventory on them. And fpp3 gives you a visual toolkit specifically designed for time series data \u2014 not just generic scatter plots, but purpose-built charts that each reveal a different hidden pattern.<\/p>\n<p>Let&#8217;s meet the toolkit. We&#8217;ll use Australian quarterly beer production as our primary dataset for the core fpp3 charts \u2014 so you can see how each visualization reveals something new about data you&#8217;ve already &quot;seen.&quot; Then we&#8217;ll explore three creative techniques with different data to show their unique strengths.<\/p>\n<h2>The fpp3 Visual Toolkit<\/h2>\n<h3>1. autoplot() \u2014 The Time Plot<\/h3>\n<p>The most basic visualization, and the one most teams skip. <code>autoplot()<\/code> plots your time series as a line chart with proper time axis formatting. Two lines of code:<\/p>\n<pre><code class=\"language-r\">beer &lt;- aus_production |&gt;\n  filter(year(Quarter) &gt;= 1992) |&gt;\n  select(Quarter, Beer)\n\nbeer |&gt; autoplot(Beer)\n<\/code><\/pre>\n<p><img decoding=\"async\" src=\"https:\/\/inphronesys.com\/wp-content\/uploads\/2026\/04\/tsgraphics_autoplot-1.png\" alt=\"Time plot of Australian beer production showing trend and seasonal pattern\" \/><\/p>\n<p><strong>What this tells a supply chain pro:<\/strong> You immediately see three things \u2014 the overall level (roughly 400\u2013500 megalitres per quarter), a slight downward trend over time, and a strong seasonal pattern that repeats every year. That seasonal pattern is Q4-dominant \u2014 Australians drink more beer in their summer (October\u2013December). You also see that the variability is roughly constant \u2014 the seasonal swings don&#8217;t get bigger or smaller, which tells you additive seasonality is probably appropriate.<\/p>\n<p>This is the chart you should have run before that S&amp;OP meeting. It takes ten seconds and saves you from building a forecast on data you haven&#8217;t actually looked at.<\/p>\n<h3>2. gg_season() \u2014 The Seasonal Overlay<\/h3>\n<p>Now we go deeper. <code>gg_season()<\/code> takes each year of data and overlays them on top of each other, all sharing the same x-axis (Q1 through Q4). This lets you compare the seasonal shape across years instantly:<\/p>\n<pre><code class=\"language-r\">beer |&gt; gg_season(Beer, labels = &quot;both&quot;)\n<\/code><\/pre>\n<p><img decoding=\"async\" src=\"https:\/\/inphronesys.com\/wp-content\/uploads\/2026\/04\/tsgraphics_season-1.png\" alt=\"Seasonal plot overlaying each year's beer production pattern\" \/><\/p>\n<p><strong>What this tells a supply chain pro:<\/strong> Is the seasonal pattern stable? Getting stronger? Shifting? This chart answers all three at a glance. You can see that Q4 is consistently the peak and Q2 is consistently the trough \u2014 but the peak has been getting slightly lower over the years. The overall &quot;shape&quot; of the season is stable, but the level is declining. If your seasonal factors in Excel haven&#8217;t been updated since 2005, this chart tells you they need revision.<\/p>\n<p>This is how you discover that your December spike has been creeping into November for three years. Or that your Q3 pre-build has shifted from August to July. Or that one year&#8217;s pattern was completely anomalous \u2014 and your model is treating it as normal.<\/p>\n<p>Your ERP vendor charges six figures for a dashboard that can&#8217;t do <code>gg_season()<\/code>.<\/p>\n<h3>3. gg_subseries() \u2014 The Subseries Means<\/h3>\n<p>This one is less well known, and it&#8217;s a gem. <code>gg_subseries()<\/code> splits your data into mini-panels \u2014 one per season (quarter, in our case). Within each panel, you see the observations for that quarter over time. And the horizontal blue line shows the mean for that period:<\/p>\n<pre><code class=\"language-r\">beer |&gt; gg_subseries(Beer)\n<\/code><\/pre>\n<p><img decoding=\"async\" src=\"https:\/\/inphronesys.com\/wp-content\/uploads\/2026\/04\/tsgraphics_subseries-1.png\" alt=\"Subseries plot showing each quarter's trend over time with blue mean lines\" \/><\/p>\n<p><strong>What this tells a supply chain pro:<\/strong> Is each season trending the same way, or are some quarters changing while others hold steady? Look at Q4 \u2014 it&#8217;s clearly declining. But Q2 might be more stable. That distinction matters enormously for planning: if your peak season is eroding while your trough stays flat, your overall demand is contracting, and your seasonal factors need to shrink the peak amplitude.<\/p>\n<p>This is the chart that tells you Q4 production has been declining for 15 years. And makes you ask: did anyone notice? Was this deliberate (market shift, health trends, category decline) or did it slip under the radar while everyone focused on the annual total?<\/p>\n<h3>4. gg_lag() \u2014 The Lag Scatter Plot<\/h3>\n<p>This chart asks: does last quarter&#8217;s production predict this quarter&#8217;s production? And if so, which lags matter most?<\/p>\n<pre><code class=\"language-r\">beer |&gt; gg_lag(Beer, lags = 1:9)\n<\/code><\/pre>\n<p><img decoding=\"async\" src=\"https:\/\/inphronesys.com\/wp-content\/uploads\/2026\/04\/tsgraphics_lag-1.png\" alt=\"Lag scatter plots showing correlations between current and past beer production values\" \/><\/p>\n<p><strong>What this tells a supply chain pro:<\/strong> Each panel plots the current quarter&#8217;s value (y-axis) against the value k quarters ago (x-axis). If you see a tight cluster along the diagonal, that lag is a strong predictor. The color coding shows which quarter each point belongs to.<\/p>\n<p>Look at lag 4 \u2014 that&#8217;s the &quot;same quarter last year&quot; comparison. If that panel shows a tight linear relationship, it means last year&#8217;s Q4 is a good predictor of this year&#8217;s Q4. That&#8217;s Seasonal Naive in visual form. If lag 1 also shows a tight relationship, recent momentum matters too. If only lag 4 is tight and lag 1 is scattered, your data is seasonal but not autoregressive \u2014 a critical distinction for model selection.<\/p>\n<p>This is the chart that tells you whether &quot;last quarter predicts this quarter&quot; or &quot;same quarter last year predicts this quarter.&quot; Your model choice depends on the answer. And yes, we just diagnosed a model selection problem by looking at a scatter plot of beer production. Sometimes the best tools are the simplest \u2014 and the ones that pair well with an actual beer.<\/p>\n<h3>5. ACF Plot \u2014 The Autocorrelation Fingerprint<\/h3>\n<p>The ACF (AutoCorrelation Function) plot is the single most information-dense chart in time series analysis. It summarizes the correlation structure of your entire dataset in one compact graph:<\/p>\n<pre><code class=\"language-r\">beer |&gt; ACF(Beer) |&gt; autoplot()\n<\/code><\/pre>\n<p><img decoding=\"async\" src=\"https:\/\/inphronesys.com\/wp-content\/uploads\/2026\/04\/tsgraphics_acf-1.png\" alt=\"ACF plot showing the autocorrelation fingerprint of beer production\" \/><\/p>\n<p><strong>What this tells a supply chain pro:<\/strong> Read it like a diagnostic scan. Three patterns to look for:<\/p>\n<ul>\n<li><strong>Slowly decaying bars<\/strong> = your data has a trend. The current value is correlated with many past values because they&#8217;re all riding the same trend.<\/li>\n<li><strong>Spikes at seasonal lags<\/strong> (4, 8, 12 for quarterly data) = your data has seasonality. Values are correlated with the same season in previous years.<\/li>\n<li><strong>Scalloped pattern<\/strong> (decay + spikes) = your data has both trend and seasonality. This is the most common pattern in supply chain data.<\/li>\n<\/ul>\n<p>The blue dashed lines mark the significance threshold. Bars that extend beyond them represent statistically significant autocorrelation. For beer data, you&#8217;ll see the scalloped pattern \u2014 confirmation that this data has both trend and seasonal components, which tells you an ETS or seasonal ARIMA model is appropriate.<\/p>\n<p>Three seconds of looking at this chart and you know whether ETS or ARIMA is the better starting point. Three seconds. Compare that to the hours people spend &quot;tuning&quot; models without first understanding their data&#8217;s correlation structure.<\/p>\n<h2>Beyond the Textbook<\/h2>\n<p>The five fpp3 charts above cover the essentials. But there are visualization techniques that go beyond what the textbook teaches \u2014 charts that are visually striking, immediately intuitive, and perfect for presentations where you need to make a point in under five seconds.<\/p>\n<h3>6. Ridgeline Plot \u2014 Distribution Mountains<\/h3>\n<p>A ridgeline plot (sometimes called a joy plot) stacks yearly distributions like mountain ranges, showing how the <em>shape<\/em> of your data changes over time. It uses the <code>ggridges<\/code> package (install it once with <code>install.packages(&quot;ggridges&quot;)<\/code>):<\/p>\n<pre><code class=\"language-r\">library(ggridges)\nbeer |&gt;\n  mutate(Year = factor(year(Quarter))) |&gt;\n  ggplot(aes(x = Beer, y = Year)) +\n  geom_density_ridges()\n<\/code><\/pre>\n<p><img decoding=\"async\" src=\"https:\/\/inphronesys.com\/wp-content\/uploads\/2026\/04\/tsgraphics_ridgeline-1.png\" alt=\"Ridgeline plot stacking yearly beer production distributions like mountain ranges\" \/><\/p>\n<p><strong>What this tells a supply chain pro:<\/strong> If your demand volatility is increasing, a ridgeline plot screams it at you. Wider &quot;mountains&quot; = more spread in that year&#8217;s values. If the mountains are getting wider over time, your demand is becoming harder to predict. If they&#8217;re shifting left or right, your baseline level is changing. And if one year has a weird double-peak shape, something structural happened that year.<\/p>\n<p>This chart is a showstopper in presentations. Your warehouse manager will stop scrolling. Your VP will ask &quot;what&#8217;s that?&quot; And you&#8217;ll say &quot;that&#8217;s our demand volatility by year, and it&#8217;s getting worse.&quot; Good luck getting that reaction from a pivot table.<\/p>\n<h3>7. Calendar Heatmap \u2014 The GitHub Contribution Graph<\/h3>\n<p>You&#8217;ve seen GitHub&#8217;s green contribution squares? Same idea, but for your warehouse data. Each cell represents a single day, arranged in a weekday \u00d7 week grid, colored by order volume. Daily data is where this chart shines \u2014 it reveals patterns that weekly or monthly aggregation hides completely:<\/p>\n<pre><code class=\"language-r\">orders |&gt;\n  mutate(\n    week = isoweek(date),\n    weekday = wday(date, label = TRUE)\n  ) |&gt;\n  ggplot(aes(x = week, y = weekday, fill = volume)) +\n  geom_tile()\n<\/code><\/pre>\n<p><img decoding=\"async\" src=\"https:\/\/inphronesys.com\/wp-content\/uploads\/2026\/04\/tsgraphics_calendar_heatmap-1.png\" alt=\"Calendar heatmap of daily warehouse orders showing weekday patterns and seasonal variation\" \/><\/p>\n<p><strong>What this tells a supply chain pro:<\/strong> Patterns jump off the screen. Monday order spikes from the weekend backlog. Friday dips because nobody submits purchase orders at 4 PM on a Friday. A dead week in August when the factory was shut down for maintenance. That one Wednesday in March that&#8217;s inexplicably hot \u2014 turns out a customer placed their entire quarter&#8217;s worth of orders in a single day.<\/p>\n<p>Your warehouse manager will understand this chart in two seconds. No statistics degree required. No explanation of autocorrelation needed. Dark square = high demand. Pattern of dark squares = recurring pattern. Done.<\/p>\n<h3>8. Month \u00d7 Year Tile Heatmap \u2014 Ten Years in One Image<\/h3>\n<p>The tile heatmap puts months on the y-axis, years on the x-axis, and encodes the value as color. It&#8217;s the most compact way to show both seasonality AND trend simultaneously:<\/p>\n<pre><code class=\"language-r\">a10_data |&gt;\n  ggplot(aes(x = year, y = month, fill = cost)) +\n  geom_tile() +\n  scale_fill_viridis_c()\n<\/code><\/pre>\n<p><img decoding=\"async\" src=\"https:\/\/inphronesys.com\/wp-content\/uploads\/2026\/04\/tsgraphics_tile_heatmap-1.png\" alt=\"Tile heatmap showing monthly antidiabetic drug sales across years \u2014 seasonality and trend in one view\" \/><\/p>\n<p><strong>What this tells a supply chain pro:<\/strong> Read it two ways. Read across a row: you see the trend for that month over years. Read down a column: you see the seasonal pattern for that year. Read the overall gradient from top-left to bottom-right: you see the combined trend and seasonality at once. Fifteen years of monthly data in a single image.<\/p>\n<p>For the a10 antidiabetic drug data, the heatmap reveals something autoplot hints at but doesn&#8217;t make obvious \u2014 January is consistently the hottest month. Why? Australia&#8217;s Pharmaceutical Benefits Scheme resets its safety net threshold on January 1, so patients rush to fill extra prescriptions in late December while subsidies still apply \u2014 but those sales aren&#8217;t registered until January due to government reporting lags. That spike has nothing to do with disease epidemiology \u2014 it&#8217;s a government policy artifact. And the overall trend is unmistakable: the colors get hotter from left to right as costs increase year over year.<\/p>\n<p>This chart is devastating in S&amp;OP meetings. Instead of flipping through twelve monthly charts or squinting at a line plot with 180 data points, you show one image and say &quot;here&#8217;s everything.&quot; The trend is obvious, the seasonality is obvious, and anomalies pop out as cells that don&#8217;t match their neighbors.<\/p>\n<h2>The 30-Second Rule<\/h2>\n<p>Here&#8217;s my challenge to you. Before your next forecast \u2014 before you open your model, before you tune parameters, before you touch a single smoothing constant \u2014 spend 30 seconds plotting the data three different ways:<\/p>\n<ol>\n<li><strong>autoplot()<\/strong> \u2014 see the big picture<\/li>\n<li><strong>gg_season()<\/strong> \u2014 check if the seasonal pattern is stable<\/li>\n<li><strong>ACF<\/strong> \u2014 read the autocorrelation fingerprint<\/li>\n<\/ol>\n<p>If what you see surprises you, your forecast was about to be wrong.<\/p>\n<p>A trend you didn&#8217;t know about. A seasonal shift that started two years ago. An outlier from that month when the warehouse flooded and everything got backordered. These are the things that break forecasts \u2014 and they&#8217;re invisible in summary tables but obvious in the right chart.<\/p>\n<p>The fpp3 toolkit gives you these charts in one or two lines of code each. No formatting. No wrestling with Excel chart axes. No &quot;why did the legend move when I resized the window.&quot; Just data in, insight out.<\/p>\n<p>And if you want to go further \u2014 ridgeline plots, heatmaps, calendar grids \u2014 R&#8217;s visualization ecosystem is effectively unlimited. The charts in this post are the starting lineup. The bench goes deep.<\/p>\n<h2>Interactive Dashboard<\/h2>\n<p>Explore the visual toolkit yourself \u2014 switch between chart types, change datasets, and discover patterns in real time.<\/p>\n<div class=\"dashboard-link\" style=\"margin:2em 0; padding:1.5em; background:#f8f9fa; border-left:4px solid #0073aa; border-radius:4px;\">\n<p style=\"margin:0 0 0.5em 0; font-size:1.1em;\"><strong>Interactive Dashboard<\/strong><\/p>\n<p style=\"margin:0 0 1em 0;\">Explore the data yourself \u2014 adjust parameters and see the results update in real time.<\/p>\n<p><a href=\"https:\/\/inphronesys.com\/wp-content\/uploads\/2026\/04\/2026-04-04_Time_Series_Graphics_FPP3_dashboard-1.html\" target=\"_blank\" style=\"display:inline-block; padding:0.6em 1.2em; background:#0073aa; color:#fff; text-decoration:none; border-radius:4px; font-weight:bold;\">Open Interactive Dashboard &rarr;<\/a><\/div>\n<h2>What&#8217;s Next<\/h2>\n<p>Today we learned to <em>see<\/em> our data. Next time, we learn to <em>decompose<\/em> it \u2014 breaking a time series into its trend, seasonal, and remainder components to understand the structure hiding underneath the noise. If today was &quot;pop the hood and look,&quot; next time is &quot;take the engine apart and understand every piece.&quot;<\/p>\n<p>Because once you can see the trend, the seasonality, and the noise separately, choosing the right forecasting model stops being a guessing game. It becomes obvious.<\/p>\n<p>See you next time.<\/p>\n<details>\n<summary><strong>Show R Code<\/strong><\/summary>\n<pre><code class=\"language-r\"># =============================================================================\n# Time Series Graphics with fpp3 \u2014 Full Reproducible Code\n# =============================================================================\n# Generates all visualizations from this blog post\n# Install once: install.packages(c(&quot;fpp3&quot;, &quot;ggridges&quot;))\n\nsource(&quot;Scripts\/theme_inphronesys.R&quot;)\nlibrary(fpp3)\nlibrary(ggridges)\n\n# --- Anscombe's Quartet ---------------------------------------------------\n# Demonstrates why summary statistics alone are not enough\ndata(anscombe)\n\nanscombe_long &lt;- tibble(\n  x = c(anscombe$x1, anscombe$x2, anscombe$x3, anscombe$x4),\n  y = c(anscombe$y1, anscombe$y2, anscombe$y3, anscombe$y4),\n  dataset = rep(paste(&quot;Dataset&quot;, c(&quot;I&quot;, &quot;II&quot;, &quot;III&quot;, &quot;IV&quot;)), each = 11)\n)\n\nggplot(anscombe_long, aes(x = x, y = y)) +\n  geom_point(size = 3, color = iph_colors$blue) +\n  geom_smooth(method = &quot;lm&quot;, se = FALSE, color = iph_colors$red,\n              linewidth = 1) +\n  facet_wrap(~dataset, ncol = 2) +\n  labs(title = &quot;Anscombe's Quartet&quot;,\n       subtitle = &quot;All four datasets: mean(x) = 9, mean(y) \u2248 7.5, r \u2248 0.816&quot;,\n       x = &quot;X&quot;, y = &quot;Y&quot;) +\n  theme_inphronesys()\n\nggsave(&quot;https:\/\/inphronesys.com\/wp-content\/uploads\/2026\/04\/tsgraphics_anscombe-1.png&quot;, width = 8, height = 7,\n       dpi = 100, bg = &quot;white&quot;)\n\n# --- Prepare beer data ----------------------------------------------------\nbeer &lt;- aus_production |&gt;\n  filter(year(Quarter) &gt;= 1992) |&gt;\n  select(Quarter, Beer)\n\n# --- 1. autoplot() \u2014 Time plot --------------------------------------------\nbeer |&gt;\n  autoplot(Beer) +\n  labs(title = &quot;Australian Quarterly Beer Production&quot;,\n       subtitle = &quot;1992\u20132010: declining trend with strong Q4 seasonality&quot;,\n       y = &quot;Megalitres&quot;) +\n  theme_inphronesys()\n\nggsave(&quot;https:\/\/inphronesys.com\/wp-content\/uploads\/2026\/04\/tsgraphics_autoplot-1.png&quot;, width = 8, height = 5,\n       dpi = 100, bg = &quot;white&quot;)\n\n# --- 2. gg_season() \u2014 Seasonal overlay ------------------------------------\nbeer |&gt;\n  gg_season(Beer, labels = &quot;both&quot;) +\n  labs(title = &quot;Seasonal Plot: Beer Production by Quarter&quot;,\n       subtitle = &quot;Each colored line is one year \u2014 Q4 peak, Q2 trough&quot;,\n       y = &quot;Megalitres&quot;) +\n  theme_inphronesys()\n\nggsave(&quot;https:\/\/inphronesys.com\/wp-content\/uploads\/2026\/04\/tsgraphics_season-1.png&quot;, width = 8, height = 5,\n       dpi = 100, bg = &quot;white&quot;)\n\n# --- 3. gg_subseries() \u2014 Subseries means ----------------------------------\nbeer |&gt;\n  gg_subseries(Beer) +\n  labs(title = &quot;Subseries Plot: Each Quarter's Trend Over Time&quot;,\n       subtitle = &quot;Blue line = quarter mean \u2014 Q4 declining, Q2 stable&quot;,\n       y = &quot;Megalitres&quot;) +\n  theme_inphronesys()\n\nggsave(&quot;https:\/\/inphronesys.com\/wp-content\/uploads\/2026\/04\/tsgraphics_subseries-1.png&quot;, width = 8, height = 5,\n       dpi = 100, bg = &quot;white&quot;)\n\n# --- 4. gg_lag() \u2014 Lag scatter plots --------------------------------------\nbeer |&gt;\n  gg_lag(Beer, lags = 1:9, geom = &quot;point&quot;) +\n  labs(title = &quot;Lag Plots: Does Past Production Predict Current?&quot;,\n       subtitle = &quot;Lag 4 (same quarter last year) shows the tightest relationship&quot;) +\n  theme_inphronesys()\n\nggsave(&quot;https:\/\/inphronesys.com\/wp-content\/uploads\/2026\/04\/tsgraphics_lag-1.png&quot;, width = 8, height = 7,\n       dpi = 100, bg = &quot;white&quot;)\n\n# --- 5. ACF plot \u2014 Autocorrelation fingerprint ----------------------------\nbeer |&gt;\n  ACF(Beer) |&gt;\n  autoplot() +\n  labs(title = &quot;ACF: The Autocorrelation Fingerprint&quot;,\n       subtitle = &quot;Scalloped pattern = trend + seasonality&quot;) +\n  theme_inphronesys()\n\nggsave(&quot;https:\/\/inphronesys.com\/wp-content\/uploads\/2026\/04\/tsgraphics_acf-1.png&quot;, width = 8, height = 5,\n       dpi = 100, bg = &quot;white&quot;)\n\n# --- 6. Ridgeline plot \u2014 Distribution mountains ---------------------------\nbeer |&gt;\n  as_tibble() |&gt;\n  mutate(Year = factor(year(Quarter))) |&gt;\n  ggplot(aes(x = Beer, y = Year, fill = after_stat(x))) +\n  geom_density_ridges_gradient(scale = 3, rel_min_height = 0.01) +\n  scale_fill_gradient(low = iph_colors$lightgrey, high = iph_colors$blue) +\n  labs(title = &quot;Ridgeline Plot: Production Distribution by Year&quot;,\n       subtitle = &quot;Each ridge shows one year's spread \u2014 wider = more variable&quot;,\n       x = &quot;Megalitres&quot;, y = NULL) +\n  theme_inphronesys() +\n  theme(legend.position = &quot;none&quot;)\n\nggsave(&quot;https:\/\/inphronesys.com\/wp-content\/uploads\/2026\/04\/tsgraphics_ridgeline-1.png&quot;, width = 8, height = 5,\n       dpi = 100, bg = &quot;white&quot;)\n\n# --- Prepare a10 antidiabetic drug data -----------------------------------\na10_data &lt;- PBS |&gt;\n  filter(ATC2 == &quot;A10&quot;) |&gt;\n  summarise(Cost = sum(Cost)) |&gt;\n  mutate(\n    Year  = year(Month),\n    Month_name = factor(month(Month, label = TRUE), levels = rev(month.abb))\n  ) |&gt;\n  as_tibble()\n\n# --- 7. Calendar heatmap (daily warehouse orders) -------------------------\nset.seed(42)\ndates_daily &lt;- seq(as.Date(&quot;2025-01-01&quot;), as.Date(&quot;2025-12-31&quot;), by = &quot;day&quot;)\nweekday_effect &lt;- c(Mon = 1.15, Tue = 1.05, Wed = 1.0, Thu = 0.95,\n                    Fri = 0.85, Sat = 0.5, Sun = 0.3)\norders &lt;- tibble(\n  date   = dates_daily,\n  wday   = wday(dates_daily, label = TRUE),\n  week   = isoweek(dates_daily),\n  volume = round(150 * weekday_effect[as.character(wday(dates_daily, label = TRUE))] *\n                   (1 + 0.2 * sin(2 * pi * yday(dates_daily) \/ 365)) +\n                   rnorm(length(dates_daily), 0, 15))\n)\n\norders |&gt;\n  ggplot(aes(x = week, y = fct_rev(wday), fill = volume)) +\n  geom_tile(color = &quot;white&quot;, linewidth = 0.5) +\n  scale_fill_gradient(low = &quot;white&quot;, high = iph_colors$blue) +\n  labs(title = &quot;Calendar Heatmap: Daily Warehouse Orders (2025)&quot;,\n       subtitle = &quot;Weekday \u00d7 week grid \u2014 weekday patterns + seasonal variation&quot;,\n       x = &quot;Week of Year&quot;, y = NULL, fill = &quot;Orders&quot;) +\n  theme_inphronesys() +\n  theme(panel.grid = element_blank())\n\nggsave(&quot;https:\/\/inphronesys.com\/wp-content\/uploads\/2026\/04\/tsgraphics_calendar_heatmap-1.png&quot;, width = 8, height = 5,\n       dpi = 100, bg = &quot;white&quot;)\n\n# --- 8. Month \u00d7 Year tile heatmap ----------------------------------------\na10_data |&gt;\n  ggplot(aes(x = Year, y = Month_name, fill = Cost)) +\n  geom_tile(color = &quot;white&quot;, linewidth = 0.5) +\n  scale_fill_viridis_c(option = &quot;inferno&quot;, labels = scales::label_comma()) +\n  labs(title = &quot;Tile Heatmap: Seasonality \u00d7 Trend in One View&quot;,\n       subtitle = &quot;Read across = trend over years | Read down = seasonal pattern&quot;,\n       x = NULL, y = NULL, fill = &quot;Cost ($M)&quot;) +\n  theme_inphronesys() +\n  theme(panel.grid = element_blank())\n\nggsave(&quot;https:\/\/inphronesys.com\/wp-content\/uploads\/2026\/04\/tsgraphics_tile_heatmap-1.png&quot;, width = 8, height = 5,\n       dpi = 100, bg = &quot;white&quot;)\n\n# =============================================================================\n# Try It With Your Own Data\n# =============================================================================\n# Export your monthly demand from SAP\/Oracle\/ERP as CSV:\n#\n# my_data &lt;- read.csv(&quot;my_demand.csv&quot;) |&gt;\n#   mutate(month = yearmonth(date)) |&gt;\n#   as_tsibble(index = month)\n#\n# # The 30-second visual check:\n# my_data |&gt; autoplot(demand)           # Big picture\n# my_data |&gt; gg_season(demand)          # Seasonal stability\n# my_data |&gt; ACF(demand) |&gt; autoplot()  # Autocorrelation fingerprint\n<\/code><\/pre>\n<\/details>\n<h2>References<\/h2>\n<ul>\n<li>Anscombe, F.J. (1973). Graphs in Statistical Analysis. <em>The American Statistician<\/em>, 27(1), 17-21.<\/li>\n<li>Hyndman, R.J., &amp; Athanasopoulos, G. (2021). <em>Forecasting: Principles and Practice<\/em>, 3rd edition, Chapter 2: Time Series Graphics. OTexts. Available free online at <a href=\"https:\/\/otexts.com\/fpp3\/\">otexts.com\/fpp3<\/a>.<\/li>\n<li>Wilke, C.O. (2019). <em>Fundamentals of Data Visualization<\/em>. O&#8217;Reilly Media.<\/li>\n<li>Grabowski, J.-P. (2024). <em>R For Purchasing Professionals (RFPP)<\/em>. A practical guide to using R for supply chain data analysis.<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Four datasets. Identical statistics. Completely different shapes. If you&#8217;re not plotting your demand data before forecasting it, you&#8217;re flying blind \u2014 and fpp3 gives you the visual toolkit to see what your spreadsheet hides.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[13,206,115],"tags":[247,47,8,127,51,246,249,15,248,26,208],"class_list":["post-1493","post","type-post","status-publish","format-standard","hentry","category-data-science","category-forecasting","category-supply-chain-management","tag-acf","tag-data-visualization","tag-forecasting","tag-fpp3","tag-ggplot2","tag-gg_season","tag-heatmap","tag-r","tag-ridgeline-plot","tag-supply-chain-analytics","tag-time-series-2"],"_links":{"self":[{"href":"https:\/\/inphronesys.com\/index.php?rest_route=\/wp\/v2\/posts\/1493","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/inphronesys.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/inphronesys.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/inphronesys.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/inphronesys.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1493"}],"version-history":[{"count":1,"href":"https:\/\/inphronesys.com\/index.php?rest_route=\/wp\/v2\/posts\/1493\/revisions"}],"predecessor-version":[{"id":1494,"href":"https:\/\/inphronesys.com\/index.php?rest_route=\/wp\/v2\/posts\/1493\/revisions\/1494"}],"wp:attachment":[{"href":"https:\/\/inphronesys.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1493"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/inphronesys.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1493"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/inphronesys.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1493"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}