metachronistic http://swingleydev.com/blog/ Latest metachronistic posts en-us Tue, 02 Jan 2024 07:18:28 -0900 Blog Migration http://swingleydev.com/blog/p/2026/ <div class="document"> <p>I've decided to migrate this blog to a quarto-based blog format. All future posts will be found here: <a class="reference external" href="https://swingley.dev/blog2">https://swingley.dev/blog2</a>.</p> </div> Tue, 02 Jan 2024 07:18:28 -0900 http://swingleydev.com/blog/p/2026/ python r rst quarto Yard List, 2023 http://swingleydev.com/blog/p/2025/ <div class="document"> <div class="figure align-right"> <a class="reference external image-reference" href="//media.swingleydev.com/img/photolog/2023/04/ruffed_grouse_next_to_the_house_2023-04.jpg"><img alt="" src="//media.swingleydev.com/img/photolog/2023/04/ruffed_grouse_next_to_the_house_2023-04_600.jpg" style="width: 400px; height: 225px;" /></a> <p class="caption">Ruffed Grouse, April 2023</p> </div> <p>We’ve been keeping a <a class="reference external" href="https://swingley.dev/animals/yard_list/">yard list</a> of all the animals we see since we moved to the Goldstream Valley in 2008. At the end of the year it’s fun to look at the data and compare this year against previous years.</p> <p>We saw 39 different species of bird, 8 mammal species, and one amphibian (<a class="reference external" href="https://swingley.dev/animals/yard_list/2023/">the full list</a>). In an average year we see 36 bird species, 7 mammals, and the one amphibian we have in the Interior, so we saw a few more than usual in 2023.</p> <p>Here’s a list of species we either saw for the first time this year, or are uncommonly seen on our property:</p> <table border="1" class="tosf tdlalign docutils"> <colgroup> <col width="57%" /> <col width="43%" /> </colgroup> <thead valign="bottom"> <tr><th class="head">Common Name</th> <th class="head">Years seen (including 2023)</th> </tr> </thead> <tbody valign="top"> <tr><td>Coyote</td> <td>1</td> </tr> <tr><td>Northern Waterthrush</td> <td>1</td> </tr> <tr><td>Townsend’s Solitaire</td> <td>1</td> </tr> <tr><td>Ruffed Grouse</td> <td>2</td> </tr> <tr><td>Black-billed Magpie</td> <td>3</td> </tr> <tr><td>Alder Flycatcher</td> <td>4</td> </tr> <tr><td>Lynx</td> <td>4</td> </tr> </tbody> </table> <p>And we only missed one species we commonly see, Northern Shrike, which we’ve seen in 11 out of 16 years.</p> </div> Fri, 29 Dec 2023 13:18:33 -0900 http://swingleydev.com/blog/p/2025/ birds mammals yard list Positional Eligibility http://swingleydev.com/blog/p/2024/ <div class="document"> <div class="section" id="introduction"> <h1>Introduction</h1> <p>For the past two years I’ve played Yahoo fantasy baseball with a group of friends. It’s a fun addition to watching games because it requires you to pay attention to more than just the players on the teams you root for (especially important if your favorite “team” is the Athletics).</p> <p>Last year we had a draft party and it was interesting to see how different people approached the draft. Some of us chose players for emotional reasons like whether they played for the team they rooted for or what country the player was from, and some used a very analytical approach. The last two years I’ve tended to be more on the emotional side, choosing preferrentialy for former Oakland Athletcs players in the first year, and current Phillies last year. Some brought computers to track choices and rankings, and some didn’t bring anything at all except their phones and minds.</p> <p>I’ve been working on my draft strategy for next year, and plan to use a more analytical approach to the draft. I’m working on an app that will have all the players in draft ranked, and allow me to easily mark off who has been selected, and who I’ve added to my team in real time as the draft is underway.</p> <p>One of the important considerations for choosing any player is what positions they can play. Not only do you need to field a complete team with pitchers, catchers, infielders, and outfielders, but some players are capable of playing multiple positions, and those players can be more valuable to a fantasy manager than their pure numbers would suggest because you can plug them into different positions on any given day. Last year I had Alec Bohm on my team, which allowed me to fill either first base (typically manned by Vladimir Gurerro Jr) or third, depending on what teams were playing or who might be injured or getting a day off. I used Brandon Drury to great effect two years ago because he was eligible for three infield positions.</p> <p><a class="reference external" href="https://help.yahoo.com/kb/SLN6766.html">Positional eligibility</a> for Yahoo fantasy follows these rules:</p> <ul class="simple"> <li>Position eligibility – 5 starts or 10 total appearances in a position.</li> <li>Pitcher eligibility – 3 starts to be a starter, or 5 relief appearances to qualify as a reliever.</li> </ul> <p>In this post I will use <a class="reference external" href="https://www.retrosheet.org/eventfile.htm">Retrosheet event data</a> to determine the positional eligibility for all the players who played in the majors last year. In cases where a player in the draft hasn’t played in the majors but is likely to reach Major League Baseball in 2024, I’ll just use whatever position the projections have him in.</p> </div> <div class="section" id="methods"> <h1>Methods</h1> <p>I’m going to use the <a class="reference external" href="https://github.com/colindouglas/retrosheet">retrosheet</a> R package to load the event files for 2023, then determine how many games each player started and substituted at each position, and apply Yahoo’s rules to determine eligibility.</p> <p>We’ll load some libraries, get the team IDs, and map Retrosheet position IDs to the usual position abbreviations.</p> <div class="highlight"><pre><span></span><span class="nf">library</span><span class="p">(</span><span class="n">tidyr</span><span class="p">)</span> <span class="nf">library</span><span class="p">(</span><span class="n">dplyr</span><span class="p">)</span> <span class="nf">library</span><span class="p">(</span><span class="n">purrr</span><span class="p">)</span> <span class="nf">library</span><span class="p">(</span><span class="n">retrosheet</span><span class="p">)</span> <span class="nf">library</span><span class="p">(</span><span class="n">glue</span><span class="p">)</span> <span class="n">YEAR</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="m">2023</span> <span class="n">team_ids</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="nf">getTeamIDs</span><span class="p">(</span><span class="n">YEAR</span><span class="p">)</span> <span class="n">positions</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="nf">tribble</span><span class="p">(</span> <span class="w"> </span><span class="o">~</span><span class="n">fieldPos</span><span class="p">,</span><span class="w"> </span><span class="o">~</span><span class="n">pos</span><span class="p">,</span> <span class="w"> </span><span class="s">&quot;1&quot;</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;P&quot;</span><span class="p">,</span> <span class="w"> </span><span class="s">&quot;2&quot;</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;C&quot;</span><span class="p">,</span> <span class="w"> </span><span class="s">&quot;3&quot;</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;1B&quot;</span><span class="p">,</span> <span class="w"> </span><span class="s">&quot;4&quot;</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;2B&quot;</span><span class="p">,</span> <span class="w"> </span><span class="s">&quot;5&quot;</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;3B&quot;</span><span class="p">,</span> <span class="w"> </span><span class="s">&quot;6&quot;</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;SS&quot;</span><span class="p">,</span> <span class="w"> </span><span class="s">&quot;7&quot;</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;LF&quot;</span><span class="p">,</span> <span class="w"> </span><span class="s">&quot;8&quot;</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;CF&quot;</span><span class="p">,</span> <span class="w"> </span><span class="s">&quot;9&quot;</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;RF&quot;</span><span class="p">,</span> <span class="w"> </span><span class="s">&quot;10&quot;</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;DH&quot;</span><span class="p">,</span> <span class="w"> </span><span class="s">&quot;11&quot;</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;PH&quot;</span><span class="p">,</span> <span class="w"> </span><span class="s">&quot;12&quot;</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;PR&quot;</span> <span class="p">)</span> </pre></div> <p>Next, we write a function to retrieve the data for a single team’s home games, and extract the starting and subtitution information, which are stored as <tt class="docutils literal">$start</tt> and <tt class="docutils literal">$sub</tt> matrices in the Retrosheet event files. Then loop over this function for every team, and convert position ID to the position abbreviations.</p> <div class="highlight"><pre><span></span><span class="n">get_pbp</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="nf">function</span><span class="p">(</span><span class="n">team_id</span><span class="p">)</span><span class="w"> </span><span class="p">{</span> <span class="w"> </span><span class="nf">print</span><span class="p">(</span><span class="nf">glue</span><span class="p">(</span><span class="s">&quot;loading {team_id}&quot;</span><span class="p">))</span> <span class="w"> </span><span class="n">pbp</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="nf">getRetrosheet</span><span class="p">(</span><span class="s">&quot;play&quot;</span><span class="p">,</span><span class="w"> </span><span class="n">YEAR</span><span class="p">,</span><span class="w"> </span><span class="n">team_id</span><span class="p">)</span> <span class="w"> </span><span class="n">starters</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="nf">map</span><span class="p">(</span> <span class="w"> </span><span class="nf">seq</span><span class="p">(</span><span class="m">1</span><span class="p">,</span><span class="w"> </span><span class="nf">length</span><span class="p">(</span><span class="n">pbp</span><span class="p">)),</span> <span class="w"> </span><span class="nf">function</span><span class="p">(</span><span class="n">game</span><span class="p">)</span><span class="w"> </span><span class="p">{</span> <span class="w"> </span><span class="n">pbp</span><span class="p">[[</span><span class="n">game</span><span class="p">]]</span><span class="o">$</span><span class="n">start</span><span class="w"> </span><span class="o">|&gt;</span> <span class="w"> </span><span class="nf">as_tibble</span><span class="p">()</span> <span class="w"> </span><span class="p">}</span> <span class="w"> </span><span class="p">)</span><span class="w"> </span><span class="o">|&gt;</span> <span class="w"> </span><span class="nf">list_rbind</span><span class="p">()</span><span class="w"> </span><span class="o">|&gt;</span> <span class="w"> </span><span class="nf">mutate</span><span class="p">(</span><span class="n">start_sub</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">&quot;start&quot;</span><span class="p">)</span> <span class="w"> </span><span class="n">subs</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="nf">map</span><span class="p">(</span> <span class="w"> </span><span class="nf">seq</span><span class="p">(</span><span class="m">1</span><span class="p">,</span><span class="w"> </span><span class="nf">length</span><span class="p">(</span><span class="n">pbp</span><span class="p">)),</span> <span class="w"> </span><span class="nf">function</span><span class="p">(</span><span class="n">game</span><span class="p">)</span><span class="w"> </span><span class="p">{</span> <span class="w"> </span><span class="n">pbp</span><span class="p">[[</span><span class="n">game</span><span class="p">]]</span><span class="o">$</span><span class="n">sub</span><span class="w"> </span><span class="o">|&gt;</span> <span class="w"> </span><span class="nf">as_tibble</span><span class="p">()</span> <span class="w"> </span><span class="p">}</span> <span class="w"> </span><span class="p">)</span><span class="w"> </span><span class="o">|&gt;</span> <span class="w"> </span><span class="nf">list_rbind</span><span class="p">()</span><span class="w"> </span><span class="o">|&gt;</span> <span class="w"> </span><span class="nf">mutate</span><span class="p">(</span><span class="n">start_sub</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">&quot;sub&quot;</span><span class="p">)</span> <span class="w"> </span><span class="nf">bind_rows</span><span class="p">(</span><span class="n">starters</span><span class="p">,</span><span class="w"> </span><span class="n">subs</span><span class="p">)</span> <span class="p">}</span> <span class="n">pbp_start_sub</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="nf">map</span><span class="p">(</span> <span class="w"> </span><span class="n">team_ids</span><span class="p">,</span> <span class="w"> </span><span class="n">get_pbp</span> <span class="p">)</span><span class="w"> </span><span class="o">|&gt;</span> <span class="w"> </span><span class="nf">list_rbind</span><span class="p">()</span><span class="w"> </span><span class="o">|&gt;</span> <span class="w"> </span><span class="nf">inner_join</span><span class="p">(</span><span class="n">positions</span><span class="p">,</span><span class="w"> </span><span class="n">by</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">&quot;fieldPos&quot;</span><span class="p">)</span> </pre></div> <p>That data frame looks like this, with one row for every player that played in any game during the 2023 regular season:</p> <pre class="literal-block"> # A tibble: 76,043 × 7 retroID name team batPos fieldPos start_sub pos &lt;chr&gt; &lt;chr&gt; &lt;chr&gt; &lt;chr&gt; &lt;chr&gt; &lt;chr&gt; &lt;chr&gt; 1 sprig001 George Springer 0 1 9 start RF 2 bichb001 Bo Bichette 0 2 6 start SS 3 guerv002 Vladimir Guerrero Jr. 0 3 3 start 1B 4 chapm001 Matt Chapman 0 4 5 start 3B 5 merrw001 Whit Merrifield 0 5 7 start LF 6 kirka001 Alejandro Kirk 0 6 2 start C 7 espis001 Santiago Espinal 0 7 4 start 2B 8 luplj001 Jordan Luplow 0 8 10 start DH 9 kierk001 Kevin Kiermaier 0 9 8 start CF 10 bassc001 Chris Bassitt 0 0 1 start P # ℹ 76,033 more rows </pre> <p>Next, we convert that into appearances by grouping the data by player, whether they were a starter or substitute, and by their position. Since each row in the original data frame is per game, we can use <tt class="docutils literal">n()</tt> to count the games each player started and subbed for each position.</p> <div class="highlight"><pre><span></span><span class="n">appearances</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">pbp_start_sub</span><span class="w"> </span><span class="o">|&gt;</span> <span class="w"> </span><span class="nf">group_by</span><span class="p">(</span><span class="n">retroID</span><span class="p">,</span><span class="w"> </span><span class="n">name</span><span class="p">,</span><span class="w"> </span><span class="n">start_sub</span><span class="p">,</span><span class="w"> </span><span class="n">pos</span><span class="p">)</span><span class="w"> </span><span class="o">|&gt;</span> <span class="w"> </span><span class="nf">summarize</span><span class="p">(</span><span class="n">games</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nf">n</span><span class="p">(),</span><span class="w"> </span><span class="n">.groups</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">&quot;drop&quot;</span><span class="p">)</span><span class="w"> </span><span class="o">|&gt;</span> <span class="w"> </span><span class="nf">pivot_wider</span><span class="p">(</span><span class="n">names_from</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">start_sub</span><span class="p">,</span><span class="w"> </span><span class="n">values_from</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">games</span><span class="p">)</span> </pre></div> <p>That looks like this:</p> <pre class="literal-block"> # A tibble: 3,479 × 5 retroID name pos sub start &lt;chr&gt; &lt;chr&gt; &lt;chr&gt; &lt;int&gt; &lt;int&gt; 1 abadf001 Fernando Abad P 6 NA 2 abboa001 Andrew Abbott P NA 21 3 abboc001 Cory Abbott P 22 NA 4 abrac001 CJ Abrams SS 3 148 5 abrac001 CJ Abrams PH 2 NA 6 abrac001 CJ Abrams PR 1 NA 7 abrea001 Albert Abreu P 45 NA 8 abreb002 Bryan Abreu P 72 NA 9 abrej003 Jose Abreu 1B NA 134 10 abrej003 Jose Abreu DH NA 7 # ℹ 3,469 more rows </pre> <p>Finally, we group by the player and position, calculate eligibility, then group by player and combine all the positions they are eligible for into a single string. There’s a little funny business at the end to remove pitching eligibility from position players who are called into action as pitchers in blow out games, and player suffixes, which may or may not be necessary for matching against your projection ranks.</p> <div class="highlight"><pre><span></span><span class="n">eligibility</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">appearances</span><span class="w"> </span><span class="o">|&gt;</span> <span class="w"> </span><span class="nf">filter</span><span class="p">(</span><span class="n">pos</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="s">&quot;PH&quot;</span><span class="p">,</span><span class="w"> </span><span class="n">pos</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="s">&quot;PR&quot;</span><span class="p">)</span><span class="w"> </span><span class="o">|&gt;</span> <span class="w"> </span><span class="nf">mutate</span><span class="p">(</span> <span class="w"> </span><span class="n">sub</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nf">if_else</span><span class="p">(</span><span class="nf">is.na</span><span class="p">(</span><span class="n">sub</span><span class="p">),</span><span class="w"> </span><span class="m">0</span><span class="p">,</span><span class="w"> </span><span class="n">sub</span><span class="p">),</span> <span class="w"> </span><span class="n">start</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nf">if_else</span><span class="p">(</span><span class="nf">is.na</span><span class="p">(</span><span class="n">start</span><span class="p">),</span><span class="w"> </span><span class="m">0</span><span class="p">,</span><span class="w"> </span><span class="n">start</span><span class="p">),</span> <span class="w"> </span><span class="n">total</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">sub</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">start</span><span class="p">,</span> <span class="w"> </span><span class="n">eligible</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nf">case_when</span><span class="p">(</span> <span class="w"> </span><span class="n">pos</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s">&quot;P&quot;</span><span class="w"> </span><span class="o">&amp;</span><span class="w"> </span><span class="n">start</span><span class="w"> </span><span class="o">&gt;=</span><span class="w"> </span><span class="m">3</span><span class="w"> </span><span class="o">&amp;</span><span class="w"> </span><span class="n">sub</span><span class="w"> </span><span class="o">&gt;=</span><span class="w"> </span><span class="m">5</span><span class="w"> </span><span class="o">~</span><span class="w"> </span><span class="s">&quot;SP,RP&quot;</span><span class="p">,</span> <span class="w"> </span><span class="n">pos</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s">&quot;P&quot;</span><span class="w"> </span><span class="o">&amp;</span><span class="w"> </span><span class="n">start</span><span class="w"> </span><span class="o">&gt;=</span><span class="w"> </span><span class="m">3</span><span class="w"> </span><span class="o">~</span><span class="w"> </span><span class="s">&quot;SP&quot;</span><span class="p">,</span> <span class="w"> </span><span class="n">pos</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s">&quot;P&quot;</span><span class="w"> </span><span class="o">&amp;</span><span class="w"> </span><span class="n">sub</span><span class="w"> </span><span class="o">&gt;=</span><span class="w"> </span><span class="m">5</span><span class="w"> </span><span class="o">~</span><span class="w"> </span><span class="s">&quot;RP&quot;</span><span class="p">,</span> <span class="w"> </span><span class="n">pos</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s">&quot;P&quot;</span><span class="w"> </span><span class="o">~</span><span class="w"> </span><span class="s">&quot;P&quot;</span><span class="p">,</span> <span class="w"> </span><span class="n">start</span><span class="w"> </span><span class="o">&gt;=</span><span class="w"> </span><span class="m">5</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">total</span><span class="w"> </span><span class="o">&gt;=</span><span class="w"> </span><span class="m">10</span><span class="w"> </span><span class="o">~</span><span class="w"> </span><span class="n">pos</span><span class="p">,</span> <span class="w"> </span><span class="kc">TRUE</span><span class="w"> </span><span class="o">~</span><span class="w"> </span><span class="kc">NA</span> <span class="w"> </span><span class="p">)</span> <span class="w"> </span><span class="p">)</span><span class="w"> </span><span class="o">|&gt;</span> <span class="w"> </span><span class="nf">filter</span><span class="p">(</span><span class="o">!</span><span class="nf">is.na</span><span class="p">(</span><span class="n">eligible</span><span class="p">))</span><span class="w"> </span><span class="o">|&gt;</span> <span class="w"> </span><span class="nf">arrange</span><span class="p">(</span><span class="n">retroID</span><span class="p">,</span><span class="w"> </span><span class="n">name</span><span class="p">,</span><span class="w"> </span><span class="nf">desc</span><span class="p">(</span><span class="n">total</span><span class="p">))</span><span class="w"> </span><span class="o">|&gt;</span> <span class="w"> </span><span class="nf">group_by</span><span class="p">(</span><span class="n">retroID</span><span class="p">,</span><span class="w"> </span><span class="n">name</span><span class="p">)</span><span class="w"> </span><span class="o">|&gt;</span> <span class="w"> </span><span class="nf">summarize</span><span class="p">(</span> <span class="w"> </span><span class="n">eligible</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nf">paste</span><span class="p">(</span><span class="n">eligible</span><span class="p">,</span><span class="w"> </span><span class="n">collapse</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">&quot;,&quot;</span><span class="p">),</span> <span class="w"> </span><span class="n">eligible</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nf">gsub</span><span class="p">(</span><span class="s">&quot;,P$&quot;</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;&quot;</span><span class="p">,</span><span class="w"> </span><span class="n">eligible</span><span class="p">),</span> <span class="w"> </span><span class="n">.groups</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">&quot;drop&quot;</span> <span class="w"> </span><span class="p">)</span><span class="w"> </span><span class="o">|&gt;</span> <span class="w"> </span><span class="nf">mutate</span><span class="p">(</span> <span class="w"> </span><span class="n">name</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nf">gsub</span><span class="p">(</span><span class="s">&quot; (Jr.|II|IV)&quot;</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;&quot;</span><span class="p">,</span><span class="w"> </span><span class="n">name</span><span class="p">)</span> <span class="w"> </span><span class="p">)</span> </pre></div> <p>Here’s a look at the final results. You can download the full data as a CSV file below.</p> <pre class="literal-block"> # A tibble: 1,402 × 3 retroID name eligible &lt;chr&gt; &lt;chr&gt; &lt;chr&gt; 1 abadf001 Fernando Abad RP 2 abboa001 Andrew Abbott SP 3 abboc001 Cory Abbott RP 4 abrac001 CJ Abrams SS 5 abrea001 Albert Abreu RP 6 abreb002 Bryan Abreu RP 7 abrej003 Jose Abreu 1B,DH 8 abrew002 Wilyer Abreu CF,LF 9 acevd001 Domingo Acevedo RP 10 actog001 Garrett Acton RP # ℹ 1,392 more rows </pre> <p>Who is eligible for the most positions? Here's the top 20:</p> <pre class="literal-block"> retroID name eligible &lt;chr&gt; &lt;chr&gt; &lt;chr&gt; 1 herne001 Enrique Hernandez SS,2B,CF,3B,LF,1B 2 diaza003 Aledmys Diaz 3B,SS,LF,2B,1B,DH 3 hampg001 Garrett Hampson SS,CF,RF,2B,LF 4 mckiz001 Zach McKinstry 3B,2B,RF,LF,SS 5 ariag002 Gabriel Arias SS,1B,RF,3B 6 bertj001 Jon Berti SS,3B,LF,2B 7 biggc002 Cavan Biggio 2B,RF,1B,3B 8 cabro002 Oswaldo Cabrera LF,RF,3B,SS 9 castw003 Willi Castro LF,CF,3B,2B 10 dubom001 Mauricio Dubon 2B,CF,LF,SS 11 edmat001 Tommy Edman 2B,SS,CF,RF 12 gallj002 Joey Gallo 1B,LF,CF,RF 13 ibana001 Andy Ibanez 2B,3B,LF,RF 14 newmk001 Kevin Newman 3B,SS,2B,1B,DH 15 rengl001 Luis Rengifo 2B,SS,3B,RF 16 senzn001 Nick Senzel 3B,LF,CF,RF 17 shorz001 Zack Short 2B,SS,3B,RP 18 stees001 Spencer Steer 1B,3B,LF,2B,DH 19 vargi001 Ildemaro Vargas 3B,2B,SS,LF 20 vierm001 Matt Vierling RF,LF,3B,CF </pre> </div> <div class="section" id="code-and-data"> <h1>Code and data</h1> <p>Downloads:</p> <ul class="simple"> <li><a class="reference external" href="//media.swingleydev.com/data/2023/12/positional_eligibility.R">R code</a></li> <li><a class="reference external" href="//media.swingleydev.com/data/2023/12/positional_eligibility_2023.csv">Positional Eligibility CSV</a></li> </ul> </div> <div class="section" id="references-and-acknowledgements"> <h1>References and Acknowledgements</h1> <p>The information used here was obtained free of charge from and is copyrighted by Retrosheet. Interested parties may contact Retrosheet at “www.retrosheet.org”.</p> </div> </div> Tue, 26 Dec 2023 14:33:14 -0900 http://swingleydev.com/blog/p/2024/ baseball R fantasy baseball Storm Totals http://swingleydev.com/blog/p/2023/ <div class="document"> <p>Friday night we got 2.4 inches of snow at home, after a storm earlier in the week dropped a total of 6.9 inches of snow (0.51 inches of liquid). I plowed the road on Wednesday afternoon after most of that first storm’s snow had fallen and got up Saturday morning debating about whether I should plow again. My normal rule is if we get more than two inches I’ll plow, but I didn’t feel like it and left it. It’s snowing again today, so I will probably wind up plowing soon.</p> <p>Feeling somewhat responsible for keeping the road clear makes winter something of a mixed bag for me because I enjoy the snow in the winter, but the drudgery of plowing turns snow storms into work. I remember plowing three times in the span of a week before Thanksgiving one year, and everyone in Fairbanks remembers Christmas 2021 when we had a major storm with both rain and snow, following by extreme cold, and most people were stuck at home until they could dig out. Our four wheeler was out of commission with a burned up rear differential, so I couldn’t do anything about it.</p> <p>I thought it would be interesting to look at the storm data for Fairbanks. I’m defining a “storm” as any period with one or more consecutive days with precipitation, and by “precipitation” I mean either rain, or the liquid when daily snowfall is melted. I am not including “trace” precipitation (snowfall less than a tenth of an inch or liquid less than 0.01 inches) in this calculation.</p> <p>Here’s a table of the top ten storms in Fairbanks, ranked by total precipitation.</p> <table border="1" class="tosf docutils"> <colgroup> <col width="9%" /> <col width="18%" /> <col width="9%" /> <col width="17%" /> <col width="15%" /> <col width="15%" /> <col width="15%" /> </colgroup> <thead valign="bottom"> <tr><th class="head">Rank</th> <th class="head">Start</th> <th class="head">Days</th> <th class="head">Total Snow (inches)</th> <th class="head">Total Precip (inches)</th> <th class="head">Per Day Snow</th> <th class="head">Per Day Precip</th> </tr> </thead> <tbody valign="top"> <tr><td>1</td> <td>1967‑08‑08</td> <td>8</td> <td>0.00</td> <td>6.15</td> <td>0.00</td> <td>0.77</td> </tr> <tr><td>2</td> <td>2003‑07‑26</td> <td>11</td> <td>0.00</td> <td>4.57</td> <td>0.00</td> <td>0.42</td> </tr> <tr><td>3</td> <td>1937‑01‑18</td> <td>12</td> <td>38.15</td> <td>4.17</td> <td>3.18</td> <td>0.35</td> </tr> <tr><td>4</td> <td>1990‑07‑07</td> <td>7</td> <td>0.00</td> <td>3.98</td> <td>0.00</td> <td>0.57</td> </tr> <tr><td>5</td> <td>2021‑12‑25</td> <td>5</td> <td><strong>23.39</strong></td> <td><strong>3.67</strong></td> <td><strong>4.68</strong></td> <td><strong>0.73</strong></td> </tr> <tr><td>6</td> <td>2019‑07‑28</td> <td>11</td> <td>0.00</td> <td>3.59</td> <td>0.00</td> <td>0.33</td> </tr> <tr><td>7</td> <td>2014‑06‑30</td> <td>3</td> <td>0.00</td> <td>3.37</td> <td>0.00</td> <td><strong>1.12</strong></td> </tr> <tr><td>8</td> <td>1948‑07‑18</td> <td>7</td> <td>0.00</td> <td>3.18</td> <td>0.00</td> <td>0.45</td> </tr> <tr><td>9</td> <td>1932‑08‑02</td> <td>7</td> <td>0.00</td> <td>3.14</td> <td>0.00</td> <td>0.45</td> </tr> <tr><td>10</td> <td>1962‑08‑25</td> <td>6</td> <td>0.00</td> <td>3.09</td> <td>0.00</td> <td>0.52</td> </tr> </tbody> </table> <p>A couple storms stand out to me. First, the Christmas 2021 event is 5th on the list (it winds up 13th on the list of winter storms ranked by total snowfall instead of liquid precipitation). It’s so high on this list because a significant amount of the total precipitation in that storm came as rain.</p> <p>The other remarkable storm for me is the three day rainstorm that started on June 30th, 2014 and ended on July 2nd. We got a remarkable 1.12 inches of rain per day over those three days, and on July 2nd Goldstream Creek went over the banks at our house. Here’s a ranking of storms by average daily precipitation.</p> <table border="1" class="tosf docutils"> <colgroup> <col width="18%" /> <col width="35%" /> <col width="18%" /> <col width="29%" /> </colgroup> <thead valign="bottom"> <tr><th class="head">Rank</th> <th class="head">Start</th> <th class="head">Days</th> <th class="head">Per Day Precip (inches)</th> </tr> </thead> <tbody valign="top"> <tr><td>1</td> <td>2014-07-07</td> <td>1</td> <td>1.13</td> </tr> <tr><td>2</td> <td>2014-06-30</td> <td>3</td> <td>1.12</td> </tr> <tr><td>3</td> <td>2014-09-01</td> <td>2</td> <td>1.12</td> </tr> <tr><td>4</td> <td>1953-06-24</td> <td>1</td> <td>1.08</td> </tr> <tr><td>5</td> <td>1992-07-06</td> <td>1</td> <td>0.95</td> </tr> </tbody> </table> <p>The top three storms are all from the summer 2014.</p> <img alt="House surrounded by water" src="https://media.swingleydev.com/img/photolog/2014/07/house_surrounded_by_water_2014-07_600.jpg" /> <p>There is evidence that one of the consequences of climate change in Alaska is an increase in the severity of storms. Here’s a ranking of the number of top 50 storms in each decade. The previous decade leads the list, and our current decade already has 2 such top 50 storms. Changing the minimum ranking from top 50 to top 100 doesn’t change the list much, and 2010‒2019 is a the top of that ranking as well.</p> <table border="1" class="tosf docutils"> <colgroup> <col width="30%" /> <col width="70%" /> </colgroup> <thead valign="bottom"> <tr><th class="head">Decade</th> <th class="head">Number of Top 50 Storms</th> </tr> </thead> <tbody valign="top"> <tr><td>2010‒2019</td> <td>9</td> </tr> <tr><td>1920‒1929</td> <td>7</td> </tr> <tr><td>1930‒1939</td> <td>7</td> </tr> <tr><td>1940‒1949</td> <td>6</td> </tr> <tr><td>1960‒1969</td> <td>4</td> </tr> <tr><td>2000‒2009</td> <td>4</td> </tr> <tr><td>1990‒1999</td> <td>3</td> </tr> <tr><td>1910‒1919</td> <td>2</td> </tr> <tr><td>1950‒1959</td> <td>2</td> </tr> <tr><td>1970‒1979</td> <td>2</td> </tr> <tr><td>1980‒1989</td> <td>2</td> </tr> <tr><td>2020‒2023</td> <td>2</td> </tr> </tbody> </table> </div> Sun, 17 Dec 2023 14:34:11 -0900 http://swingleydev.com/blog/p/2023/ snow weather Hythergraphs http://swingleydev.com/blog/p/2022/ <div class="document"> <div class="section" id="introduction"> <h1>Introduction</h1> <p>Yesterday Richard James <a class="reference external" href="https://ak-wx.blogspot.com/2023/12/hythergraphs.html">posted</a> about “hythergraphs”, which he’d seen on Toolik Field Station’s <a class="reference external" href="https://www.uaf.edu/toolik/edc/monitoring/abiotic/climate_summaries.php">web site</a>.</p> <p>Hythergraphs show monthly weather parameters for an entire year, plotting temperature against precipitation (or other paired climate variables) against each other for each month of the year, drawing a line from month to month. When contrasting one climate record against another (historic vs.&nbsp;contemporary, one station against another), the differences stand out.</p> <p>I was curious to see how easy it would be to produce one with R and ggplot.</p> </div> <div class="section" id="data"> <h1>Data</h1> <p>I’ll produce hythergraphs, one that compares Fairbanks Airport data against the data collected at our station on Goldstream Creek for the period of record for our station (2011‒2022) and one that compares the Fairbanks Airport station data from 1951‒2000 against data from 2001‒2022 (similar to what Richard did).</p> <p>I’m using the following R packages:</p> <div class="highlight"><pre><span></span><span class="nf">library</span><span class="p">(</span><span class="n">tidyverse</span><span class="p">)</span> <span class="nf">library</span><span class="p">(</span><span class="n">RPostgres</span><span class="p">)</span> <span class="nf">library</span><span class="p">(</span><span class="n">lubridate</span><span class="p">)</span> <span class="nf">library</span><span class="p">(</span><span class="n">scales</span><span class="p">)</span> </pre></div> <p>I’ll skip the part where I pull the data from the GHCND database. What we need is a table of observations that look like this. We’ve got a categorical column (<tt class="docutils literal">station_name</tt>), a date column, and the two climate variables we’re going to plot:</p> <pre class="literal-block"> # A tibble: 30,072 × 4 station_name dte PRCP TAVG &lt;chr&gt; &lt;date&gt; &lt;dbl&gt; &lt;dbl&gt; 1 GOLDSTREAM CREEK 2011-04-01 0 -17.5 2 GOLDSTREAM CREEK 2011-04-02 0 -15.6 3 GOLDSTREAM CREEK 2011-04-03 0 -8.1 4 GOLDSTREAM CREEK 2011-04-04 0 -5 5 GOLDSTREAM CREEK 2011-04-05 0 -5 6 GOLDSTREAM CREEK 2011-04-06 0.5 -3.9 7 GOLDSTREAM CREEK 2011-04-07 0 -8.3 8 GOLDSTREAM CREEK 2011-04-08 2 -5.85 9 GOLDSTREAM CREEK 2011-04-09 0.5 -1.65 10 GOLDSTREAM CREEK 2011-04-10 0 -4.45 # ℹ 30,062 more rows </pre> <p>From that raw data, we’ll aggregate to year and month, calculating the montly precipitation sum and mean average temperature, then aggregate to station and month, calculating the mean monthly precipitation and temperature.</p> <p>The final step adds the necessary aesthetics to produce the plot using ggplot. We’ll draw the monthly scatterplot values using the first letter of the month, calculated using <tt class="docutils literal">month_label = substring(month.name[month], 1, 1)</tt> below. To draw the lines from one month to the next we use <tt class="docutils literal">geom_segement</tt> and calculate the ends of each segment by setting <tt class="docutils literal">xend</tt> and <tt class="docutils literal">yend</tt> to the next row’s value from the table.</p> <p>One flaw in this approach is that there’s no line between December and January because there is no “next” value in the data frame. This could be fixed by seperately finding the January positions, then passing those to <tt class="docutils literal">lead()</tt> as the default value (which is normally NA).</p> <div class="highlight"><pre><span></span><span class="n">airport_goldstream</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="n">pivot</span><span class="w"> </span><span class="o">|&gt;</span> <span class="w"> </span><span class="nf">filter</span><span class="p">(</span><span class="n">dte</span><span class="w"> </span><span class="o">&gt;=</span><span class="w"> </span><span class="s">&quot;2010-04-01&quot;</span><span class="p">)</span><span class="w"> </span><span class="o">|&gt;</span> <span class="w"> </span><span class="c1"># get monthly precip total, mean temp</span> <span class="w"> </span><span class="nf">mutate</span><span class="p">(</span> <span class="w"> </span><span class="n">year</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nf">year</span><span class="p">(</span><span class="n">dte</span><span class="p">),</span> <span class="w"> </span><span class="n">month</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nf">month</span><span class="p">(</span><span class="n">dte</span><span class="p">)</span> <span class="w"> </span><span class="p">)</span><span class="w"> </span><span class="o">|&gt;</span> <span class="w"> </span><span class="nf">group_by</span><span class="p">(</span><span class="n">station_name</span><span class="p">,</span><span class="w"> </span><span class="n">year</span><span class="p">,</span><span class="w"> </span><span class="n">month</span><span class="p">)</span><span class="w"> </span><span class="o">|&gt;</span> <span class="w"> </span><span class="nf">summarize</span><span class="p">(</span> <span class="w"> </span><span class="n">sum_prcp_in</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nf">sum</span><span class="p">(</span><span class="n">PRCP</span><span class="p">,</span><span class="w"> </span><span class="n">na.rm</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kc">TRUE</span><span class="p">)</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="m">25.4</span><span class="p">,</span> <span class="w"> </span><span class="n">mean_tavg_f</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nf">mean</span><span class="p">(</span><span class="n">TAVG</span><span class="p">,</span><span class="w"> </span><span class="n">na.rm</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kc">TRUE</span><span class="p">)</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="m">9</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="m">5.0</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="m">32</span><span class="p">,</span> <span class="w"> </span><span class="n">.groups</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">&quot;drop&quot;</span> <span class="w"> </span><span class="p">)</span><span class="w"> </span><span class="o">|&gt;</span> <span class="w"> </span><span class="c1"># get monthy means for each station</span> <span class="w"> </span><span class="nf">group_by</span><span class="p">(</span><span class="n">station_name</span><span class="p">,</span><span class="w"> </span><span class="n">month</span><span class="p">)</span><span class="w"> </span><span class="o">|&gt;</span> <span class="w"> </span><span class="nf">summarize</span><span class="p">(</span> <span class="w"> </span><span class="n">mean_prcp_in</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nf">mean</span><span class="p">(</span><span class="n">sum_prcp_in</span><span class="p">),</span> <span class="w"> </span><span class="n">mean_tavg_f</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nf">mean</span><span class="p">(</span><span class="n">mean_tavg_f</span><span class="p">),</span> <span class="w"> </span><span class="n">.groups</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">&quot;drop&quot;</span> <span class="w"> </span><span class="p">)</span><span class="w"> </span><span class="o">|&gt;</span> <span class="w"> </span><span class="c1"># add month label, line segment ends</span> <span class="w"> </span><span class="nf">arrange</span><span class="p">(</span><span class="n">station_name</span><span class="p">,</span><span class="w"> </span><span class="n">month</span><span class="p">)</span><span class="w"> </span><span class="o">|&gt;</span> <span class="w"> </span><span class="nf">group_by</span><span class="p">(</span><span class="n">station_name</span><span class="p">)</span><span class="w"> </span><span class="o">|&gt;</span> <span class="w"> </span><span class="nf">mutate</span><span class="p">(</span> <span class="w"> </span><span class="n">month_label</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nf">substring</span><span class="p">(</span><span class="n">month.name</span><span class="p">[</span><span class="n">month</span><span class="p">],</span><span class="w"> </span><span class="m">1</span><span class="p">,</span><span class="w"> </span><span class="m">1</span><span class="p">),</span> <span class="w"> </span><span class="n">xend</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nf">lead</span><span class="p">(</span><span class="n">mean_prcp_in</span><span class="p">),</span> <span class="w"> </span><span class="n">yend</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nf">lead</span><span class="p">(</span><span class="n">mean_tavg_f</span><span class="p">)</span> <span class="w"> </span><span class="p">)</span> </pre></div> <p>Here’s what that data frame looks like:</p> <pre class="literal-block"> # A tibble: 24 × 7 # Groups: station_name [2] station_name month mean_prcp_in mean_tavg_f month_label xend yend &lt;chr&gt; &lt;dbl&gt; &lt;dbl&gt; &lt;dbl&gt; &lt;chr&gt; &lt;dbl&gt; &lt;dbl&gt; 1 FAIRBANKS INTL AP 1 0.635 -6.84 J 0.988 -0.213 2 FAIRBANKS INTL AP 2 0.988 -0.213 F 0.635 11.5 3 FAIRBANKS INTL AP 3 0.635 11.5 M 0.498 33.1 4 FAIRBANKS INTL AP 4 0.498 33.1 A 0.670 51.2 5 FAIRBANKS INTL AP 5 0.670 51.2 M 1.79 61.3 6 FAIRBANKS INTL AP 6 1.79 61.3 J 2.41 63.1 7 FAIRBANKS INTL AP 7 2.41 63.1 J 2.59 57.9 8 FAIRBANKS INTL AP 8 2.59 57.9 A 1.66 46.5 9 FAIRBANKS INTL AP 9 1.66 46.5 S 1.04 29.5 10 FAIRBANKS INTL AP 10 1.04 29.5 O 1.16 5.21 # ℹ 14 more rows </pre> </div> <div class="section" id="plots"> <h1>Plots</h1> <p>Here’s the code to produce the plot. The month labels are displayed using <tt class="docutils literal">geom_label</tt>, and the lines between months are generated from <tt class="docutils literal">geom_segment</tt>.</p> <div class="highlight"><pre><span></span><span class="n">airport_v_gsc</span><span class="w"> </span><span class="o">&lt;-</span><span class="w"> </span><span class="nf">ggplot</span><span class="p">(</span> <span class="w"> </span><span class="n">data</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">airport_goldstream</span><span class="p">,</span> <span class="w"> </span><span class="nf">aes</span><span class="p">(</span><span class="n">x</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">mean_prcp_in</span><span class="p">,</span><span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">mean_tavg_f</span><span class="p">,</span><span class="w"> </span><span class="n">color</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">station_name</span><span class="p">)</span> <span class="p">)</span><span class="w"> </span><span class="o">+</span> <span class="w"> </span><span class="nf">theme_bw</span><span class="p">()</span><span class="w"> </span><span class="o">+</span> <span class="w"> </span><span class="nf">geom_segment</span><span class="p">(</span><span class="nf">aes</span><span class="p">(</span><span class="n">xend</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">xend</span><span class="p">,</span><span class="w"> </span><span class="n">yend</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">yend</span><span class="p">,</span><span class="w"> </span><span class="n">color</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">station_name</span><span class="p">))</span><span class="w"> </span><span class="o">+</span> <span class="w"> </span><span class="nf">geom_label</span><span class="p">(</span><span class="nf">aes</span><span class="p">(</span><span class="n">label</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">month_label</span><span class="p">),</span><span class="w"> </span><span class="n">show.legend</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kc">FALSE</span><span class="p">)</span><span class="w"> </span><span class="o">+</span> <span class="w"> </span><span class="nf">scale_x_continuous</span><span class="p">(</span> <span class="w"> </span><span class="n">name</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">&quot;Monthly Average Precipitation (inches liquid)&quot;</span><span class="p">,</span> <span class="w"> </span><span class="n">breaks</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nf">pretty_breaks</span><span class="p">(</span><span class="n">n</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">10</span><span class="p">)</span> <span class="w"> </span><span class="p">)</span><span class="w"> </span><span class="o">+</span> <span class="w"> </span><span class="nf">scale_y_continuous</span><span class="p">(</span> <span class="w"> </span><span class="n">name</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">&quot;Monthly Average Tempearature (°F)&quot;</span><span class="p">,</span> <span class="w"> </span><span class="n">breaks</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nf">pretty_breaks</span><span class="p">(</span><span class="n">n</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">10</span><span class="p">)</span> <span class="w"> </span><span class="p">)</span><span class="w"> </span><span class="o">+</span> <span class="w"> </span><span class="nf">scale_color_manual</span><span class="p">(</span> <span class="w"> </span><span class="n">name</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">&quot;Station&quot;</span><span class="p">,</span> <span class="w"> </span><span class="n">values</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nf">c</span><span class="p">(</span><span class="s">&quot;darkorange&quot;</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;darkcyan&quot;</span><span class="p">)</span> <span class="w"> </span><span class="p">)</span><span class="w"> </span><span class="o">+</span> <span class="w"> </span><span class="nf">theme</span><span class="p">(</span> <span class="w"> </span><span class="n">legend.position</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nf">c</span><span class="p">(</span><span class="m">0.8</span><span class="p">,</span><span class="w"> </span><span class="m">0.2</span><span class="p">),</span> <span class="w"> </span><span class="n">legend.background</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nf">element_rect</span><span class="p">(</span> <span class="w"> </span><span class="n">fill</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">&quot;white&quot;</span><span class="p">,</span><span class="w"> </span><span class="n">linetype</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">&quot;solid&quot;</span><span class="p">,</span><span class="w"> </span><span class="n">color</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">&quot;grey80&quot;</span><span class="p">,</span><span class="w"> </span><span class="n">size</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">0.5</span> <span class="w"> </span><span class="p">)</span> <span class="w"> </span><span class="p">)</span><span class="w"> </span><span class="o">+</span> <span class="w"> </span><span class="nf">labs</span><span class="p">(</span> <span class="w"> </span><span class="n">title</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">&quot;Monthly temperature and precipitation&quot;</span><span class="p">,</span> <span class="w"> </span><span class="n">subtitle</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">&quot;Fairbanks Airport and Goldstream Creek Stations, 2011‒2022&quot;</span> <span class="w"> </span><span class="p">)</span> </pre></div> <object class="img-responsive" data="//media.swingleydev.com/img/blog/2023/12/airport_v_gsc.svg" type="image/svg+xml">Fairbanks Airport, Goldstream Creek Hythergraph</object> <p>You can see from the plot that we are consistently colder than the airport, curiously more dramatically in the summer than winter. The airport gets slighly more precipitation in winter, but our summer precipitation is significantly higher, especially in August.</p> <p>The standard plot to display this information would be two bar charts with one plot showing the monthly mean temperature for each station, and a second plot showing precipitation. The advantage of such a display is that the differences would be more clear, and the bars could include standard errors (or standard deviation) that would help provide an idea of whether the differences between stations are statistically significant or not.</p> <p>For example (the lines above the bars are one standard deviation above or below the mean):</p> <object class="img-responsive" data="//media.swingleydev.com/img/blog/2023/12/airport_v_gsc_bar_chart.svg" type="image/svg+xml">Fairbanks Airport, Goldstream Creek Bar Chart</object> <p>In this plot of the same data, you can tell from the standard deviation lines that the precipitation differences between stations are probably not significant, but the cooler summer temperatures at Goldstrem Creek may be.</p> <p>If we calculate the standard deviations of the monthly means, we can use <tt class="docutils literal">geom_tile</tt> to draw significance boxes around each monthly value in the hytherplot as Richard suggests in his post. Here’s the ggplot geom to do that:</p> <div class="highlight"><pre><span></span><span class="nf">geom_tile</span><span class="p">(</span> <span class="w"> </span><span class="nf">aes</span><span class="p">(</span><span class="n">width</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">2</span><span class="o">*</span><span class="n">sd_prcp_in</span><span class="p">,</span><span class="w"> </span><span class="n">height</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">2</span><span class="o">*</span><span class="n">sd_tavg_f</span><span class="p">,</span><span class="w"> </span><span class="n">fill</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">station_name</span><span class="p">),</span> <span class="w"> </span><span class="n">show.legend</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kc">FALSE</span><span class="p">,</span><span class="w"> </span><span class="n">alpha</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">0.25</span> <span class="p">)</span><span class="w"> </span><span class="o">+</span> </pre></div> <p>And the updated plot:</p> <object class="img-responsive" data="//media.swingleydev.com/img/blog/2023/12/airport_v_gsc_with_sd.svg" type="image/svg+xml">Fairbanks Airport, Goldstream Creek</object> <p>This clearly shows the large variation in precipitation, and if you carefully compare the boxes for a particular month, you can draw concusions similar to what is made fairly clear in the bar charts. For example, if we focus on August, you can see that the Goldstream Creek precipitation box clearly overlaps that of the airport station, but the temperature ranges do not overlap, suggesting that August temperatures are cooler at Goldstream Creek but that while precipitation is much higher, it’s not statistically significant.</p> </div> <div class="section" id="airport-station-different-time-periods"> <h1>Airport station, different time periods</h1> <p>Here’s the plot for the airport station that is similar to the plot Richard created (I used different time periods).</p> <object class="img-responsive" data="//media.swingleydev.com/img/blog/2023/12/airport_periods.svg" type="image/svg+xml">Fairbanks Airport Hythergraph</object> <p>This plot demonstrates that while temperatures have increased in the last two decades, it’s the differences in the pattern of precipitation that stands out, with July and August precipitation much larger in the last 20 years. It’s also curious that February and April precipitation is higher, but the differences are smaller in the other winter months. This is a case where some sense of the distribution of the values would be useful.</p> </div> </div> Sun, 03 Dec 2023 11:22:49 -0900 http://swingleydev.com/blog/p/2022/ R weather ggplot