<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>R on Zhenguo Zhang&#39;s Blog</title>
    <link>https://fortune9.netlify.app/categories/r/</link>
    <description>Recent content in R on Zhenguo Zhang&#39;s Blog</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <lastBuildDate>Sun, 30 Aug 2026 00:00:00 +0000</lastBuildDate>
    
        <atom:link href="https://fortune9.netlify.app/categories/r/index.xml" rel="self" type="application/rss+xml" />
    
    
    
        <item>
        <title>[R] Understanding position_dodge() and position_dodge2() in ggplot2</title>
        <link>https://fortune9.netlify.app/2026/08/30/r-understanding-position-dodge-and-position-dodge2-in-ggplot2/</link>
        <pubDate>Sun, 30 Aug 2026 00:00:00 +0000</pubDate>
        
        <guid>https://fortune9.netlify.app/2026/08/30/r-understanding-position-dodge-and-position-dodge2-in-ggplot2/</guid>
        <creator>"ZZG"</creator>
        <description>Zhenguo Zhang&#39;s Blog https://fortune9.netlify.app/2026/08/30/r-understanding-position-dodge-and-position-dodge2-in-ggplot2/ -


&lt;p&gt;In &lt;code&gt;ggplot2&lt;/code&gt;, when displaying grouped data along categorical axes (such as grouped bar charts, boxplots, or error bars), horizontal dodging is used to prevent elements from overlapping at each categorical position. &lt;code&gt;ggplot2&lt;/code&gt; provides two primary dodging position functions: &lt;code&gt;position_dodge()&lt;/code&gt; and &lt;code&gt;position_dodge2()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In this post, we will explore:&lt;/p&gt;
&lt;ol style=&#34;list-style-type: decimal&#34;&gt;
&lt;li&gt;How the &lt;code&gt;width&lt;/code&gt; parameter in &lt;code&gt;position_dodge()&lt;/code&gt; interacts with the parent geom’s &lt;code&gt;width&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The core differences between &lt;code&gt;position_dodge2()&lt;/code&gt; and &lt;code&gt;position_dodge()&lt;/code&gt;, including why changing &lt;code&gt;width&lt;/code&gt; in &lt;code&gt;position_dodge2()&lt;/code&gt; often has no visual effect.&lt;/li&gt;
&lt;li&gt;How &lt;code&gt;preserve = &#34;single&#34;&lt;/code&gt; behaves when elements of a group variable are missing at a given x-axis level.&lt;/li&gt;
&lt;/ol&gt;
&lt;div id=&#34;definition-of-terms&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Definition of Terms&lt;/h3&gt;
&lt;p&gt;To keep our explanations clear and consistent throughout this post, we define two key concepts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;x-axis level&lt;/strong&gt;: The discrete value or category on the x-axis. In our examples using &lt;code&gt;mtcars&lt;/code&gt;, the x-axis level is &lt;code&gt;cyl&lt;/code&gt; (with levels &lt;code&gt;4&lt;/code&gt;, &lt;code&gt;6&lt;/code&gt;, and &lt;code&gt;8&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;group variable&lt;/strong&gt;: The variable that divides items into subgroups at each x-axis level, typically mapped to an aesthetic like &lt;code&gt;fill&lt;/code&gt; or &lt;code&gt;color&lt;/code&gt;. In our examples, the group variable is &lt;code&gt;gear&lt;/code&gt; (with levels &lt;code&gt;3&lt;/code&gt;, &lt;code&gt;4&lt;/code&gt;, and &lt;code&gt;5&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;dodged elements&lt;/strong&gt;: The individual visual marks (e.g. bars) corresponding to each level of the group variable at a specific x-axis level.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(ggplot2)
library(patchwork)&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;/div&gt;
&lt;div id=&#34;the-width-parameter-in-position_dodge&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;1. The &lt;code&gt;width&lt;/code&gt; Parameter in &lt;code&gt;position_dodge()&lt;/code&gt;&lt;/h2&gt;
&lt;div id=&#34;what-does-width-control&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;What does &lt;code&gt;width&lt;/code&gt; control?&lt;/h3&gt;
&lt;p&gt;In &lt;code&gt;position_dodge(width = ...)&lt;/code&gt;, &lt;code&gt;width&lt;/code&gt; specifies the &lt;strong&gt;total dodging span&lt;/strong&gt; (interval) on the x-axis into which all dodged elements for a given x-axis level are arranged side-by-side.&lt;/p&gt;
&lt;p&gt;By default, if you do not explicitly supply &lt;code&gt;width&lt;/code&gt; to &lt;code&gt;position_dodge()&lt;/code&gt;, it &lt;strong&gt;inherits its value from the parent geom&lt;/strong&gt; (e.g., &lt;code&gt;geom_bar()&lt;/code&gt; defaults to &lt;code&gt;width = 0.9&lt;/code&gt;).&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;interaction-between-geom_barwidth-and-position_dodgewidth&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Interaction between &lt;code&gt;geom_bar(width)&lt;/code&gt; and &lt;code&gt;position_dodge(width)&lt;/code&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;geom_bar(width = ...)&lt;/code&gt;&lt;/strong&gt;: Sets the total physical width allocated to the bars at each x-axis level. The individual bar width is derived by dividing this value by the number of elements at that x-axis level.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;position_dodge(width = ...)&lt;/code&gt;&lt;/strong&gt;: Sets the total span on the x-axis across which the center positions of the dodged elements are calculated and spaced.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Both parameters use x-axis coordinate units (where the distance between adjacent discrete x-axis levels is &lt;code&gt;1.0&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;Let’s examine how varying both parameters affects the layout using the &lt;code&gt;mtcars&lt;/code&gt; dataset (plotting mean &lt;code&gt;mpg&lt;/code&gt; across x-axis level &lt;code&gt;cyl&lt;/code&gt;, with group variable &lt;code&gt;gear&lt;/code&gt; mapped to &lt;code&gt;fill&lt;/code&gt;):&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;# Base plot configuration
base_p &amp;lt;- ggplot(mtcars, aes(x = factor(cyl), y = mpg, fill = factor(gear))) +
  labs(x = &amp;quot;Cylinders (x-axis level)&amp;quot;, y = &amp;quot;Mean MPG&amp;quot;, fill = &amp;quot;Gear (group variable)&amp;quot;) +
  theme_minimal(base_size = 11)

# Case 1: Default matching widths (0.9 / 0.9)
# Bars touch neatly within each x-axis level
p1 &amp;lt;- base_p +
  geom_bar(
    stat = &amp;quot;summary&amp;quot;, 
    fun = &amp;quot;mean&amp;quot;, 
    width = 0.9, 
    position = position_dodge(width = 0.9)
  ) +
  ggtitle(&amp;quot;1. Matching widths (0.9 / 0.9)&amp;quot;, subtitle = &amp;quot;Bars touch neatly within each x-axis level&amp;quot;)

# Case 2: geom_bar width (0.5) &amp;lt; dodge width (0.9)
# Dodging span is 0.9, but bars are narrower -&amp;gt; gaps appear between bars
p2 &amp;lt;- base_p +
  geom_bar(
    stat = &amp;quot;summary&amp;quot;, 
    fun = &amp;quot;mean&amp;quot;, 
    width = 0.5, 
    position = position_dodge(width = 0.9)
  ) +
  ggtitle(&amp;quot;2. geom_bar(0.5) &amp;lt; dodge(0.9)&amp;quot;, subtitle = &amp;quot;Gaps created between dodged elements&amp;quot;)

# Case 3: geom_bar width (0.9) &amp;gt; dodge width (0.5)
# Dodging span is narrower than bar widths -&amp;gt; bars overlap
p3 &amp;lt;- base_p +
  geom_bar(
    stat = &amp;quot;summary&amp;quot;, 
    fun = &amp;quot;mean&amp;quot;, 
    width = 0.9, 
    position = position_dodge(width = 0.5)
  ) +
  ggtitle(&amp;quot;3. geom_bar(0.9) &amp;gt; dodge(0.5)&amp;quot;, subtitle = &amp;quot;Dodged elements overlap&amp;quot;)

# Case 4: Both changed to 0.6
# Group as a whole is narrower, bars touch, larger separation between x-axis levels
p4 &amp;lt;- base_p +
  geom_bar(
    stat = &amp;quot;summary&amp;quot;, 
    fun = &amp;quot;mean&amp;quot;, 
    width = 0.6, 
    position = position_dodge(width = 0.6)
  ) +
  ggtitle(&amp;quot;4. Both set to 0.6&amp;quot;, subtitle = &amp;quot;Compact cluster, wider space between x-axis levels&amp;quot;)

(p1 | p2) / (p3 | p4)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;https://fortune9.netlify.app/2026/08/30/r-understanding-position-dodge-and-position-dodge2-in-ggplot2/index_files/figure-html/section-1-dodge-width-1.png&#34; alt=&#34;&#34; width=&#34;1800&#34; style=&#34;display: block; margin: auto;&#34; /&gt;&lt;/p&gt;
&lt;p&gt;As demonstrated:
- Increasing &lt;code&gt;width&lt;/code&gt; in &lt;code&gt;geom_bar()&lt;/code&gt; increases the individual width of dodged elements at that x-axis level.
- Increasing &lt;code&gt;width&lt;/code&gt; in &lt;code&gt;position_dodge()&lt;/code&gt; increases the total dodging span across which elements are spread.
- When both values are equal, the dodged elements within each x-axis level touch each other without overlapping or leaving gaps.&lt;/p&gt;
&lt;hr /&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;differences-between-position_dodge2-and-position_dodge&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;2. Differences Between &lt;code&gt;position_dodge2()&lt;/code&gt; and &lt;code&gt;position_dodge()&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;While &lt;code&gt;position_dodge()&lt;/code&gt; was originally designed for simple geoms with fixed-width positions (like &lt;code&gt;geom_bar&lt;/code&gt; and &lt;code&gt;geom_col&lt;/code&gt;), &lt;code&gt;position_dodge2()&lt;/code&gt; was introduced to handle geoms with variable widths or explicit intervals (&lt;code&gt;xmin&lt;/code&gt; to &lt;code&gt;xmax&lt;/code&gt;), such as &lt;code&gt;geom_boxplot()&lt;/code&gt;, &lt;code&gt;geom_rect()&lt;/code&gt;, and &lt;code&gt;geom_linerange()&lt;/code&gt;.&lt;/p&gt;
&lt;div id=&#34;key-differences&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Key Differences:&lt;/h3&gt;
&lt;ol style=&#34;list-style-type: decimal&#34;&gt;
&lt;li&gt;&lt;strong&gt;Boundary-Based Packing vs. Fixed Slot Offsets&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;position_dodge()&lt;/code&gt; divides the total dodge width at an x-axis level into fixed slots and places each level of the group variable into its designated slot.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;position_dodge2()&lt;/code&gt; packs elements (for different levels of the group variable) sequentially side-by-side using the bounding boxes of the geoms.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The &lt;code&gt;width&lt;/code&gt; Parameter Has No Visual Effect in &lt;code&gt;position_dodge2()&lt;/code&gt; with Bars&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;Because &lt;code&gt;position_dodge2()&lt;/code&gt; arranges bars based on their pre-computed bounding intervals rather than calculating center slot offsets from a dodge span, changing &lt;code&gt;width&lt;/code&gt; in &lt;code&gt;position_dodge2()&lt;/code&gt; produces no change in the plot output when bar widths are already defined by the parent geom.&lt;/li&gt;
&lt;li&gt;Bar widths must be controlled directly via &lt;code&gt;geom_bar(width = ...)&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Built-in &lt;code&gt;padding&lt;/code&gt; and &lt;code&gt;reverse&lt;/code&gt; Support&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;padding&lt;/code&gt;: Adds proportional space between dodged elements at the same x-axis level without requiring manual mismatch of geom and dodge widths.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;reverse = TRUE&lt;/code&gt;: Reverses the left-to-right plotting order of the group variable without needing to alter factor levels.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div id=&#34;demo-width-has-no-effect-in-position_dodge2&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Demo: &lt;code&gt;width&lt;/code&gt; Has No Effect in &lt;code&gt;position_dodge2()&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Below, we compare &lt;code&gt;position_dodge2(width = 0.3)&lt;/code&gt; against &lt;code&gt;position_dodge2(width = 0.9)&lt;/code&gt;. Notice that the two plots are completely identical:&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;# Changing width in position_dodge2 produces identical output
p_d2_w03 &amp;lt;- base_p +
  geom_bar(
    stat = &amp;quot;summary&amp;quot;, 
    fun = &amp;quot;mean&amp;quot;, 
    position = position_dodge2(width = 0.3)
  ) +
  ggtitle(&amp;quot;position_dodge2(width = 0.3)&amp;quot;, subtitle = &amp;quot;Width parameter has no visual effect&amp;quot;)

p_d2_w09 &amp;lt;- base_p +
  geom_bar(
    stat = &amp;quot;summary&amp;quot;, 
    fun = &amp;quot;mean&amp;quot;, 
    position = position_dodge2(width = 0.9)
  ) +
  ggtitle(&amp;quot;position_dodge2(width = 0.9)&amp;quot;, subtitle = &amp;quot;Identical layout to width = 0.3&amp;quot;)

p_d2_w03 | p_d2_w09&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;https://fortune9.netlify.app/2026/08/30/r-understanding-position-dodge-and-position-dodge2-in-ggplot2/index_files/figure-html/section-2-dodge2-no-effect-1.png&#34; alt=&#34;&#34; width=&#34;2000&#34; style=&#34;display: block; margin: auto;&#34; /&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;creating-spacing-with-padding-and-reversing-order-with-reverse&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Creating Spacing with &lt;code&gt;padding&lt;/code&gt; and Reversing Order with &lt;code&gt;reverse&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Instead of altering &lt;code&gt;width&lt;/code&gt;, &lt;code&gt;position_dodge2()&lt;/code&gt; provides the &lt;code&gt;padding&lt;/code&gt; and &lt;code&gt;reverse&lt;/code&gt; parameters:&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;# Using padding and reverse in position_dodge2
p_dodge2_demo &amp;lt;- base_p +
  geom_bar(
    stat = &amp;quot;summary&amp;quot;, 
    fun = &amp;quot;mean&amp;quot;, 
    position = position_dodge2(padding = 0.2, reverse = TRUE)
  ) +
  labs(
    title = &amp;quot;position_dodge2(padding = 0.2, reverse = TRUE)&amp;quot;,
    subtitle = &amp;quot;Built-in bar padding and reversed order of group variable&amp;quot;
  )

p_dodge2_demo&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;https://fortune9.netlify.app/2026/08/30/r-understanding-position-dodge-and-position-dodge2-in-ggplot2/index_files/figure-html/section-2-dodge2-padding-reverse-1.png&#34; alt=&#34;&#34; width=&#34;1800&#34; style=&#34;display: block; margin: auto;&#34; /&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;handling-missing-elements-with-preserve-single&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;3. Handling Missing Elements with &lt;code&gt;preserve = &#34;single&#34;&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;A significant functional difference between &lt;code&gt;position_dodge()&lt;/code&gt; and &lt;code&gt;position_dodge2()&lt;/code&gt; occurs when certain levels of the group variable are absent at a specific x-axis level.&lt;/p&gt;
&lt;p&gt;Let’s inspect the count of observations across &lt;code&gt;cyl&lt;/code&gt; (x-axis level) and &lt;code&gt;gear&lt;/code&gt; (group variable) in &lt;code&gt;mtcars&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;table(mtcars$cyl, mtcars$gear)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;##    
##      3  4  5
##   4  1  8  2
##   6  2  4  1
##   8 12  0  2&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At the x-axis level &lt;strong&gt;&lt;code&gt;cyl = 8&lt;/code&gt;&lt;/strong&gt;, the group variable &lt;code&gt;gear&lt;/code&gt; contains observations for gears &lt;code&gt;3&lt;/code&gt; (12 cars) and &lt;code&gt;5&lt;/code&gt; (2 cars), but &lt;strong&gt;&lt;code&gt;gear = 4&lt;/code&gt; is completely missing (0 cars)&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;When we set &lt;code&gt;preserve = &#34;single&#34;&lt;/code&gt; to ensure that all individual bar widths remain uniform across all x-axis levels:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;position_dodge(preserve = &#34;single&#34;)&lt;/code&gt;&lt;/strong&gt;: Retains fixed slot assignments. Because &lt;code&gt;gear = 4&lt;/code&gt; is missing at &lt;code&gt;cyl = 8&lt;/code&gt;, it leaves a &lt;strong&gt;blank gap&lt;/strong&gt; in the middle where &lt;code&gt;gear = 4&lt;/code&gt; would normally reside.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;position_dodge2(preserve = &#34;single&#34;)&lt;/code&gt;&lt;/strong&gt;: Preserves individual bar width while &lt;strong&gt;re-centering the remaining dodged elements&lt;/strong&gt;, packing them side-by-side without leaving an empty gap.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;# position_dodge with preserve = &amp;quot;single&amp;quot;
p_dodge_single &amp;lt;- base_p +
  geom_bar(
    stat = &amp;quot;summary&amp;quot;, 
    fun = &amp;quot;mean&amp;quot;, 
    position = position_dodge(preserve = &amp;quot;single&amp;quot;)
  ) +
  labs(
    title = &amp;quot;position_dodge(preserve = &amp;#39;single&amp;#39;)&amp;quot;,
    subtitle = &amp;quot;Leaves an empty gap for missing gear = 4 at cyl = 8&amp;quot;
  )

# position_dodge2 with preserve = &amp;quot;single&amp;quot;
p_dodge2_single &amp;lt;- base_p +
  geom_bar(
    stat = &amp;quot;summary&amp;quot;, 
    fun = &amp;quot;mean&amp;quot;, 
    position = position_dodge2(preserve = &amp;quot;single&amp;quot;)
  ) +
  labs(
    title = &amp;quot;position_dodge2(preserve = &amp;#39;single&amp;#39;)&amp;quot;,
    subtitle = &amp;quot;Re-centers remaining elements (no gap at cyl = 8)&amp;quot;
  )

# Side-by-side comparison
p_dodge_single | p_dodge2_single&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;https://fortune9.netlify.app/2026/08/30/r-understanding-position-dodge-and-position-dodge2-in-ggplot2/index_files/figure-html/section-3-preserve-single-1.png&#34; alt=&#34;&#34; width=&#34;2000&#34; style=&#34;display: block; margin: auto;&#34; /&gt;&lt;/p&gt;
&lt;p&gt;Note that if one sets preserve = “total”, then you would not see any difference, because the bars are re-stretched
to ensure the bars from each categorical level occupy all the width assigned to that level.&lt;/p&gt;
&lt;hr /&gt;
&lt;/div&gt;
&lt;div id=&#34;summary&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Summary&lt;/h2&gt;
&lt;table&gt;
&lt;colgroup&gt;
&lt;col width=&#34;33%&#34; /&gt;
&lt;col width=&#34;33%&#34; /&gt;
&lt;col width=&#34;33%&#34; /&gt;
&lt;/colgroup&gt;
&lt;thead&gt;
&lt;tr class=&#34;header&#34;&gt;
&lt;th align=&#34;left&#34;&gt;Feature&lt;/th&gt;
&lt;th align=&#34;left&#34;&gt;&lt;code&gt;position_dodge()&lt;/code&gt;&lt;/th&gt;
&lt;th align=&#34;left&#34;&gt;&lt;code&gt;position_dodge2()&lt;/code&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr class=&#34;odd&#34;&gt;
&lt;td align=&#34;left&#34;&gt;&lt;strong&gt;Primary Use Cases&lt;/strong&gt;&lt;/td&gt;
&lt;td align=&#34;left&#34;&gt;Simple 1D fixed-width geoms (&lt;code&gt;geom_bar&lt;/code&gt;, &lt;code&gt;geom_col&lt;/code&gt;)&lt;/td&gt;
&lt;td align=&#34;left&#34;&gt;Interval &amp;amp; variable-width geoms (&lt;code&gt;geom_boxplot&lt;/code&gt;, &lt;code&gt;geom_rect&lt;/code&gt;, &lt;code&gt;geom_linerange&lt;/code&gt;) and bars&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class=&#34;even&#34;&gt;
&lt;td align=&#34;left&#34;&gt;&lt;strong&gt;Role of &lt;code&gt;width&lt;/code&gt; Parameter&lt;/strong&gt;&lt;/td&gt;
&lt;td align=&#34;left&#34;&gt;Sets total dodging span across each x-axis level&lt;/td&gt;
&lt;td align=&#34;left&#34;&gt;Has no visual effect on bars with predefined geom width&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class=&#34;odd&#34;&gt;
&lt;td align=&#34;left&#34;&gt;&lt;strong&gt;Missing Elements (&lt;code&gt;preserve=&#34;single&#34;&lt;/code&gt;)&lt;/strong&gt;&lt;/td&gt;
&lt;td align=&#34;left&#34;&gt;Leaves empty slot / gap at the missing level&lt;/td&gt;
&lt;td align=&#34;left&#34;&gt;Re-centers remaining dodged elements together&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class=&#34;even&#34;&gt;
&lt;td align=&#34;left&#34;&gt;&lt;strong&gt;Padding Between Elements&lt;/strong&gt;&lt;/td&gt;
&lt;td align=&#34;left&#34;&gt;Manual (&lt;code&gt;geom_bar(width) &amp;lt; position_dodge(width)&lt;/code&gt;)&lt;/td&gt;
&lt;td align=&#34;left&#34;&gt;Built-in via &lt;code&gt;padding = ...&lt;/code&gt; argument&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class=&#34;odd&#34;&gt;
&lt;td align=&#34;left&#34;&gt;&lt;strong&gt;Reverse Plotting Order&lt;/strong&gt;&lt;/td&gt;
&lt;td align=&#34;left&#34;&gt;Requires re-leveling the group variable&lt;/td&gt;
&lt;td align=&#34;left&#34;&gt;Built-in via &lt;code&gt;reverse = TRUE&lt;/code&gt; argument&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
- https://fortune9.netlify.app/2026/08/30/r-understanding-position-dodge-and-position-dodge2-in-ggplot2/ - </description>
        </item>
    
    
    
        <item>
        <title>[R] Environment Variables in R Shiny-Server Container: Problem and Solutions</title>
        <link>https://fortune9.netlify.app/2026/08/15/r-environment-variables-in-r-shiny-server-container/</link>
        <pubDate>Sat, 15 Aug 2026 00:00:00 +0000</pubDate>
        
        <guid>https://fortune9.netlify.app/2026/08/15/r-environment-variables-in-r-shiny-server-container/</guid>
        <creator>"ZZG"</creator>
        <description>Zhenguo Zhang&#39;s Blog https://fortune9.netlify.app/2026/08/15/r-environment-variables-in-r-shiny-server-container/ -&lt;p&gt;When dockerizing an R Shiny application hosted via &lt;strong&gt;Shiny Server&lt;/strong&gt; (built from shiny server docker image &lt;a href=&#34;https://hub.docker.com/r/rocker/shiny)&#34;&gt;https://hub.docker.com/r/rocker/shiny)&lt;/a&gt;, a common issue developers face is that environment variables set via &lt;code&gt;ENV&lt;/code&gt; instructions in the &lt;code&gt;Dockerfile&lt;/code&gt; (or passed at runtime via &lt;code&gt;docker run -e&lt;/code&gt;) are completely missing inside the R Shiny app.&lt;/p&gt;
&lt;p&gt;For example, if you set the following environment variable in your &lt;code&gt;Dockerfile&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-dockerfile&#34; data-lang=&#34;dockerfile&#34;&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;ENV&lt;/span&gt; SHOULD_IN_SHINY&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;From dockerfile&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;When your app launches and runs &lt;code&gt;Sys.getenv(&amp;quot;SHOULD_IN_SHINY&amp;quot;)&lt;/code&gt;, it returns an empty string &lt;code&gt;&amp;quot;&amp;quot;&lt;/code&gt; instead of &lt;code&gt;&amp;quot;From dockerfile&amp;quot;&lt;/code&gt;.
This is not a problem with Docker itself, but rather a consequence of how &lt;strong&gt;Shiny Server&lt;/strong&gt; spawns R worker processes.&lt;/p&gt;
&lt;p&gt;In this post, we will look into the root cause behind this behavior in Shiny Server and demonstrate the two recommended solutions to correctly expose environment variables to your R Shiny workers.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;the-root-cause-how-shiny-server-spawns-r-processes&#34;&gt;The Root Cause: How Shiny Server Spawns R Processes&lt;/h2&gt;
&lt;p&gt;The reason environment variables do not carry over to your R session lies in how Shiny Server executes R worker processes inside the container.&lt;/p&gt;
&lt;p&gt;Shiny Server runs as a system service (typically as &lt;code&gt;root&lt;/code&gt; or &lt;code&gt;shiny&lt;/code&gt;). When launching an app instance, it re-executes R as the &lt;code&gt;shiny&lt;/code&gt; unprivileged user using &lt;code&gt;su&lt;/code&gt;. Specifically, the execution call combines two mutually exclusive flags:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;su shiny --login --preserve-environment -c &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;... R ...&amp;#34;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Let&amp;rsquo;s break down what these flags request from &lt;code&gt;su&lt;/code&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;--login&lt;/code&gt; (&lt;code&gt;-l&lt;/code&gt;)&lt;/strong&gt;: Starts a &lt;strong&gt;login shell&lt;/strong&gt;. This intentionally &lt;strong&gt;resets&lt;/strong&gt; the environment to a minimal whitelist (&lt;code&gt;HOME&lt;/code&gt;, &lt;code&gt;PATH&lt;/code&gt;, &lt;code&gt;USER&lt;/code&gt;, &lt;code&gt;TERM&lt;/code&gt;, etc.) and sources system startup profiles (&lt;code&gt;/etc/profile&lt;/code&gt;, &lt;code&gt;~/.profile&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;--preserve-environment&lt;/code&gt; (&lt;code&gt;-p&lt;/code&gt;)&lt;/strong&gt;: Explicitly asks &lt;code&gt;su&lt;/code&gt; to &lt;strong&gt;keep&lt;/strong&gt; the current environment inherited from the caller (which includes Docker&amp;rsquo;s &lt;code&gt;ENV&lt;/code&gt; variables).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Because Linux&amp;rsquo;s &lt;code&gt;su&lt;/code&gt; utility cannot honor both conflicting behaviors, it chooses &lt;code&gt;--login&lt;/code&gt; and prints a warning:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;su: ignoring --preserve-environment, it&amp;#39;s mutually exclusive with --login
&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This warning is emitted by Shiny Server&amp;rsquo;s underlying process execution call, not by the R app itself. Attempting to suppress or patch it requires modifying and rebuilding Shiny Server C++ code, which is rarely practical.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Because the &lt;strong&gt;login shell wins&lt;/strong&gt;, all custom environment variables passed to the container via &lt;code&gt;ENV&lt;/code&gt; or &lt;code&gt;docker run&lt;/code&gt; are &lt;strong&gt;wiped before R ever starts&lt;/strong&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;solutions&#34;&gt;Solutions&lt;/h2&gt;
&lt;p&gt;Since patching Shiny Server is unnecessary, we can utilize the natural extension points provided by the login shell or R itself.&lt;/p&gt;
&lt;h3 id=&#34;solution-1-use-profile-recommended-for-user-level-shell-vars&#34;&gt;Solution 1: Use &lt;code&gt;~/.profile&lt;/code&gt; (Recommended for User-Level Shell Vars)&lt;/h3&gt;
&lt;p&gt;Since &lt;code&gt;--login&lt;/code&gt; causes the shell to source &lt;code&gt;~/.profile&lt;/code&gt; for the &lt;code&gt;shiny&lt;/code&gt; user, we can write our environment variables to &lt;code&gt;/home/shiny/.profile&lt;/code&gt; during the Docker build phase.&lt;/p&gt;
&lt;p&gt;In your &lt;code&gt;Dockerfile&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;1
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-dockerfile&#34; data-lang=&#34;dockerfile&#34;&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Append environment variable to the shiny user&amp;#39;s profile&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;RUN&lt;/span&gt; echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;export SHOULD_IN_SHINY=&amp;#34;From dockerfile&amp;#34;&amp;#39;&lt;/span&gt; &amp;gt;&amp;gt; /home/shiny/.profile&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;When Shiny Server executes &lt;code&gt;su shiny --login ...&lt;/code&gt;, the login shell will read &lt;code&gt;/home/shiny/.profile&lt;/code&gt; and load &lt;code&gt;SHOULD_IN_SHINY&lt;/code&gt; into the environment right before starting the R process.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&#34;solution-2-use-renviron-recommended-for-r-specific-configs&#34;&gt;Solution 2: Use &lt;code&gt;~/.Renviron&lt;/code&gt; (Recommended for R-Specific Configs)&lt;/h3&gt;
&lt;p&gt;Alternatively, R automatically inspects and loads &lt;code&gt;~/.Renviron&lt;/code&gt; on startup, right after the shell environment is initialized.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;~/.Renviron&lt;/code&gt; is purpose-built for R:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Scoped strictly to R processes.&lt;/li&gt;
&lt;li&gt;Does not use shell &lt;code&gt;export&lt;/code&gt; keywords or &lt;code&gt;$&lt;/code&gt; variable expansions.&lt;/li&gt;
&lt;li&gt;Uses simple &lt;code&gt;KEY=value&lt;/code&gt; key-value pairs.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In your &lt;code&gt;Dockerfile&lt;/code&gt;, set up &lt;code&gt;/home/shiny/.Renviron&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;1
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;2
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-dockerfile&#34; data-lang=&#34;dockerfile&#34;&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Set up .Renviron for the shiny user&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;RUN&lt;/span&gt; echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;SHOULD_IN_SHINY=&amp;#34;From dockerfile&amp;#34;&amp;#39;&lt;/span&gt; &amp;gt;&amp;gt; /home/shiny/.Renviron &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    &lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; chown shiny:shiny /home/shiny/.Renviron&lt;span style=&#34;color:#960050;background-color:#1e0010&#34;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;In your Shiny app (&lt;code&gt;app.R&lt;/code&gt; or &lt;code&gt;server.R&lt;/code&gt;), you can access it reliably:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;1
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-r&#34; data-lang=&#34;r&#34;&gt;should_in_shiny &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Sys.getenv&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;SHOULD_IN_SHINY&amp;#34;&lt;/span&gt;)
&lt;span style=&#34;color:#75715e&#34;&gt;# Returns: &amp;#34;From dockerfile&amp;#34;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;hr&gt;
&lt;h2 id=&#34;summary&#34;&gt;Summary&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;The Problem&lt;/strong&gt;: Shiny Server calls &lt;code&gt;su shiny --login --preserve-environment&lt;/code&gt;, causing &lt;code&gt;su&lt;/code&gt; to discard inherited environment variables (such as Docker &lt;code&gt;ENV&lt;/code&gt;) in favor of a clean login shell.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Solution 1 (&lt;code&gt;~/.profile&lt;/code&gt;)&lt;/strong&gt;: Append &lt;code&gt;export KEY=&amp;quot;value&amp;quot;&lt;/code&gt; to &lt;code&gt;/home/shiny/.profile&lt;/code&gt; in your &lt;code&gt;Dockerfile&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Solution 2 (&lt;code&gt;~/.Renviron&lt;/code&gt;)&lt;/strong&gt;: Append &lt;code&gt;KEY=&amp;quot;value&amp;quot;&lt;/code&gt; to &lt;code&gt;/home/shiny/.Renviron&lt;/code&gt; in your &lt;code&gt;Dockerfile&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Both approaches integrate seamlessly with Docker builds and ensure your Shiny application receives all required configuration variables cleanly.&lt;/p&gt;
- https://fortune9.netlify.app/2026/08/15/r-environment-variables-in-r-shiny-server-container/ - </description>
        </item>
    
    
    
        <item>
        <title>[R] How to Position the Legend Inside a Plot in ggplot2</title>
        <link>https://fortune9.netlify.app/2026/05/30/r-position-legend-inside-plot/</link>
        <pubDate>Sat, 30 May 2026 00:00:00 +0000</pubDate>
        
        <guid>https://fortune9.netlify.app/2026/05/30/r-position-legend-inside-plot/</guid>
        <creator>"ZZG"</creator>
        <description>Zhenguo Zhang&#39;s Blog https://fortune9.netlify.app/2026/05/30/r-position-legend-inside-plot/ -


&lt;p&gt;By default, &lt;code&gt;ggplot2&lt;/code&gt; places the legend outside the plot area (usually on the right). However, sometimes you may want to move the legend inside the plot to save space or improve the layout. This post explores how to achieve this using &lt;code&gt;theme()&lt;/code&gt; parameters.&lt;/p&gt;
&lt;div id=&#34;example-1-basic-usage-of-legend.position&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Example 1: Basic Usage of &lt;code&gt;legend.position&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;The simplest way to move a legend inside the plot is by providing a numeric vector of length two to the &lt;code&gt;legend.position&lt;/code&gt; argument in &lt;code&gt;theme()&lt;/code&gt;. These coordinates represent the relative position within the plot panel, ranging from 0 to 1. Check the
section on &lt;a href=&#34;#key-positioning-controls&#34;&gt;“Key Positioning Controls”&lt;/a&gt; at the end for a detailed explanation of the coordinate system.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(ggplot2)

ggplot(mtcars, aes(wt, mpg, color = factor(cyl))) +
  geom_point(size = 3) +
  theme_bw() +
  theme(legend.position = c(0.8, 0.8))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;https://fortune9.netlify.app/2026/05/30/r-position-legend-inside-plot/index_files/figure-html/example1-1.png&#34; alt=&#34;&#34; width=&#34;672&#34; /&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;example-2-fine-tuning-with-justification-and-background&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Example 2: Fine-Tuning with Justification and Background&lt;/h2&gt;
&lt;p&gt;When you place a legend inside, you often need to adjust which part of the legend box aligns with your coordinates and handle the background if it obscures data.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;legend.justification&lt;/code&gt;&lt;/strong&gt;: Controls the anchor point of the legend box. For example, &lt;code&gt;c(&#34;right&#34;, &#34;top&#34;)&lt;/code&gt; means the top-right corner of the legend box will be placed at the specified coordinates.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;legend.background&lt;/code&gt;&lt;/strong&gt;: Use &lt;code&gt;element_blank()&lt;/code&gt; to make the background transparent.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;ggplot(mtcars, aes(wt, mpg, color = factor(cyl))) +
  geom_point(size = 3) +
  theme_bw() +
  theme(
    legend.position = c(1, 1),
    legend.justification = c(&amp;quot;right&amp;quot;, &amp;quot;top&amp;quot;),
    legend.background = element_blank()
  )&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;https://fortune9.netlify.app/2026/05/30/r-position-legend-inside-plot/index_files/figure-html/example2-1.png&#34; alt=&#34;&#34; width=&#34;672&#34; /&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;example-3-positioning-in-faceted-plots&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Example 3: Positioning in Faceted Plots&lt;/h2&gt;
&lt;p&gt;Moving the legend inside a faceted plot works similarly: the whole figure is considered as
one plot for the coordinate system. You can use the coordinates to place it within one of the empty spaces or over a specific panel.
In the following example, the legend is placed in the bottom center of the plot, and a background is added to improve readability:&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;ggplot(mtcars, aes(wt, mpg, color = factor(cyl))) +
  geom_point(size = 3) +
  facet_wrap(~am) +
  theme_bw() +
  theme(
    legend.position = c(0.5, 0.2),
    legend.background = element_rect(fill = &amp;quot;white&amp;quot;, color = &amp;quot;grey80&amp;quot;)
  )&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;https://fortune9.netlify.app/2026/05/30/r-position-legend-inside-plot/index_files/figure-html/example3-1.png&#34; alt=&#34;&#34; width=&#34;672&#34; /&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;example-4-the-empty-space-trick-for-faceted-plots&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Example 4: The “Empty Space” Trick for Faceted Plots&lt;/h2&gt;
&lt;p&gt;If you have a panel which doesn’t have any data, and then it is the perfect spot to
place legend. To show this, the facet variable &lt;code&gt;carb&lt;/code&gt; has only 3 values, and we
will make a 2x2 facet grid. We will also remove the background and border of the legend.
The following example shows this:&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;# Use 3 categories to leave the 4th spot in a 2x2 grid empty
mtcars_subset &amp;lt;- mtcars[mtcars$carb %in% c(1, 2, 4), ]

ggplot(mtcars_subset, aes(wt, mpg, color = factor(cyl))) +
  geom_point(size = 3) +
  facet_wrap(~carb, nrow = 2, ncol = 2) +
  theme_bw() +
  theme(
    # Coordinates c(0.75, 0.25) target the center of the empty bottom-right area
    legend.position = c(0.75, 0.25),
    legend.background = element_blank(),
    legend.justification = &amp;quot;center&amp;quot;
  )&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;https://fortune9.netlify.app/2026/05/30/r-position-legend-inside-plot/index_files/figure-html/example4-1.png&#34; alt=&#34;&#34; width=&#34;672&#34; /&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;key-positioning-controls&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Key Positioning Controls&lt;/h2&gt;
&lt;p&gt;To master legend positioning, keep these three controls in mind:&lt;/p&gt;
&lt;ol style=&#34;list-style-type: decimal&#34;&gt;
&lt;li&gt;&lt;strong&gt;Coordinate System&lt;/strong&gt;: The coordinates &lt;code&gt;c(X, Y)&lt;/code&gt; represent a relative scale from 0 to 1 across the plot panel.
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;c(0, 0)&lt;/code&gt;: Bottom-left corner&lt;/li&gt;
&lt;li&gt;&lt;code&gt;c(1, 1)&lt;/code&gt;: Top-right corner&lt;/li&gt;
&lt;li&gt;&lt;code&gt;c(0.5, 0.5)&lt;/code&gt;: Center of the plot&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Anchor Point (&lt;code&gt;legend.justification&lt;/code&gt;)&lt;/strong&gt;: Use this to control which part of the legend box aligns with your coordinates. For example, &lt;code&gt;c(&#34;right&#34;, &#34;top&#34;)&lt;/code&gt; ensures the top-right corner of the legend box sits exactly at your target coordinate.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Background Removal&lt;/strong&gt;: If your legend blocks data points, clear the legend box background using &lt;code&gt;legend.background = element_blank()&lt;/code&gt;. Alternatively, use &lt;code&gt;element_rect()&lt;/code&gt; to give it a semi-transparent or styled background.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Happy Programming!&lt;/p&gt;
&lt;/div&gt;
- https://fortune9.netlify.app/2026/05/30/r-position-legend-inside-plot/ - </description>
        </item>
    
    
    
        <item>
        <title>[R] How to use ggpattern to add patterns to ggplot2 plots</title>
        <link>https://fortune9.netlify.app/2026/05/22/r-how-to-use-ggpattern/</link>
        <pubDate>Fri, 22 May 2026 00:00:00 +0000</pubDate>
        
        <guid>https://fortune9.netlify.app/2026/05/22/r-how-to-use-ggpattern/</guid>
        <creator>"ZZG"</creator>
        <description>Zhenguo Zhang&#39;s Blog https://fortune9.netlify.app/2026/05/22/r-how-to-use-ggpattern/ -


&lt;p&gt;Adding patterns to plots is a great way to improve accessibility (making plots colorblind-friendly) and to add an extra dimension of information. The &lt;code&gt;ggpattern&lt;/code&gt; package provides a rich set of tools to achieve this in &lt;code&gt;ggplot2&lt;/code&gt;.&lt;/p&gt;
&lt;div id=&#34;basic-example-with-mtcars&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Basic Example with mtcars&lt;/h2&gt;
&lt;p&gt;Let’s start with a barplot using the &lt;code&gt;mtcars&lt;/code&gt; dataset. We will map &lt;code&gt;cyl&lt;/code&gt; to the x-axis, &lt;code&gt;mpg&lt;/code&gt; to the y-axis, use &lt;code&gt;gear&lt;/code&gt; for the fill color, and &lt;code&gt;am&lt;/code&gt; for the pattern.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;# Prepare data
df &amp;lt;- mtcars %&amp;gt;%
  mutate(
    cyl = factor(cyl),
    gear = factor(gear),
    am = factor(am, labels = c(&amp;quot;Automatic&amp;quot;, &amp;quot;Manual&amp;quot;))
  )

# Create barplot
ggplot(df, aes(x = cyl, y = mpg, fill = gear)) +
  geom_bar_pattern(
    aes(pattern = am),
    stat = &amp;quot;identity&amp;quot;,
    position = &amp;quot;dodge&amp;quot;,
    color = &amp;quot;black&amp;quot;,
    pattern_fill = &amp;quot;black&amp;quot;,
    pattern_spacing = 0.02,
    pattern_key_scale_factor = 1.5
  ) +
  scale_pattern_manual(values = c(&amp;quot;stripe&amp;quot;, &amp;quot;crosshatch&amp;quot;)) +
  labs(
    title = &amp;quot;MPG by Cylinders, Gear, and Transmission&amp;quot;,
    subtitle = &amp;quot;Patterns representing transmission type&amp;quot;,
    x = &amp;quot;Cylinders&amp;quot;,
    y = &amp;quot;Miles Per Gallon (MPG)&amp;quot;,
    fill = &amp;quot;Gears&amp;quot;,
    pattern = &amp;quot;Transmission&amp;quot;
  ) +
  theme_minimal()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;https://fortune9.netlify.app/2026/05/22/r-how-to-use-ggpattern/index_files/figure-html/basic-example-1.png&#34; alt=&#34;&#34; width=&#34;768&#34; /&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;exploring-key-parameters&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Exploring Key Parameters&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;ggpattern&lt;/code&gt; package allows for fine-grained control over how patterns are rendered. Here are some of the most important parameters:&lt;/p&gt;
&lt;div id=&#34;pattern_key_scale_factor&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;1. pattern_key_scale_factor&lt;/h3&gt;
&lt;p&gt;This parameter scales the pattern density specifically in the legend. Without it, patterns in the legend can often be hard to see.
Reduce the value will make it easier fit into the legend keys.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;p_base &amp;lt;- ggplot(df, aes(x = cyl, y = mpg, fill = gear)) +
  geom_bar_pattern(
    aes(pattern = am),
    stat = &amp;quot;identity&amp;quot;,
    position = &amp;quot;dodge&amp;quot;,
    color = &amp;quot;black&amp;quot;,
    pattern_spacing = 0.02
  ) +
  theme_minimal() +
  labs(title = &amp;quot;Default vs Scaled Legend&amp;quot;)

# Default legend
p1 &amp;lt;- p_base + labs(subtitle = &amp;quot;Default (key_scale_factor = 1)&amp;quot;)

# Scaled legend
p2 &amp;lt;- p_base + 
  geom_bar_pattern(
    aes(pattern = am),
    stat = &amp;quot;identity&amp;quot;,
    position = &amp;quot;dodge&amp;quot;,
    color = &amp;quot;black&amp;quot;,
    pattern_spacing = 0.02,
    pattern_key_scale_factor = 0.5
  ) +
  labs(subtitle = &amp;quot;Scaled (key_scale_factor = 0.5)&amp;quot;)

p1&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;https://fortune9.netlify.app/2026/05/22/r-how-to-use-ggpattern/index_files/figure-html/scale-factor-1.png&#34; alt=&#34;&#34; width=&#34;768&#34; /&gt;&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;p2&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;https://fortune9.netlify.app/2026/05/22/r-how-to-use-ggpattern/index_files/figure-html/scale-factor-2.png&#34; alt=&#34;&#34; width=&#34;768&#34; /&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;pattern_spacing-and-pattern_density&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;2. pattern_spacing and pattern_density&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;pattern_spacing&lt;/code&gt; controls the distance between pattern elements (lower = denser), while &lt;code&gt;pattern_density&lt;/code&gt; controls the coverage (higher = denser).&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;# Spacing effect
ggplot(df, aes(x = cyl, y = mpg, fill = gear)) +
  geom_bar_pattern(
    aes(pattern = am),
    stat = &amp;quot;identity&amp;quot;,
    position = &amp;quot;dodge&amp;quot;,
    pattern_spacing = 0.2, # Wider spacing
    pattern_key_scale_factor = 1.5
  ) +
  labs(title = &amp;quot;Effect of pattern_spacing = 0.5 (Sparser)&amp;quot;) +
  theme_minimal()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;https://fortune9.netlify.app/2026/05/22/r-how-to-use-ggpattern/index_files/figure-html/spacing-density-1.png&#34; alt=&#34;&#34; width=&#34;768&#34; /&gt;&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;# Density effect
ggplot(df, aes(x = cyl, y = mpg, fill = gear)) +
  geom_bar_pattern(
    aes(pattern = am),
    stat = &amp;quot;identity&amp;quot;,
    position = &amp;quot;dodge&amp;quot;,
    pattern_density = 0.8, # Higher density
    pattern_key_scale_factor = 1.5
  ) +
  labs(title = &amp;quot;Effect of pattern_density = 0.8 (Denser)&amp;quot;) +
  theme_minimal()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;https://fortune9.netlify.app/2026/05/22/r-how-to-use-ggpattern/index_files/figure-html/spacing-density-2.png&#34; alt=&#34;&#34; width=&#34;768&#34; /&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;pattern_fill&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;3. pattern_fill&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;pattern_fill&lt;/code&gt; sets the color of the pattern elements themselves.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;ggplot(df, aes(x = cyl, y = mpg, fill = gear)) +
  geom_bar_pattern(
    aes(pattern = am),
    stat = &amp;quot;identity&amp;quot;,
    position = &amp;quot;dodge&amp;quot;,
    pattern_fill = &amp;quot;white&amp;quot;, # White pattern lines
    pattern_density = 0.5, # make it bigger so that the color is easier to see
    pattern_spacing = 0.02,
    pattern_key_scale_factor = 1.5
  ) +
  labs(title = &amp;quot;Effect of pattern_fill = &amp;#39;white&amp;#39;&amp;quot;) +
  theme_minimal()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;https://fortune9.netlify.app/2026/05/22/r-how-to-use-ggpattern/index_files/figure-html/pattern-fill-1.png&#34; alt=&#34;&#34; width=&#34;768&#34; /&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;pattern_shape&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;4. pattern_shape&lt;/h3&gt;
&lt;p&gt;For geometric patterns like &lt;code&gt;regular_polygon&lt;/code&gt;, &lt;code&gt;pattern_shape&lt;/code&gt; controls the number of sides.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;ggplot(df, aes(x = cyl, y = mpg, fill = gear)) +
  geom_bar_pattern(
    aes(pattern_shape=gear),
    pattern = &amp;quot;regular_polygon&amp;quot;,
    stat = &amp;quot;identity&amp;quot;,
    position = &amp;quot;dodge&amp;quot;,
    pattern_size = 0.5, # stroke line width
    pattern_density = 0.5, # increase the shape size
    pattern_spacing = 0.03,
    pattern_key_scale_factor = 1.5
  ) +
  scale_pattern_shape_manual(values = c(&amp;quot;3&amp;quot;=&amp;quot;circle&amp;quot;, &amp;quot;4&amp;quot;=&amp;quot;convex6&amp;quot;, &amp;quot;5&amp;quot;=&amp;quot;square&amp;quot;)) + # manually set shapes
  labs(title = &amp;quot;Effect of mapping pattern_shape to gear&amp;quot;) +
  theme_minimal()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;https://fortune9.netlify.app/2026/05/22/r-how-to-use-ggpattern/index_files/figure-html/pattern-shape-1.png&#34; alt=&#34;&#34; width=&#34;768&#34; /&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&#34;troubleshooting&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Troubleshooting&lt;/h2&gt;
&lt;p&gt;If you encounter issues installing or loading &lt;code&gt;ggpattern&lt;/code&gt; on Linux, you may need to install the following system dependencies:&lt;/p&gt;
&lt;pre class=&#34;bash&#34;&gt;&lt;code&gt;sudo apt-get install libudunits2-dev
sudo apt install libproj22
sudo apt-get install libgdal-dev&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
- https://fortune9.netlify.app/2026/05/22/r-how-to-use-ggpattern/ - </description>
        </item>
    
    
    
        <item>
        <title>[R] How to change legend key size in ggplot2</title>
        <link>https://fortune9.netlify.app/2026/04/27/r-how-to-change-legend-key-size-in-ggplot2/</link>
        <pubDate>Mon, 27 Apr 2026 00:00:00 +0000</pubDate>
        
        <guid>https://fortune9.netlify.app/2026/04/27/r-how-to-change-legend-key-size-in-ggplot2/</guid>
        <creator>"ZZG"</creator>
        <description>Zhenguo Zhang&#39;s Blog https://fortune9.netlify.app/2026/04/27/r-how-to-change-legend-key-size-in-ggplot2/ -


&lt;p&gt;In &lt;code&gt;ggplot2&lt;/code&gt;, the legend keys (the symbols next to the labels) usually inherit their size and appearance from the layers in the plot. For example, if you have a scatter plot with very small points, the legend keys will also be very small, making them hard to see.&lt;/p&gt;
&lt;p&gt;To fix this without changing the size of the points in the actual plot, you can use the &lt;code&gt;override.aes&lt;/code&gt; argument within &lt;code&gt;guide_legend()&lt;/code&gt;.&lt;/p&gt;
&lt;div id=&#34;the-problem-tiny-legend-keys&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;The Problem: Tiny Legend Keys&lt;/h3&gt;
&lt;p&gt;When plotting many data points, we often decrease the &lt;code&gt;size&lt;/code&gt; to avoid overplotting. However, this makes the legend keys tiny:&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(ggplot2)

p &amp;lt;- ggplot(iris, aes(Sepal.Length, Sepal.Width, color = Species)) +
  geom_point(size = 0.5) + 
  theme_minimal() +
  labs(title = &amp;quot;Tiny Legend Keys&amp;quot;)

p&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;https://fortune9.netlify.app/2026/04/27/r-how-to-change-legend-key-size-in-ggplot2/index_files/figure-html/tiny-legend-1.png&#34; alt=&#34;&#34; width=&#34;480&#34; /&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;the-solution-using-override.aes&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;The Solution: Using &lt;code&gt;override.aes&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;By using &lt;code&gt;guides()&lt;/code&gt;, we can “override” the aesthetics of the legend. This allows us to keep the small points in the plot while making the legend keys large and clear.&lt;/p&gt;
&lt;p&gt;If your legend is for the &lt;strong&gt;color&lt;/strong&gt; aesthetic:&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;p_fixed &amp;lt;- p + 
  guides(color = guide_legend(override.aes = list(size = 5))) +
  labs(title = &amp;quot;Fixed Legend Keys (Size 5)&amp;quot;)

p_fixed&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;https://fortune9.netlify.app/2026/04/27/r-how-to-change-legend-key-size-in-ggplot2/index_files/figure-html/fixed-legend-1.png&#34; alt=&#34;&#34; width=&#34;480&#34; /&gt;&lt;/p&gt;
&lt;p&gt;If you were using &lt;strong&gt;fill&lt;/strong&gt; (e.g., in a bar plot or boxplot), you would simply change &lt;code&gt;color&lt;/code&gt; to &lt;code&gt;fill&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;guides(fill = guide_legend(override.aes = list(size = 5)))&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div id=&#34;adjusting-legend-text-and-title-size&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Adjusting Legend Text and Title Size&lt;/h3&gt;
&lt;p&gt;Note that &lt;code&gt;override.aes&lt;/code&gt; only affects the symbols inside the legend. To change the size of the labels or the legend title, you should use the &lt;code&gt;theme()&lt;/code&gt; function:&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;p_fixed + 
  theme(
    legend.text = element_text(size = 12),   # Legend labels
    legend.title = element_text(size = 14, face = &amp;quot;bold&amp;quot;) # Legend title
  )&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;https://fortune9.netlify.app/2026/04/27/r-how-to-change-legend-key-size-in-ggplot2/index_files/figure-html/theme-adjust-1.png&#34; alt=&#34;&#34; width=&#34;480&#34; /&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;summary&#34; class=&#34;section level3&#34;&gt;
&lt;h3&gt;Summary&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;guides(color = guide_legend(override.aes = list(size = ...)))&lt;/code&gt; to change the &lt;strong&gt;symbol size&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;theme(legend.text = element_text(size = ...))&lt;/code&gt; to change the &lt;strong&gt;text size&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
- https://fortune9.netlify.app/2026/04/27/r-how-to-change-legend-key-size-in-ggplot2/ - </description>
        </item>
    
    
    
        <item>
        <title>Single vs Double Quotes in Command Line and R</title>
        <link>https://fortune9.netlify.app/2026/04/26/single-vs-double-quotes-in-command-line-and-r/</link>
        <pubDate>Sun, 26 Apr 2026 00:00:00 +0000</pubDate>
        
        <guid>https://fortune9.netlify.app/2026/04/26/single-vs-double-quotes-in-command-line-and-r/</guid>
        <creator>"ZZG"</creator>
        <description>Zhenguo Zhang&#39;s Blog https://fortune9.netlify.app/2026/04/26/single-vs-double-quotes-in-command-line-and-r/ -&lt;p&gt;When feeding a program with command line arguments, single quotes and double quotes make a significant difference.&lt;/p&gt;
&lt;h3 id=&#34;the-shell-rule&#34;&gt;The Shell Rule&lt;/h3&gt;
&lt;p&gt;Single quotes (&lt;code&gt;&#39;&lt;/code&gt;) do not allow escaping any characters; the contents are treated literally. Double quotes (&lt;code&gt;&amp;quot;&lt;/code&gt;), however, allow for character escaping and variable expansion.&lt;/p&gt;
&lt;p&gt;You can test this using the &lt;code&gt;printf&lt;/code&gt; command, which prints each argument it receives on a new line:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;1
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;2
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;3
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;4
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;5
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;6
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;7
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Using single quotes: the backslash is literal&lt;/span&gt;
printf &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;%s\n&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;\+hello&amp;#39;&lt;/span&gt;
&lt;span style=&#34;color:#75715e&#34;&gt;# Output: \+hello&lt;/span&gt;

&lt;span style=&#34;color:#75715e&#34;&gt;# Using double quotes: the shell escapes the double backslash&lt;/span&gt;
printf &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;%s\n&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;\\+hello&amp;#34;&lt;/span&gt;
&lt;span style=&#34;color:#75715e&#34;&gt;# Output: \+hello&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;As you can see, both commands result in the same string &lt;code&gt;\+hello&lt;/code&gt; being passed to the program. The former is read exactly as written, while in the latter, the shell interprets the double backslash as a single literal backslash before passing it along.&lt;/p&gt;
&lt;h3 id=&#34;the-r-console-rule&#34;&gt;The R Console Rule&lt;/h3&gt;
&lt;p&gt;In R, when you work directly in the R console, you &lt;strong&gt;must deal with the language&amp;rsquo;s own string literal syntax&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Most programming languages, including R, use the backslash (&lt;code&gt;\&lt;/code&gt;) as an escape character. So when you type it,
it will be explained as an escape character immediately. If you type &lt;code&gt;&amp;quot;\.&amp;quot;&lt;/code&gt; in R console, it will be interpreted
in the console first before being passed to R itself; the interpreter will likely tell you there is no such escape sequence as &lt;code&gt;\.&lt;/code&gt;, and it won&amp;rsquo;t actually put a backslash in the resulting string.&lt;/p&gt;
&lt;p&gt;To place a literal backslash in a string in R, you have to use a double backslash (&lt;code&gt;\\&lt;/code&gt;). This tells R that you don&amp;rsquo;t want the second backslash to be an escape character when typing &lt;strong&gt;in the console&lt;/strong&gt;, but rather that you want a single literal backslash character in the string to be passed to R.&lt;/p&gt;
&lt;p&gt;For instance, when defining a regular expression:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-r&#34; data-lang=&#34;r&#34;&gt;myregexp &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;^planet\\.name$&amp;#34;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;This creates a string containing the text &lt;code&gt;^planet\.name$&lt;/code&gt; (note the single backslash). This string is then passed to a regex function, which interprets the &lt;code&gt;\.&lt;/code&gt; sequence as &amp;ldquo;a literal dot&amp;rdquo; rather than the regex wildcard for &amp;ldquo;any character.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;This rule also applies to the scenario where you type the escaping characters in R scripts.&lt;/p&gt;
&lt;p&gt;For more depth on this, check out this &lt;a href=&#34;https://www.reddit.com/r/learnprogramming/comments/13bb5pa/why_double_slashes_in_regex_expressions/&#34;&gt;Reddit discussion on double slashes in regex&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&#34;command-line-arguments-for-r-scripts&#34;&gt;Command Line Arguments for R Scripts&lt;/h3&gt;
&lt;p&gt;Crucially, if you are running an R script and feeding it parameters from the command line (e.g., via &lt;code&gt;Rscript&lt;/code&gt;), the
above &lt;strong&gt;the shell rule&lt;/strong&gt; apply instead of the internal R console rules for those initial arguments.&lt;/p&gt;
&lt;p&gt;To see this in action, create a file named &lt;code&gt;test_args.R&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;1
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;2
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;3
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;4
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-r&#34; data-lang=&#34;r&#34;&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# test_args.R&lt;/span&gt;
args &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;commandArgs&lt;/span&gt;(trailingOnly &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;TRUE&lt;/span&gt;)
&lt;span style=&#34;color:#a6e22e&#34;&gt;if &lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;length&lt;/span&gt;(args) &lt;span style=&#34;color:#f92672&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt;) {
    &lt;span style=&#34;color:#a6e22e&#34;&gt;cat&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Argument received by R:&amp;#34;&lt;/span&gt;, args[1], &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;)
}
&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Now run it from your terminal:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;1
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;2
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;3
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;4
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;5
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;6
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;7
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Test with single quotes&lt;/span&gt;
Rscript test_args.R &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;\+hello&amp;#39;&lt;/span&gt;
&lt;span style=&#34;color:#75715e&#34;&gt;# Output: Argument received by R: \+hello&lt;/span&gt;

&lt;span style=&#34;color:#75715e&#34;&gt;# Test with double quotes&lt;/span&gt;
Rscript test_args.R &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;\\+hello&amp;#34;&lt;/span&gt;
&lt;span style=&#34;color:#75715e&#34;&gt;# Output: Argument received by R: \+hello&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;If you want to input a regular expression to an R script via the command line for use in a function like &lt;code&gt;sub()&lt;/code&gt;, you should use these shell quoting rules. The string &lt;code&gt;\+hello&lt;/code&gt; received by R will correctly match the literal string &lt;code&gt;+hello&lt;/code&gt; in your R code.&lt;/p&gt;
- https://fortune9.netlify.app/2026/04/26/single-vs-double-quotes-in-command-line-and-r/ - </description>
        </item>
    
    
    
        <item>
        <title>[R] How to modify the theme used by blogdown?</title>
        <link>https://fortune9.netlify.app/2026/04/18/r-how-to-modify-the-theme-used-by-blogdown/</link>
        <pubDate>Sat, 18 Apr 2026 00:00:00 +0000</pubDate>
        
        <guid>https://fortune9.netlify.app/2026/04/18/r-how-to-modify-the-theme-used-by-blogdown/</guid>
        <creator>"ZZG"</creator>
        <description>Zhenguo Zhang&#39;s Blog https://fortune9.netlify.app/2026/04/18/r-how-to-modify-the-theme-used-by-blogdown/ -&lt;p&gt;My website is built using &lt;code&gt;blogdown&lt;/code&gt; and published on Netlify via CI/CD. Recently, I updated my Hugo version from 0.92 to 0.154.2. Unfortunately, this update broke the deployment pipeline due to an incompatibility in one of the files within the &lt;code&gt;diary&lt;/code&gt; theme.&lt;/p&gt;
&lt;p&gt;When your Hugo theme is no longer compatible with a newer Hugo version or if you simply want to customize its behavior, there are two primary ways to handle it.&lt;/p&gt;
&lt;h2 id=&#34;solution-1-overriding-theme-files-locally&#34;&gt;Solution 1: Overriding Theme Files Locally&lt;/h2&gt;
&lt;p&gt;The simplest way to modify a theme without changing the theme&amp;rsquo;s source code is to take advantage of Hugo&amp;rsquo;s lookup order. Hugo prioritizes files in your root project folder over those in the &lt;code&gt;themes/&lt;/code&gt; directory.&lt;/p&gt;
&lt;h3 id=&#34;step-by-step-instructions&#34;&gt;Step-by-step instructions:&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Identify the file in the theme that needs modification (e.g., &lt;code&gt;themes/diary/layouts/_default/single.html&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Create a corresponding directory structure under your root &lt;code&gt;layouts/&lt;/code&gt; folder if it doesn&amp;rsquo;t exist.&lt;/li&gt;
&lt;li&gt;Copy the file from the theme folder to your root folder:
&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;1
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;mkdir -p layouts/_default
cp themes/diary/layouts/_default/single.html layouts/_default/single.html
&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;Modify &lt;code&gt;layouts/_default/single.html&lt;/code&gt; as needed. Hugo will now use your local version instead of the one in the theme.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;solution-2-forking-the-theme-repository&#34;&gt;Solution 2: Forking the Theme Repository&lt;/h2&gt;
&lt;p&gt;If you have many changes or want to manage the theme&amp;rsquo;s source code directly, forking the theme is a better long-term solution. Since &lt;code&gt;blogdown&lt;/code&gt; (and Hugo) typically manages themes as Git submodules, you&amp;rsquo;ll need to update the submodule to point to your fork.&lt;/p&gt;
&lt;h3 id=&#34;step-by-step-instructions-1&#34;&gt;Step-by-step instructions:&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Fork the repository&lt;/strong&gt;: Go to the original theme repo &lt;a href=&#34;https://github.com/AmazingRise/hugo-theme-diary.git&#34;&gt;hugo-theme-diary&lt;/a&gt; and fork it to your own GitHub account.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Clone your blog repo&lt;/strong&gt; (if not already local): &lt;code&gt;https://github.com/fortune9/blogdown-everyday.git&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Update the submodule URL&lt;/strong&gt;:
Update your submodule to point to your forked URL:
&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;git submodule set-url themes/diary https://github.com/YOUR_USERNAME/hugo-theme-diary.git
&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sync and Update&lt;/strong&gt;:
&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;1
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;git submodule sync
git submodule update --init --recursive
&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Apply your changes&lt;/strong&gt;: Go into the &lt;code&gt;themes/diary&lt;/code&gt; directory, make your fixes, commit, and push them to your fork.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Commit the submodule change in your blog repo&lt;/strong&gt;:
Back in the root of your blog repo, commit the change to the submodule pointer:
&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;1
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;2
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;git add themes/diary
git commit -m &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Switch diary theme to personal fork and apply Hugo compatibility fixes&amp;#34;&lt;/span&gt;
git push
&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;By following either of these methods, you can ensure your blog remains compatible with the latest Hugo versions while maintaining your custom styles and fixes.&lt;/p&gt;
- https://fortune9.netlify.app/2026/04/18/r-how-to-modify-the-theme-used-by-blogdown/ - </description>
        </item>
    
    
    
        <item>
        <title>[R] Setting Up an Interactive R Shiny Plotting App</title>
        <link>https://fortune9.netlify.app/2025/10/08/r-setting-up-an-interactive-r-shiny-plotting-app/</link>
        <pubDate>Wed, 08 Oct 2025 00:00:00 +0000</pubDate>
        
        <guid>https://fortune9.netlify.app/2025/10/08/r-setting-up-an-interactive-r-shiny-plotting-app/</guid>
        <creator>"ZZG"</creator>
        <description>Zhenguo Zhang&#39;s Blog https://fortune9.netlify.app/2025/10/08/r-setting-up-an-interactive-r-shiny-plotting-app/ -&lt;p&gt;I have an ieda of creating a shiny app to create all kinds of plots interactively,
so that users can choose their color, symbols, etc, which is very useful for data exploration and make a publication-quality figure.&lt;/p&gt;
&lt;p&gt;Today, I make it and published it at &lt;a href=&#34;https://fortune9.shinyapps.io/interactive_plot/&#34;&gt;https://fortune9.shinyapps.io/interactive_plot/&lt;/a&gt;. The source code is at github &lt;a href=&#34;https://github.com/fortune9/interactive_plot&#34;&gt;https://github.com/fortune9/interactive_plot&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This guide focuses on the infrastructure setup for creating and deploying an interactive plotting application using R Shiny. For detailed features and functionality, please refer to the &lt;a href=&#34;https://github.com/fortune9/interactive_plot/blob/main/README.md&#34;&gt;README.md&lt;/a&gt; in the GitHub repository.&lt;/p&gt;
&lt;h2 id=&#34;overview&#34;&gt;Overview&lt;/h2&gt;
&lt;p&gt;The application allows users to create customizable plots (scatter, bar, box) from both uploaded data and built-in R datasets, with extensive customization options and export capabilities. All source code is available at &lt;a href=&#34;https://github.com/fortune9/interactive_plot&#34;&gt;https://github.com/fortune9/interactive_plot&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;project-setup&#34;&gt;Project Setup&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Create the project structure:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;1
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;2
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;3
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;4
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;5
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;6
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;interactive_plot/
├── app.R
├── ui.R
├── server.R
├── www/
└── data/
&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;ol start=&#34;2&#34;&gt;
&lt;li&gt;Install required packages:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-R&#34; data-lang=&#34;R&#34;&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;install.packages&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;shiny&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ggplot2&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;tidyverse&amp;#34;&lt;/span&gt;))
&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;ol start=&#34;3&#34;&gt;
&lt;li&gt;Create the main app file (&lt;code&gt;app.R&lt;/code&gt;):&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;1
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;2
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;3
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;4
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;5
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;6
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;7
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;8
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-R&#34; data-lang=&#34;R&#34;&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;library&lt;/span&gt;(shiny)
&lt;span style=&#34;color:#a6e22e&#34;&gt;library&lt;/span&gt;(ggplot2)
&lt;span style=&#34;color:#a6e22e&#34;&gt;library&lt;/span&gt;(tidyverse)

&lt;span style=&#34;color:#a6e22e&#34;&gt;source&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ui.R&amp;#34;&lt;/span&gt;)
&lt;span style=&#34;color:#a6e22e&#34;&gt;source&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;server.R&amp;#34;&lt;/span&gt;)

&lt;span style=&#34;color:#a6e22e&#34;&gt;shinyApp&lt;/span&gt;(ui &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; ui, server &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; server)
&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id=&#34;deployment&#34;&gt;Deployment&lt;/h2&gt;
&lt;h3 id=&#34;1-prepare-for-deployment&#34;&gt;1. Prepare for Deployment&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Install the rsconnect package:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-R&#34; data-lang=&#34;R&#34;&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;install.packages&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;rsconnect&amp;#34;&lt;/span&gt;)
&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;ol start=&#34;2&#34;&gt;
&lt;li&gt;
&lt;p&gt;Create a shinyapps.io account at &lt;a href=&#34;https://www.shinyapps.io&#34;&gt;https://www.shinyapps.io&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Get your account tokens from:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Dashboard → Account → Tokens&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set up authentication in R:&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;1
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;2
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;3
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;4
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-R&#34; data-lang=&#34;R&#34;&gt;rsconnect&lt;span style=&#34;color:#f92672&#34;&gt;::&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;setAccountInfo&lt;/span&gt;(
  name&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;your-account-name&amp;#39;&lt;/span&gt;,
  token&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;your-token&amp;#39;&lt;/span&gt;,
  secret&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;your-secret&amp;#39;&lt;/span&gt;
)
&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id=&#34;2-deploy-using-github-actions&#34;&gt;2. Deploy Using GitHub Actions&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Add GitHub Secrets:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;SHINYAPPS_USER&lt;/li&gt;
&lt;li&gt;SHINYAPPS_TOKEN&lt;/li&gt;
&lt;li&gt;SHINYAPPS_SECRET&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create GitHub Actions workflow (&lt;code&gt;.github/workflows/deploy.yml&lt;/code&gt;):&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;
&lt;table style=&#34;border-spacing:0;padding:0;margin:0;border:0;width:auto;overflow:auto;display:block;&#34;&gt;&lt;tr&gt;&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 1
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 2
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 3
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 4
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 5
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 6
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 7
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 8
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt; 9
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;10
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;11
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;12
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;13
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;14
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;15
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;16
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;17
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;18
&lt;/span&gt;&lt;span style=&#34;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f&#34;&gt;19
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td style=&#34;vertical-align:top;padding:0;margin:0;border:0;;width:100%&#34;&gt;
&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Deploy to shinyapps.io&lt;/span&gt;
&lt;span style=&#34;color:#f92672&#34;&gt;on&lt;/span&gt;:
  &lt;span style=&#34;color:#f92672&#34;&gt;push&lt;/span&gt;:
    &lt;span style=&#34;color:#f92672&#34;&gt;branches&lt;/span&gt;:
      - &lt;span style=&#34;color:#ae81ff&#34;&gt;main&lt;/span&gt;
&lt;span style=&#34;color:#f92672&#34;&gt;jobs&lt;/span&gt;:
  &lt;span style=&#34;color:#f92672&#34;&gt;deploy&lt;/span&gt;:
    &lt;span style=&#34;color:#f92672&#34;&gt;runs-on&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;ubuntu-latest&lt;/span&gt;
    &lt;span style=&#34;color:#f92672&#34;&gt;steps&lt;/span&gt;:
      - &lt;span style=&#34;color:#f92672&#34;&gt;uses&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;actions/checkout@v2&lt;/span&gt;
      - &lt;span style=&#34;color:#f92672&#34;&gt;uses&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;r-lib/actions/setup-r@v2&lt;/span&gt;
      - &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Deploy to shinyapps.io&lt;/span&gt;
        &lt;span style=&#34;color:#f92672&#34;&gt;run&lt;/span&gt;: |&lt;span style=&#34;color:#e6db74&#34;&gt;
&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;          Rscript -e &amp;#39;install.packages(c(&amp;#34;shiny&amp;#34;, &amp;#34;rsconnect&amp;#34;))&amp;#39;
&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;          Rscript -e &amp;#39;rsconnect::deployApp()&amp;#39;&lt;/span&gt;          
        &lt;span style=&#34;color:#f92672&#34;&gt;env&lt;/span&gt;:
          &lt;span style=&#34;color:#f92672&#34;&gt;SHINYAPPS_USER&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;${{ secrets.SHINYAPPS_USER }}&lt;/span&gt;
          &lt;span style=&#34;color:#f92672&#34;&gt;SHINYAPPS_TOKEN&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;${{ secrets.SHINYAPPS_TOKEN }}&lt;/span&gt;
          &lt;span style=&#34;color:#f92672&#34;&gt;SHINYAPPS_SECRET&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;${{ secrets.SHINYAPPS_SECRET }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id=&#34;development-tips&#34;&gt;Development Tips&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Local Testing&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Run the app locally using &lt;code&gt;shiny::runApp()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Test with different browsers and screen sizes&lt;/li&gt;
&lt;li&gt;Verify all features before deployment&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Deployment Checks&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ensure all required packages are listed in the deployment workflow&lt;/li&gt;
&lt;li&gt;Test deployment locally using rsconnect before pushing to GitHub&lt;/li&gt;
&lt;li&gt;Monitor GitHub Actions logs for deployment issues&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Maintenance&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Keep your shinyapps.io tokens secure&lt;/li&gt;
&lt;li&gt;Update package versions regularly&lt;/li&gt;
&lt;li&gt;Monitor app usage on shinyapps.io dashboard&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;This guide covers the essential setup and deployment steps for your Shiny app. For implementation details and features, refer to the source code and documentation in the GitHub repository at &lt;a href=&#34;https://github.com/fortune9/interactive_plot&#34;&gt;https://github.com/fortune9/interactive_plot&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For questions or improvements, please open an issue in the GitHub repository.&lt;/p&gt;
&lt;p&gt;Do you know? Actually most of the code was written using Github Copilot, to which
I feed the file &lt;a href=&#34;https://github.com/fortune9/interactive_plot/blob/main/development_plan.md&#34;&gt;development plan.md&lt;/a&gt; to start. Very cool 😄!&lt;/p&gt;
- https://fortune9.netlify.app/2025/10/08/r-setting-up-an-interactive-r-shiny-plotting-app/ - </description>
        </item>
    
    
    
        <item>
        <title>[R] Use new_scale_xxx() function to add the same scale type in different ggplot layers</title>
        <link>https://fortune9.netlify.app/2025/05/10/r-use-new-scale-xxx-function-to-add-the-same-scale-type-in-different-ggplot-layers/</link>
        <pubDate>Sat, 10 May 2025 00:00:00 +0000</pubDate>
        
        <guid>https://fortune9.netlify.app/2025/05/10/r-use-new-scale-xxx-function-to-add-the-same-scale-type-in-different-ggplot-layers/</guid>
        <creator>"ZZG"</creator>
        <description>Zhenguo Zhang&#39;s Blog https://fortune9.netlify.app/2025/05/10/r-use-new-scale-xxx-function-to-add-the-same-scale-type-in-different-ggplot-layers/ -


&lt;p&gt;In one ggplot figure, normally you can only use one scale for each aesthetic mapping. For example, if you use &lt;code&gt;scale_color_manual()&lt;/code&gt; to set the color scale for a layer, you cannot use another &lt;code&gt;scale_color_manual()&lt;/code&gt; for another layer, or
set the color scale more then once in the function &lt;code&gt;aes()&lt;/code&gt;. However, you can use the &lt;code&gt;new_scale_color()&lt;/code&gt; function from the &lt;code&gt;ggnewscale&lt;/code&gt; package to add a new scale for the same aesthetic mapping in different layers.&lt;/p&gt;
&lt;p&gt;In this post, I will showcase how to use the &lt;code&gt;new_scale_color()&lt;/code&gt; function to add two different color scales in a ggplot figure. The first scale will be for a discrete variable (e.g., number of cylinders), and the second scale will be for a continuous variable (e.g., density level).&lt;/p&gt;
&lt;p&gt;Load packages first.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(ggplot2)
library(ggnewscale)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Use the mtcars dataset for the example&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;data(mtcars)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Create a plot with two color scales:
1. Points colored by ‘cyl’ (discrete)
2. Density contours colored by density level (continuous)&lt;/p&gt;
&lt;p&gt;First, let’s make a scatter plot of &lt;code&gt;mpg&lt;/code&gt; vs &lt;code&gt;wt&lt;/code&gt; with points colored by the number of cylinders (&lt;code&gt;cyl&lt;/code&gt;). We will use the &lt;code&gt;geom_point()&lt;/code&gt; function for this layer.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;plt &amp;lt;- ggplot(mtcars, aes(x = wt, y = mpg)) +
  # First layer: Scatter plot colored by cylinders (discrete variable)
  geom_point(aes(color = factor(cyl)), size = 3) +  
  scale_color_discrete(name = &amp;quot;Cylinders&amp;quot;)

plt&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;https://fortune9.netlify.app/2025/05/10/r-use-new-scale-xxx-function-to-add-the-same-scale-type-in-different-ggplot-layers/index_files/figure-html/unnamed-chunk-3-1.png&#34; width=&#34;1000&#34; style=&#34;display: block; margin: auto;&#34; /&gt;&lt;/p&gt;
&lt;p&gt;Set new scale for the next layer&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;# Reset the color scale for the next layer
plt &amp;lt;- plt + new_scale_color()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Add a second layer: Density contours colored by density level (continuous variable)&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;plt &amp;lt;- plt +
  geom_density_2d(aes(color = after_stat(level))) +  
  scale_color_viridis_c(name = &amp;quot;Density Level&amp;quot;, option = &amp;quot;magma&amp;quot;) +
  
  # Add labels and theme
  labs(title = &amp;quot;Dual Color Scales with new_scale_color()&amp;quot;,
       x = &amp;quot;Weight (1000 lbs)&amp;quot;,
       y = &amp;quot;Miles per Gallon&amp;quot;) +
  theme_minimal()

plt&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;https://fortune9.netlify.app/2025/05/10/r-use-new-scale-xxx-function-to-add-the-same-scale-type-in-different-ggplot-layers/index_files/figure-html/unnamed-chunk-4-1.png&#34; width=&#34;1000&#34; style=&#34;display: block; margin: auto;&#34; /&gt;&lt;/p&gt;
&lt;p&gt;Here I demonstrated how to use the &lt;code&gt;new_scale_color()&lt;/code&gt; function from the &lt;code&gt;ggnewscale&lt;/code&gt; package, one can also use &lt;code&gt;new_scale_fill()&lt;/code&gt; for fill aesthetics.
For other aesthetics, such as &lt;code&gt;size&lt;/code&gt;, &lt;code&gt;shape&lt;/code&gt;, etc., you can call
&lt;code&gt;new_scale(&#34;size&#34;)&lt;/code&gt;, &lt;code&gt;new_scale(&#34;shape&#34;)&lt;/code&gt;, etc. to add new scales.&lt;/p&gt;
&lt;p&gt;To learn more, check the webpage &lt;a href=&#34;https://eliocamp.github.io/ggnewscale/&#34; class=&#34;uri&#34;&gt;https://eliocamp.github.io/ggnewscale/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Happy programming 😃&lt;/p&gt;
- https://fortune9.netlify.app/2025/05/10/r-use-new-scale-xxx-function-to-add-the-same-scale-type-in-different-ggplot-layers/ - </description>
        </item>
    
    
    
        <item>
        <title>[R] How to create errorbars with overlaid points using ggplot</title>
        <link>https://fortune9.netlify.app/2025/04/26/r-how-to-create-an-error-barplot-with-overlaid-points-using-ggplot/</link>
        <pubDate>Sat, 26 Apr 2025 00:00:00 +0000</pubDate>
        
        <guid>https://fortune9.netlify.app/2025/04/26/r-how-to-create-an-error-barplot-with-overlaid-points-using-ggplot/</guid>
        <creator>"ZZG"</creator>
        <description>Zhenguo Zhang&#39;s Blog https://fortune9.netlify.app/2025/04/26/r-how-to-create-an-error-barplot-with-overlaid-points-using-ggplot/ -


&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;library(ggplot2)
library(dplyr)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Sometimes you may want to create a plot with the following features:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a point to indicate the mean of a group&lt;/li&gt;
&lt;li&gt;error bars to indicate the standard deviation of the group&lt;/li&gt;
&lt;li&gt;and each group may have subgroups, which are represented by different colors.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In this post, I will show you how to create such a plot using the &lt;code&gt;ggplot2&lt;/code&gt; package in R.&lt;/p&gt;
&lt;p&gt;We will use the builtin &lt;code&gt;mtcars&lt;/code&gt; dataset as an example. And we need to
compute the following variables for later use:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The mean mpg for each group of &lt;code&gt;cyl&lt;/code&gt; (number of cylinders) and &lt;code&gt;gear`` (number of gears), here&lt;/code&gt;cyl&lt;code&gt;is the main group and&lt;/code&gt;gear` is the subgroup.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;# Load the mtcars dataset
data(mtcars)
# Compute the mean and standard deviation of mpg for each group
mtcars_summary &amp;lt;- mtcars %&amp;gt;%
  group_by(cyl, gear) %&amp;gt;%
  summarise(mean_mpg = mean(mpg), sd_mpg = sd(mpg)) %&amp;gt;%
  ungroup()
# replace the NA values in sd_mpg with 1
mtcars_summary$sd_mpg[is.na(mtcars_summary$sd_mpg)] &amp;lt;- 1
# convert group variables into factors
mtcars_summary$cyl &amp;lt;- factor(mtcars_summary$cyl)
mtcars_summary$gear &amp;lt;- factor(mtcars_summary$gear)&lt;/code&gt;&lt;/pre&gt;
&lt;div id=&#34;create-the-plot---first-try&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Create the plot - first try&lt;/h2&gt;
&lt;p&gt;Now we can create the plot using &lt;code&gt;ggplot2&lt;/code&gt;. We will use the &lt;code&gt;geom_point()&lt;/code&gt; function to create the points, and the &lt;code&gt;geom_errorbar()&lt;/code&gt; function to create the error bars. We will also use the &lt;code&gt;aes()&lt;/code&gt; function to specify the aesthetics of the plot.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;# Create the plot
plt &amp;lt;- ggplot(mtcars_summary, aes(x = cyl, y = mean_mpg, color = gear)) +
  geom_point(size = 3) + # add points
  geom_errorbar(aes(ymin = mean_mpg - sd_mpg, ymax = mean_mpg + sd_mpg), width = 0.2) + # add error bars
  labs(x = &amp;quot;Number of Cylinders&amp;quot;, y = &amp;quot;Mean MPG&amp;quot;, color = &amp;quot;Number of Gears&amp;quot;) + # add labels
  theme_minimal() + # use a minimal theme
  theme(legend.position = &amp;quot;top&amp;quot;) # move the legend to the top
plt&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;https://fortune9.netlify.app/2025/04/26/r-how-to-create-an-error-barplot-with-overlaid-points-using-ggplot/index_files/figure-html/unnamed-chunk-3-1.png&#34; width=&#34;1000&#34; /&gt;&lt;/p&gt;
&lt;p&gt;Well, it is working, but the problem is that the error bars and points are all
aligned at the same position of x-axis. This is not what we want. We want the
subgroups to be separated by a small distance.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;create-the-plot---second-try&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Create the plot - second try&lt;/h2&gt;
&lt;p&gt;To separate the subgroups, we can use the &lt;code&gt;position_dodge()&lt;/code&gt; function. This function will move the points and error bars to the left and right, so that they are not overlapping.&lt;/p&gt;
&lt;pre class=&#34;r&#34;&gt;&lt;code&gt;pd &amp;lt;- position_dodge(width = 0.5)
# Create the plot with position_dodge
plt &amp;lt;- ggplot(mtcars_summary, aes(x = cyl, y = mean_mpg, color = gear)) +
  geom_point(size = 3, position = pd) + # add points with position_dodge
  geom_errorbar(aes(ymin = mean_mpg - sd_mpg, ymax = mean_mpg + sd_mpg), width = 0.2, position = pd) + # add error bars with position_dodge
  labs(x = &amp;quot;Number of Cylinders&amp;quot;, y = &amp;quot;Mean MPG&amp;quot;, color = &amp;quot;Number of Gears&amp;quot;) + # add labels
  theme_minimal() + # use a minimal theme
  theme(legend.position = &amp;quot;top&amp;quot;) # move the legend to the top
plt&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&#34;https://fortune9.netlify.app/2025/04/26/r-how-to-create-an-error-barplot-with-overlaid-points-using-ggplot/index_files/figure-html/unnamed-chunk-4-1.png&#34; width=&#34;1000&#34; /&gt;&lt;/p&gt;
&lt;p&gt;Cool. Isn’t it?&lt;/p&gt;
&lt;p&gt;The only difference is that we added the &lt;code&gt;position = pd&lt;/code&gt; argument to the &lt;code&gt;geom_point()&lt;/code&gt; and &lt;code&gt;geom_errorbar()&lt;/code&gt; functions. This tells &lt;code&gt;ggplot2&lt;/code&gt; to use the &lt;code&gt;position_dodge()&lt;/code&gt; function to separate the subgroups.&lt;/p&gt;
&lt;/div&gt;
&lt;div id=&#34;conclusion&#34; class=&#34;section level2&#34;&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In this post, we learned how to create a plot with error bars and overlaid points using the &lt;code&gt;ggplot2&lt;/code&gt; package in R. We also learned how to separate the subgroups using the &lt;code&gt;position_dodge()&lt;/code&gt; function.&lt;/p&gt;
&lt;p&gt;If you want to learn more about the function &lt;code&gt;position_dodge()&lt;/code&gt;, you can check an
excellent post &lt;a href=&#34;https://stackoverflow.com/questions/34889766/what-is-the-width-argument-in-position-dodge/35102486#35102486&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Happy programming! 😃&lt;/p&gt;
&lt;/div&gt;
- https://fortune9.netlify.app/2025/04/26/r-how-to-create-an-error-barplot-with-overlaid-points-using-ggplot/ - </description>
        </item>
    
    
  </channel>
</rss> 