From 18f4ecd0dd59c039fb6a4dbbb9b23042ebbba176 Mon Sep 17 00:00:00 2001 From: Derek Ogle Date: Sun, 26 Mar 2023 09:38:31 -0500 Subject: [PATCH] Cleaned up post issue --- blog/posts/_2023-3-28_Size/index.qmd | 276 ++++++++++++++++++ blog/posts/_2023-3-28_Size/preview.png | Bin 0 -> 3127 bytes docs/blog/index.html | 105 +++---- .../index.html | 2 + .../posts/2015-9-6_Cumulative_Sums/index.html | 2 + .../posts/2016-11-11_Pauly-VBModel/index.html | 2 + docs/blog/posts/2016-12-9_PSD_SE/index.html | 2 + .../2017-11-7_BackCalculationPlot/index.html | 2 + .../index.html | 2 + .../posts/2017-4-20_BlandAltman/index.html | 2 + .../2017-7-28_LF_Ridgeline_Plot/index.html | 2 + .../posts/2017-8-9_Mean_Weights/index.html | 2 + .../index.html | 2 + .../index.html | 2 + .../posts/2019-12-31_vonB_plots_1/index.html | 2 + .../posts/2020-1-2_vonB_plots_2/index.html | 2 + .../posts/2021-3-15-AgeBiasPlots/index.html | 2 + .../index.html | 2 + .../index.html | 2 + .../2021-5-25_fitPlot-replacement/index.html | 2 + .../2021-5-26_filterD-replacement/index.html | 2 + .../2021-6-1_residPlot-replacement/index.html | 2 + .../2022-12-22_AFS_Style_Figures/index.html | 2 + .../2023-2-15_Vaisviletal2022_ROC/index.html | 2 + .../index.html | 2 + .../index.html | 2 + .../posts/2023-3-15-Axis_Magic/index.html | 1 + .../index.html | 1 + .../2023-3-20-Rooketal2022_Fig4/index.html | 2 + .../index.html | 1 + .../index.html | 1 + .../index.html | 2 + .../index.html | 2 + .../posts/2023-3-9-Clemens2022/index.html | 2 + .../index.html | 2 + .../2023_2_14_Quistetal2022_BCData/index.html | 2 + docs/listings.json | 1 - docs/search.json | 65 ++--- docs/sitemap.xml | 198 ++++++------- .../posts/2016-6-12_Halflife_of_K/index.html | 2 + .../2018-4-19_Adding_Zero_Catches/index.html | 2 + .../posts/2019-3-8_ALK_FWDrumLE/index.html | 2 + .../posts/2019-3-8_ALK_RockBassLO/index.html | 2 + .../posts/2019-3-8_ALK_StripedBass/index.html | 2 + .../index.html | 2 + .../2019-3-8_Condition_BGInch/index.html | 2 + .../index.html | 2 + .../posts/2019-3-8_Graphing_Inch/index.html | 2 + .../2019-3-8_Graphing_YPerchTL/index.html | 2 + .../2019-3-8_Growth_EuroPerch/index.html | 2 + .../2019-3-8_Growth_RockBassLO/index.html | 2 + .../posts/2019-3-8_Growth_Sculpin/index.html | 2 + .../2019-3-8_MR_TanRiffleshell/index.html | 2 + .../2019-3-8_MR_UNSPRainbowTrout/index.html | 2 + .../posts/2019-3-8_MR_URBrownTrout/index.html | 2 + .../posts/2019-3-8_MR_WIYOYWalleye/index.html | 2 + .../index.html | 2 + .../index.html | 2 + .../2019-3-8_Recruitment_WalleyeEL/index.html | 2 + .../2019-3-8_SizeStrux_YPerchTL/index.html | 2 + .../posts/2019-3-8_WLBluegill_Inch/index.html | 2 + .../posts/2019-3-8_WLLMB_Inch/index.html | 2 + .../posts/2019-3-8_WL_YPerchTL/index.html | 2 + .../posts/2019-3-8_Wrangling_Inch/index.html | 2 + .../2019-3-8_Wrangling_YPerchTL/index.html | 2 + .../2022-12-19_AgeComp_WalleyePS/index.html | 2 + .../2022-12-19_SizeStrux_YPerchSB1/index.html | 2 + .../2022-12-19_Using_fishR_Data/index.html | 2 + .../index.html | 2 + .../2022-12-21_SizeStrux_BGLouise/index.html | 2 + .../posts/2022-12-22_BagLimits_MN/index.html | 2 + .../2022-12-23_Depletion_Ruffe/index.html | 2 + .../posts/2022-12-23_MR_SeaLamprey/index.html | 2 + .../2022-12-23_Removal_Crayfish/index.html | 2 + .../2022-12-23_Removal_EBullhead/index.html | 2 + 75 files changed, 574 insertions(+), 205 deletions(-) create mode 100644 blog/posts/_2023-3-28_Size/index.qmd create mode 100644 blog/posts/_2023-3-28_Size/preview.png diff --git a/blog/posts/_2023-3-28_Size/index.qmd b/blog/posts/_2023-3-28_Size/index.qmd new file mode 100644 index 0000000..8bfce06 --- /dev/null +++ b/blog/posts/_2023-3-28_Size/index.qmd @@ -0,0 +1,276 @@ +--- +title: How Does Size Work in ggplot2 +description: Demonstration of size= and linewidth= in ggplot2 objects. +author: Derek H. Ogle +date: 3/27/2023 +image: preview.png +categories: + - ggplot2 + - axes + - annotations + - labels +--- + +# Introduction +I have often wrestled with issues of "size" with respect to ggplot objects. It seems that `size=` behaves differently in certain situations and is unrelated to `linewidth=`. I often just fiddle with the values until I get something that looks like I want. Dissatisfied with this approach, I explored the idea of "size" in `ggplot2` further and report some of my findings here. + +```{r} +#| label: load-packages +library(ggplot2) +``` + + +# Text +### Default Sizes +Unless modified by the user, the default "base" font size in most `ggplot2` themes is 11 pt. This is evident for `theme_grey()` (the default `ggplot2` theme) below. This can be modified with `base_size=` to the theme function. + +```{r} +#| label: see-theme-text-size +theme_grey()$text +``` + +Several of the default font sizes for other items are based on this base size. For example, for most themes the axis titles are the base size, the plot title is 1.2× larger than the base size, and the axis tick labels and facet strip labels are 0.8× the base size.^[I chose not to show the code by default for some of these plots because the point demonstrated by the plot is the point, not the code. However, click "code" if you would like to see the code.] + +```{r} +#| label: demo-default-text-sizes +#| code-fold: true +#| fig.width: 5 +pd <- ggplot() + + geom_point() + + scale_x_continuous(name="Base Font Size (11)", + limits=c(0,1),breaks=c(0,1),expand=expansion(add=0.5), + labels=rep("0.8X Base Font Size",2)) + + scale_y_continuous(name="Base Font Size (11)", + limits=c(0,1),breaks=c(0,1),expand=expansion(add=0.25), + labels=rep("0.8X Base Font Size",2)) + + ggtitle("1.2X Base Font Size") +pd +``` + +Text added to the plot with `geom_text()` is shown at the base font size by default. + +```{r} +#| label: demo-default-label-size +#| code-fold: true +#| fig.width: 5 +pd + + geom_text(data=data.frame(x=0.5,y=0.5,label="Text at Default Base Font Size"), + mapping=aes(x=x,y=y,label=label)) +``` + +### Text Label Font Sizes +`geom_text()` has a `size=` argument for changing the size of the text. As such, you might change it to 13.2 assuming that its size would then match the size of plot title (i.e., 1.2×11). + +```{r} +#| label: demo-default-label-issue-1 +#| code-fold: true +#| fig.width: 5 +pd + + geom_text(data=data.frame(x=0.5,y=0.5,label="Text at 'size=13.2'"), + mapping=aes(x=x,y=y,label=label),size=13.2) +``` + +This clearly did not meet expectations. Why? Because the units for `size=` is **not** pts, rather it is mm. In `geom_text()` those mm units get converted to pts for displaying the text. There are a little over 72 dots (or "pts") per inch, which corresponds to approximately `r formatC(72/25.4,format="f",digits=3)` dots per mm. Thus, `size=13.2` sets the text size at approximately 13.2×`r formatC(72/25.4,format="f",digits=3)`=`r formatC(13.2*72/25.4,format="f",digits=3)` pts. Thus, the very large text above. + +This phenomenon is also evident in the default "size" used in `geom_text()` shown below. Note that 3.88×`r formatC(72/25.4,format="f",digits=3)`=`r formatC(3.88*72/25.4,format="f",digits=3)` or, approximately, the 11 pt base font size. + +```{r} +#| label: geomtext-default-aes +GeomText$default_aes +``` + +The exact conversion factor from mm to pts is stored in the `ggplot2` constant `.pt`. + +```{r} +#| lbel: ggplots-pt-constant +.pt +``` + +Thus, if you want use `size=` in `geom_text()` to display text at a specific pt size then divide the desired pt size by `.pt`. For example, the plot below uses `size=11*1.2/.pt` for the top text and `size=16/.pt` for the bottom text. + +```{r} +#| label: demo-default-label-issue-2 +#| code-fold: true +#| fig.width: 5 +pd + + geom_text(data=data.frame(x=c(0.5,0.5),y=c(0.75,0.25), + label=c("Text at 1.2X Base Font Size", + "Text at 16 pt Font Size")), + mapping=aes(x=x,y=y,label=label),size=c(11*1.2,16)/.pt) +``` + +:::{.callout-tip} +Set the font size in `geom_text()` or `geom_label()` to a desired point size by setting `size=` to the desired point size divided by the `ggplot2` constant in `.pt`. For example, use `size=16/.pt` to use a 16 pt font size. +::: + +The following "chart" gives an idea of how a particular `size=` will be converted to a pt size (on the left) and how a particular pt size corresponds to a `size=` value (on the right). + +```{r} +#| label: show-mm-to-pt-conversion-examples +#| code-fold: true +#| fig.width: 7 +#| fig.height: 6 +dat2 <- data.frame(sz1=3:10, + pts2=c(6,8,10,11,12,14,18,24)) |> + dplyr::mutate(sz2=pts2/.pt, + pts1=sz1*.pt, + x1=rep(0,length(sz1)), + y=seq_along(sz1), + lbl1=glue::glue("size={sz1}; {round(pts1,1)} pt"), + x2=rep(1,length(sz2)), + lbl2=glue::glue("{pts2} pts; size={round(sz2,1)}")) + +ggplot(data=dat2) + + geom_text(mapping=aes(x=x1,y=y,size=sz1,label=lbl1)) + + geom_text(mapping=aes(x=x2,y=y,size=sz2,label=lbl2)) + + geom_vline(xintercept=0.5,color="gray70") + + scale_size_identity() + + scale_x_continuous(expand=expansion(add=0.5)) + + theme_classic() + + theme(axis.title=element_blank(),axis.text=element_blank(), + axis.ticks=element_blank(),axis.line=element_blank(), + legend.position="none") +``` + + +### Theme-Related Font Sizes +Text related to plot titles,^[And subtitles, captions, and tags.] axis titles, axis tick labels, and facet strip labels are all modified using `element_text()` with specific arguments in `theme()`. `element_text()` has `size=` for altering the size of text. However, the units of `size=` in this element function **is** pts and is not mm. The text sizes for the plot title, axis title, and axis tick marks for a `ggplot2` object called `pd2` are modified as shown below. + +```{r} +#| label: demo-theme-text-sizes-1 +#| code-fold: true +#| fig.width: 5 +pd2 <- ggplot() + + geom_point() + + scale_x_continuous(name="16 pt Font", + limits=c(0,1),breaks=c(0,1),expand=expansion(add=0.5), + labels=rep("12 pt Font",2)) + + scale_y_continuous(name="18 pt Font", + limits=c(0,1),breaks=c(0,1),expand=expansion(add=0.25), + labels=rep("11 pt Font",2)) + + ggtitle("24 pt Font") +``` + +```{r} +#| label: demo-theme-text-sizes-2 +#| fig.width: 4.5 +pd2 + + theme(plot.title=element_text(size=24), + axis.title.y=element_text(size=18), + axis.title.x=element_text(size=16), + axis.text.y=element_text(size=11), + axis.text.x=element_text(size=12)) +``` + +:::{.callout-tip} +Set the font size for `ggplot2` plot labels, axis titles, axis tick labels, and facet strip lables using `size=` in `element_text()` set equal to specific arguments related to these items in `theme()`. The values used in `size=` here in pts and, thus, do **not** need to be converted to pts. +::: + +  + +# Line Widths + +```{r} +#| label: demo-linewidths +#| code-fold: true +#| fig.width: 4.5 +dat1 <- data.frame(lw=c(0.1,0.25,0.5,0.75,1,1.5,2,3,4)) |> + dplyr::mutate(x=rep(0,length(lw)), + xend=rep(1,length(lw)), + y=seq_along(lw), + yend=y) + +ggplot(data=dat1) + + geom_segment(mapping=aes(x=x,xend=xend,y=y,yend=yend,linewidth=lw)) + + scale_y_continuous(name="linewidth=",breaks=dat1$y,labels=dat1$lw, + sec.axis=sec_axis(~.*0.75,name="mm", + breaks=dat1$y*0.75, + labels=round(dat1$lw*0.75,2))) + + geom_segment(x=0,y=3,xend=1,yend=3,color="red") + + scale_x_continuous(expand=expansion(mult=0)) + + scale_linewidth_identity() + + theme_classic() + + theme(axis.title.x=element_blank(),axis.text.x=element_blank(), + axis.ticks=element_blank(),axis.line=element_blank(), + axis.title.y=element_text(size=14),axis.text.y=element_text(size=12), + legend.position="none") +``` + + +```{r} +#| label: show-linewidth-defaults +GeomLine$default_aes +GeomSegment$default_aes +GeomPath$default_aes +``` + +  + +# Points + +```{r} +#| label: demo-points-1 +#| code-fold: true +dat3 <- tidyr::expand_grid(Size=(0:3)*2,Stroke=(0:3)*2) + +ggplot(data=dat3,mapping=aes(x=Size,y=Stroke,size=Size,stroke=Stroke)) + + geom_abline(slope=-1,intercept=(1:5)*2,linewidth=(1:5)*2, + colour="gray95",alpha=0.75) + + geom_point(shape=21,fill="red") + + scale_size_identity() + + scale_y_continuous(expand=expansion(mult=0.1)) + + scale_x_continuous(expand=expansion(mult=0.1)) + + theme_bw() + + theme(axis.line=element_blank(), + axis.title=element_text(size=14),axis.text=element_text(size=12), + panel.grid.minor=element_blank(), + panel.border=element_blank()) +``` + + +```{r} +#| label: demo-points-2 +#| code-fold: true +dat4 <- tidyr::expand_grid(Size=0:6,Shape=c(19,21)) + +stroke <- 4 + +ggplot(data=dat4,mapping=aes(x=Shape,y=Size,size=Size,shape=Shape)) + + geom_hline(yintercept=0:6,linewidth=(0:6)+stroke,color="gray90") + + geom_hline(yintercept=0:6,linewidth=(0:6),color="gray95") + + geom_point(fill="red",stroke=stroke) + + scale_size_identity() + + scale_shape_identity() + + scale_y_continuous(expand=expansion(mult=0.1)) + + scale_x_continuous(expand=expansion(mult=0.1),breaks=c(19,21)) + + theme_bw() + + theme(axis.line=element_blank(), + axis.title=element_text(size=14),axis.text=element_text(size=12), + panel.grid.minor=element_blank(), + panel.border=element_blank()) + +``` + +```{r} +#| label: show-points-defaults +GeomPoint$default_aes +``` + +  + +```{r} +#| label: make-preview +#| echo: false +#| fig.show: "hide" +#| results: "hide" +# This is used as a work-around for creating a preview image. See the +# discussion at https://github.com/quarto-dev/quarto-cli/issues/2042 +png("preview.png",width=1000,height=500,units="px", + bg="transparent",res=216) +## PLOT CONSTRUCTION CODE HERE (usually keep aspect.ratio=1) +ggplot() + + geom_point() + + theme_bw() + + theme(aspect.ratio=0.7) +dev.off() +``` \ No newline at end of file diff --git a/blog/posts/_2023-3-28_Size/preview.png b/blog/posts/_2023-3-28_Size/preview.png new file mode 100644 index 0000000000000000000000000000000000000000..0fe139eec51866ccf1aad7408657833fd7b3b0dc GIT binary patch literal 3127 zcmeAS@N?(olHy`uVBq!ia0y~yV1B{C!1#rO87MOI+jn^&#S`EY;`;aBUt?oqAo>6Q z|2pQ5UqEq|k|4j}|Nj~O|Kr)s4dincctjR6FesXXFr#tA{3-?p?t`8#jv*Cu-d?-d zDQh6&e9(8>|9O`i?2k-t{+h6iNxAsJzdx~GxZ_`!+Pd4XmoND8YxRTT^{*|3tnPf> zHBWir;aIA3eoeaY|A5BAdcPMnybJ5!3H)kL7x@$Jl&?~Jh+(1mB+JBx3(_a&7&yG> zP4SaZ_~K@y&LdEzJX4sBWADT>oXjovJf5{Mjw&AwnbAZrnmtBKg3&T^v^p5AC`a1_ zqpc+xHw-P#aL#V|XSwjRY0JNz{O2_!KG3LvjMDc0#r}PBwd&GEn!r{)1B0ilpUXO@ GgeCwwhSB~2 literal 0 HcmV?d00001 diff --git a/docs/blog/index.html b/docs/blog/index.html index fe918b0..6901fa0 100644 --- a/docs/blog/index.html +++ b/docs/blog/index.html @@ -196,7 +196,7 @@

R for Fisheries Analyses and Tasks

+
Categories
All (35)
Age (5)
Age Comparisons (4)
Back-calculation (1)
Biomass (1)
CPE (1)
Condition (1)
Data Wrangling (10)
FSA (7)
Growth (6)
Length Frequency (2)
Logistic Regression (1)
Maturity (1)
PSD (2)
Relative Weight (1)
Size (4)
Size Structure (2)
Stock-Recruitment (1)
Weight-Length (1)
annotations (1)
area chart (1)
axes (4)
bar chart (5)
color (2)
confidence intervals (3)
cumulative distribution (1)
dates (3)
emmeans (3)
facets (7)
functions (1)
ggplot2 (26)
histogram (1)
labels (1)
legend (1)
png (1)
reference lines (2)
@@ -266,40 +266,7 @@
- -
+ -
+ -
+ -
+ -
+ -
+ -
+ -
+ -
+ -
+ -
+ -
+ -
+ -
+ -
+ -
+ -
+
-
+ -
+ -
+ -
+ -
+ -
+ -
+ -
+ -
+ -
+ -
+ -
+ -
+ -
+ -
+ -
+ -
+

diff --git a/docs/blog/posts/2015-9-5_Age_Comparison_Results/index.html b/docs/blog/posts/2015-9-5_Age_Comparison_Results/index.html index ec7b631..ac5f62e 100644 --- a/docs/blog/posts/2015-9-5_Age_Comparison_Results/index.html +++ b/docs/blog/posts/2015-9-5_Age_Comparison_Results/index.html @@ -145,6 +145,7 @@ + @@ -167,6 +168,7 @@ + diff --git a/docs/blog/posts/2015-9-6_Cumulative_Sums/index.html b/docs/blog/posts/2015-9-6_Cumulative_Sums/index.html index 529bd10..3c0f2cd 100644 --- a/docs/blog/posts/2015-9-6_Cumulative_Sums/index.html +++ b/docs/blog/posts/2015-9-6_Cumulative_Sums/index.html @@ -145,6 +145,7 @@ + @@ -167,6 +168,7 @@ + diff --git a/docs/blog/posts/2016-11-11_Pauly-VBModel/index.html b/docs/blog/posts/2016-11-11_Pauly-VBModel/index.html index 6f99e82..b50c01b 100644 --- a/docs/blog/posts/2016-11-11_Pauly-VBModel/index.html +++ b/docs/blog/posts/2016-11-11_Pauly-VBModel/index.html @@ -102,6 +102,7 @@ + @@ -124,6 +125,7 @@ + diff --git a/docs/blog/posts/2016-12-9_PSD_SE/index.html b/docs/blog/posts/2016-12-9_PSD_SE/index.html index 8cbdfac..88d58ab 100644 --- a/docs/blog/posts/2016-12-9_PSD_SE/index.html +++ b/docs/blog/posts/2016-12-9_PSD_SE/index.html @@ -165,6 +165,7 @@ + @@ -187,6 +188,7 @@ + diff --git a/docs/blog/posts/2017-11-7_BackCalculationPlot/index.html b/docs/blog/posts/2017-11-7_BackCalculationPlot/index.html index c37b944..a457ad3 100644 --- a/docs/blog/posts/2017-11-7_BackCalculationPlot/index.html +++ b/docs/blog/posts/2017-11-7_BackCalculationPlot/index.html @@ -164,6 +164,7 @@ + @@ -186,6 +187,7 @@ + diff --git a/docs/blog/posts/2017-12-12_StockRecruit_Graph_Questions/index.html b/docs/blog/posts/2017-12-12_StockRecruit_Graph_Questions/index.html index a60f930..2cead1c 100644 --- a/docs/blog/posts/2017-12-12_StockRecruit_Graph_Questions/index.html +++ b/docs/blog/posts/2017-12-12_StockRecruit_Graph_Questions/index.html @@ -164,6 +164,7 @@ + @@ -186,6 +187,7 @@ + diff --git a/docs/blog/posts/2017-4-20_BlandAltman/index.html b/docs/blog/posts/2017-4-20_BlandAltman/index.html index 13fe1a3..c2c3b9b 100644 --- a/docs/blog/posts/2017-4-20_BlandAltman/index.html +++ b/docs/blog/posts/2017-4-20_BlandAltman/index.html @@ -164,6 +164,7 @@ + @@ -186,6 +187,7 @@ + diff --git a/docs/blog/posts/2017-7-28_LF_Ridgeline_Plot/index.html b/docs/blog/posts/2017-7-28_LF_Ridgeline_Plot/index.html index 7761536..6ff8514 100644 --- a/docs/blog/posts/2017-7-28_LF_Ridgeline_Plot/index.html +++ b/docs/blog/posts/2017-7-28_LF_Ridgeline_Plot/index.html @@ -164,6 +164,7 @@ + @@ -186,6 +187,7 @@ + diff --git a/docs/blog/posts/2017-8-9_Mean_Weights/index.html b/docs/blog/posts/2017-8-9_Mean_Weights/index.html index c7eedcd..f122f6b 100644 --- a/docs/blog/posts/2017-8-9_Mean_Weights/index.html +++ b/docs/blog/posts/2017-8-9_Mean_Weights/index.html @@ -165,6 +165,7 @@ + @@ -187,6 +188,7 @@ + diff --git a/docs/blog/posts/2018-3-30_Collapsing_Categories_or_Values/index.html b/docs/blog/posts/2018-3-30_Collapsing_Categories_or_Values/index.html index 61504b4..3bceb72 100644 --- a/docs/blog/posts/2018-3-30_Collapsing_Categories_or_Values/index.html +++ b/docs/blog/posts/2018-3-30_Collapsing_Categories_or_Values/index.html @@ -145,6 +145,7 @@ + @@ -167,6 +168,7 @@ + diff --git a/docs/blog/posts/2019-12-28_Length_Frequency_Histograms/index.html b/docs/blog/posts/2019-12-28_Length_Frequency_Histograms/index.html index db8f949..424a455 100644 --- a/docs/blog/posts/2019-12-28_Length_Frequency_Histograms/index.html +++ b/docs/blog/posts/2019-12-28_Length_Frequency_Histograms/index.html @@ -145,6 +145,7 @@ + @@ -167,6 +168,7 @@ + diff --git a/docs/blog/posts/2019-12-31_vonB_plots_1/index.html b/docs/blog/posts/2019-12-31_vonB_plots_1/index.html index 59e4c97..7eae241 100644 --- a/docs/blog/posts/2019-12-31_vonB_plots_1/index.html +++ b/docs/blog/posts/2019-12-31_vonB_plots_1/index.html @@ -165,6 +165,7 @@ + @@ -187,6 +188,7 @@ + diff --git a/docs/blog/posts/2020-1-2_vonB_plots_2/index.html b/docs/blog/posts/2020-1-2_vonB_plots_2/index.html index 273758a..8c2e00b 100644 --- a/docs/blog/posts/2020-1-2_vonB_plots_2/index.html +++ b/docs/blog/posts/2020-1-2_vonB_plots_2/index.html @@ -165,6 +165,7 @@ + @@ -187,6 +188,7 @@ + diff --git a/docs/blog/posts/2021-3-15-AgeBiasPlots/index.html b/docs/blog/posts/2021-3-15-AgeBiasPlots/index.html index bf7b849..05cef2f 100644 --- a/docs/blog/posts/2021-3-15-AgeBiasPlots/index.html +++ b/docs/blog/posts/2021-3-15-AgeBiasPlots/index.html @@ -145,6 +145,7 @@ + @@ -167,6 +168,7 @@ + diff --git a/docs/blog/posts/2021-5-11_compSlopes-replacement/index.html b/docs/blog/posts/2021-5-11_compSlopes-replacement/index.html index 7e004f9..91d24b5 100644 --- a/docs/blog/posts/2021-5-11_compSlopes-replacement/index.html +++ b/docs/blog/posts/2021-5-11_compSlopes-replacement/index.html @@ -165,6 +165,7 @@ + @@ -187,6 +188,7 @@ + diff --git a/docs/blog/posts/2021-5-12_compIntercepts-replacement/index.html b/docs/blog/posts/2021-5-12_compIntercepts-replacement/index.html index 5521a71..6b459d9 100644 --- a/docs/blog/posts/2021-5-12_compIntercepts-replacement/index.html +++ b/docs/blog/posts/2021-5-12_compIntercepts-replacement/index.html @@ -165,6 +165,7 @@ + @@ -187,6 +188,7 @@ + diff --git a/docs/blog/posts/2021-5-25_fitPlot-replacement/index.html b/docs/blog/posts/2021-5-25_fitPlot-replacement/index.html index dde4839..0539565 100644 --- a/docs/blog/posts/2021-5-25_fitPlot-replacement/index.html +++ b/docs/blog/posts/2021-5-25_fitPlot-replacement/index.html @@ -146,6 +146,7 @@ + @@ -168,6 +169,7 @@ + diff --git a/docs/blog/posts/2021-5-26_filterD-replacement/index.html b/docs/blog/posts/2021-5-26_filterD-replacement/index.html index c0e3861..627e6c9 100644 --- a/docs/blog/posts/2021-5-26_filterD-replacement/index.html +++ b/docs/blog/posts/2021-5-26_filterD-replacement/index.html @@ -146,6 +146,7 @@ + @@ -168,6 +169,7 @@ + diff --git a/docs/blog/posts/2021-6-1_residPlot-replacement/index.html b/docs/blog/posts/2021-6-1_residPlot-replacement/index.html index 23c2ac0..73529ed 100644 --- a/docs/blog/posts/2021-6-1_residPlot-replacement/index.html +++ b/docs/blog/posts/2021-6-1_residPlot-replacement/index.html @@ -145,6 +145,7 @@ + @@ -167,6 +168,7 @@ + diff --git a/docs/blog/posts/2022-12-22_AFS_Style_Figures/index.html b/docs/blog/posts/2022-12-22_AFS_Style_Figures/index.html index 16ede36..e75aa0a 100644 --- a/docs/blog/posts/2022-12-22_AFS_Style_Figures/index.html +++ b/docs/blog/posts/2022-12-22_AFS_Style_Figures/index.html @@ -164,6 +164,7 @@ + @@ -186,6 +187,7 @@ + diff --git a/docs/blog/posts/2023-2-15_Vaisviletal2022_ROC/index.html b/docs/blog/posts/2023-2-15_Vaisviletal2022_ROC/index.html index fcaa75b..5aa92db 100644 --- a/docs/blog/posts/2023-2-15_Vaisviletal2022_ROC/index.html +++ b/docs/blog/posts/2023-2-15_Vaisviletal2022_ROC/index.html @@ -164,6 +164,7 @@ + @@ -186,6 +187,7 @@ + diff --git a/docs/blog/posts/2023-2-16_Ulaskietal_GrowthMortFig/index.html b/docs/blog/posts/2023-2-16_Ulaskietal_GrowthMortFig/index.html index 0e695fe..dba5267 100644 --- a/docs/blog/posts/2023-2-16_Ulaskietal_GrowthMortFig/index.html +++ b/docs/blog/posts/2023-2-16_Ulaskietal_GrowthMortFig/index.html @@ -165,6 +165,7 @@ + @@ -187,6 +188,7 @@ + diff --git a/docs/blog/posts/2023-3-10-Text_Annotation_Position/index.html b/docs/blog/posts/2023-3-10-Text_Annotation_Position/index.html index 0140908..852482a 100644 --- a/docs/blog/posts/2023-3-10-Text_Annotation_Position/index.html +++ b/docs/blog/posts/2023-3-10-Text_Annotation_Position/index.html @@ -145,6 +145,7 @@ + @@ -167,6 +168,7 @@ + diff --git a/docs/blog/posts/2023-3-15-Axis_Magic/index.html b/docs/blog/posts/2023-3-15-Axis_Magic/index.html index 4a1fa24..785fe83 100644 --- a/docs/blog/posts/2023-3-15-Axis_Magic/index.html +++ b/docs/blog/posts/2023-3-15-Axis_Magic/index.html @@ -145,6 +145,7 @@ + diff --git a/docs/blog/posts/2023-3-18-Rooketal2022_CiscoHarvest/index.html b/docs/blog/posts/2023-3-18-Rooketal2022_CiscoHarvest/index.html index 6dfcdf7..14af67d 100644 --- a/docs/blog/posts/2023-3-18-Rooketal2022_CiscoHarvest/index.html +++ b/docs/blog/posts/2023-3-18-Rooketal2022_CiscoHarvest/index.html @@ -164,6 +164,7 @@ + diff --git a/docs/blog/posts/2023-3-20-Rooketal2022_Fig4/index.html b/docs/blog/posts/2023-3-20-Rooketal2022_Fig4/index.html index 1d38979..6810486 100644 --- a/docs/blog/posts/2023-3-20-Rooketal2022_Fig4/index.html +++ b/docs/blog/posts/2023-3-20-Rooketal2022_Fig4/index.html @@ -164,6 +164,7 @@ + @@ -186,6 +187,7 @@ + diff --git a/docs/blog/posts/2023-3-22_McCarricketal2022_Fig2/index.html b/docs/blog/posts/2023-3-22_McCarricketal2022_Fig2/index.html index ab60217..a382181 100644 --- a/docs/blog/posts/2023-3-22_McCarricketal2022_Fig2/index.html +++ b/docs/blog/posts/2023-3-22_McCarricketal2022_Fig2/index.html @@ -164,6 +164,7 @@ + diff --git a/docs/blog/posts/2023-3-25_McCarricketal2022_Fig3/index.html b/docs/blog/posts/2023-3-25_McCarricketal2022_Fig3/index.html index cd1726b..c5aaba4 100644 --- a/docs/blog/posts/2023-3-25_McCarricketal2022_Fig3/index.html +++ b/docs/blog/posts/2023-3-25_McCarricketal2022_Fig3/index.html @@ -164,6 +164,7 @@ + diff --git a/docs/blog/posts/2023-3-6_Landryetal2022_LogRegress/index.html b/docs/blog/posts/2023-3-6_Landryetal2022_LogRegress/index.html index 0a9a068..5d1340a 100644 --- a/docs/blog/posts/2023-3-6_Landryetal2022_LogRegress/index.html +++ b/docs/blog/posts/2023-3-6_Landryetal2022_LogRegress/index.html @@ -164,6 +164,7 @@ + @@ -186,6 +187,7 @@ + diff --git a/docs/blog/posts/2023-3-8_MackCheatwood2022_CumSums/index.html b/docs/blog/posts/2023-3-8_MackCheatwood2022_CumSums/index.html index 8281a29..d5abc0f 100644 --- a/docs/blog/posts/2023-3-8_MackCheatwood2022_CumSums/index.html +++ b/docs/blog/posts/2023-3-8_MackCheatwood2022_CumSums/index.html @@ -164,6 +164,7 @@ + @@ -186,6 +187,7 @@ + diff --git a/docs/blog/posts/2023-3-9-Clemens2022/index.html b/docs/blog/posts/2023-3-9-Clemens2022/index.html index 74331fa..0f265bf 100644 --- a/docs/blog/posts/2023-3-9-Clemens2022/index.html +++ b/docs/blog/posts/2023-3-9-Clemens2022/index.html @@ -164,6 +164,7 @@ + @@ -186,6 +187,7 @@ + diff --git a/docs/blog/posts/2023_2_13_Quistetal2022_AgeData/index.html b/docs/blog/posts/2023_2_13_Quistetal2022_AgeData/index.html index 4610168..0acaa5f 100644 --- a/docs/blog/posts/2023_2_13_Quistetal2022_AgeData/index.html +++ b/docs/blog/posts/2023_2_13_Quistetal2022_AgeData/index.html @@ -164,6 +164,7 @@ + @@ -186,6 +187,7 @@ + diff --git a/docs/blog/posts/2023_2_14_Quistetal2022_BCData/index.html b/docs/blog/posts/2023_2_14_Quistetal2022_BCData/index.html index e60a226..e44ea99 100644 --- a/docs/blog/posts/2023_2_14_Quistetal2022_BCData/index.html +++ b/docs/blog/posts/2023_2_14_Quistetal2022_BCData/index.html @@ -164,6 +164,7 @@ + @@ -186,6 +187,7 @@ + diff --git a/docs/listings.json b/docs/listings.json index faf0b7f..ad5a484 100644 --- a/docs/listings.json +++ b/docs/listings.json @@ -3,7 +3,6 @@ "listing": "/blog/index.html", "items": [ "/blog/posts/2023-3-27_McCarricketal2022_Fig5/index.html", - "/blog/posts/2023-3-28_Size/index.html", "/blog/posts/2023-3-26_McCarricketal2022_Fig4/index.html", "/blog/posts/2023-3-25_McCarricketal2022_Fig3/index.html", "/blog/posts/2023-3-22_McCarricketal2022_Fig2/index.html", diff --git a/docs/search.json b/docs/search.json index 381388a..2068d45 100644 --- a/docs/search.json +++ b/docs/search.json @@ -4,7 +4,7 @@ "href": "blog/index.html", "title": "R for Fisheries Analyses and Tasks", "section": "", - "text": "Order By\n Default\n \n Published - Oldest\n \n \n Published - Newest\n \n \n Modified - Oldest\n \n \n Modified - Newest\n \n \n Author\n \n \n \n\n\n\n\n\n\n\n\n\n\nMcCarrick et al. (2022) Age Composition Plot\n\n\n10 min\n\n\nUsing ggplot2 to recreate the age composition by year figure in McCarrick et al. (2022).\n\n\n\nDerek H. Ogle\n\n\nMar 27, 2023\n\n\n\n\n\nMar 25, 2023\n\n\n\n\n\n\n\n\n\n\n\n\n\nMcCarrick et al. (2022) Age Composition Plot\n\n\n10 min\n\n\nUsing ggplot2 to recreate the age composition by year figure in McCarrick et al. (2022).\n\n\n\nDerek H. Ogle\n\n\nMar 27, 2023\n\n\n\n\n\nMar 25, 2023\n\n\n\n\n\n\n\n\n\n\n\n\n\nMcCarrick et al. (2022) Wr Plot\n\n\n7 min\n\n\nUsing ggplot2 to recreate the relative weight (wr) by year figure in McCarrick et al. (2022).\n\n\n\nDerek H. Ogle\n\n\nMar 26, 2023\n\n\n\n\n\nMar 24, 2023\n\n\n\n\n\n\n\n\n\n\n\n\n\nMcCarrick et al. (2022) PSD Plot\n\n\n11 min\n\n\nUsing ggplot2 to recreate the PSD by year figure in McCarrick et al. (2022). Extended it to include CIs.\n\n\n\nDerek H. Ogle\n\n\nMar 25, 2023\n\n\n\n\n\nMar 23, 2023\n\n\n\n\n\n\n\n\n\n\n\n\n\nMcCarrick et al. (2022) CPE Plot\n\n\n14 min\n\n\nUsing ggplot2 to recreate the cpe by species, year, and length category figure in McCarrick et al. (2022).\n\n\n\nDerek H. Ogle\n\n\nMar 22, 2023\n\n\n\n\n\nMar 21, 2023\n\n\n\n\n\n\n\n\n\n\n\n\n\nRook et al. (2022) Estimated Cisco Stocking Densities\n\n\n13 min\n\n\nUsing ggplot2 to recreate the figure of estimated Cisco stocking densities in Rook et al. (2022).\n\n\n\nDerek H. Ogle\n\n\nMar 20, 2023\n\n\n\n\n\nMar 19, 2023\n\n\n\n\n\n\n\n\n\n\n\n\n\nRook et al. (2022) Cisco Harvest Figure\n\n\n13 min\n\n\nUsing ggplot2 to recreate the figure of Great Lakes Coregonid harvest in Rook et al. (2022).\n\n\n\nDerek H. Ogle\n\n\nMar 17, 2023\n\n\n\n\n\nMar 19, 2023\n\n\n\n\n\n\n\n\n\n\n\n\n\nAxis Magic\n\n\n24 min\n\n\nSome tricks with respect to axes in ggplot2.\n\n\n\nDerek H. Ogle\n\n\nMar 15, 2023\n\n\n\n\n\nMar 17, 2023\n\n\n\n\n\n\n\n\n\n\n\n\n\nUsing vjust= and hjust=\n\n\n10 min\n\n\nExplaining the use of vjust= and hjust= to position objects in ggplots.\n\n\n\nDerek H. Ogle\n\n\nMar 10, 2023\n\n\n\n\n\nMar 19, 2023\n\n\n\n\n\n\n\n\n\n\n\n\n\nClemens (2022) Temperature Figure\n\n\n9 min\n\n\nUsing ggplot2 to recreate the temperature figure in Clemens (2022).\n\n\n\nDerek H. Ogle\n\n\nMar 9, 2023\n\n\n\n\n\nMar 19, 2023\n\n\n\n\n\n\n\n\n\n\n\n\n\nMack and Cheatwood (2022) Cumulative Sums Figure\n\n\n7 min\n\n\nUsing ggplot2 to recreate the cumulative sums figures in Mack and Cheatwood (2022).\n\n\n\nDerek H. Ogle\n\n\nMar 8, 2023\n\n\n\n\n\nMar 19, 2023\n\n\n\n\n\n\n\n\n\n\n\n\n\nLandry et al. (2022) Logistic Regression Figures\n\n\n14 min\n\n\nUsing ggplot2 to recreate the logistic regression figures in Landry et al. (2022).\n\n\n\nDerek H. Ogle\n\n\nMar 6, 2023\n\n\n\n\n\nMar 6, 2023\n\n\n\n\n\n\n\n\n\n\n\n\n\nUlaski et al. (2022) Growth-Maturity Figure\n\n\n16 min\n\n\nUsing ggplot2 to recreate the growth and maturity figure in Ulaski et al. (2022).\n\n\n\nDerek H. Ogle\n\n\nFeb 16, 2023\n\n\n\n\n\nMar 19, 2023\n\n\n\n\n\n\n\n\n\n\n\n\n\nVaisvil et al. (2022) Hatching Date Figure\n\n\n9 min\n\n\nUsing ggplot2 to recreate the bass hatching date figure in Vaisvil et al. (2022).\n\n\n\nDerek H. Ogle\n\n\nFeb 15, 2023\n\n\n\n\n\nMar 19, 2023\n\n\n\n\n\n\n\n\n\n\n\n\n\nQuist et al. (2022) Back-Calculation Figure\n\n\n6 min\n\n\nUsing ggplot2 to recreate the back-calculated length-at-age figure in Quist et al. (2022).\n\n\n\nDerek H. Ogle\n\n\nFeb 14, 2023\n\n\n\n\n\nFeb 14, 2023\n\n\n\n\n\n\n\n\n\n\n\n\n\nQuist et al. (2022) Age Comparison Figures\n\n\n13 min\n\n\nUsing ggplot2 to recreate the age comparison figures in Quist et al. (2022).\n\n\n\nDerek H. Ogle\n\n\nFeb 13, 2023\n\n\n\n\n\nFeb 13, 2023\n\n\n\n\n\n\n\n\n\n\n\n\n\nAFS Style in ggplot2 Figures\n\n\n16 min\n\n\nSuggestions for the Glassic et al. (2019) process for modifying ggplot2 graphs to match the AFS Style Guide.\n\n\n\nDerek H. Ogle\n\n\nDec 22, 2022\n\n\n\n\n\nFeb 13, 2023\n\n\n\n\n\n\n\n\n\n\n\n\n\nReplace residPlot() with ggplot\n\n\n8 min\n\n\nUsing ggplot() as an alternative to residPlot() which was removed from FSA.\n\n\n\nDerek H. Ogle\n\n\nJun 1, 2021\n\n\n\n\n\nDec 14, 2022\n\n\n\n\n\n\n\n\n\n\n\n\n\nReplace filterD()\n\n\n1 min\n\n\nAn alternative to filterD() which was removed from FSA.\n\n\n\nDerek H. Ogle\n\n\nMay 26, 2021\n\n\n\n\n\nDec 19, 2022\n\n\n\n\n\n\n\n\n\n\n\n\n\nReplace fitPlot() with ggplot\n\n\n12 min\n\n\nUsing ggplot() as an alternative to fitPlot() which was removed from FSA.\n\n\n\nDerek H. Ogle\n\n\nMay 25, 2021\n\n\n\n\n\nDec 27, 2022\n\n\n\n\n\n\n\n\n\n\n\n\n\nReplace compIntercepts() with emmeans()\n\n\n5 min\n\n\nUsing emmeans() from emmeans as an alternative to compIntercepts() which was removed from FSA.\n\n\n\nDerek H. Ogle\n\n\nMay 12, 2021\n\n\n\n\n\nJan 1, 2023\n\n\n\n\n\n\n\n\n\n\n\n\n\nReplace compSlopes() with emtrends()\n\n\n5 min\n\n\nUsing emtrends() from emmeans as an alternative to compSlopes() which was removed from FSA.\n\n\n\nDerek H. Ogle\n\n\nMay 11, 2021\n\n\n\n\n\nJan 1, 2023\n\n\n\n\n\n\n\n\n\n\n\n\n\nAge Bias Plots in ggplot2\n\n\n8 min\n\n\nFlexibly construct age bias and age difference plots using ggplot2\n\n\n\nMichael Lant\n\n\nMar 15, 2021\n\n\n\n\n\nDec 7, 2022\n\n\n\n\n\n\n\n\n\n\n\n\n\nvon Bertalanffy Growth Plots I\n\n\n10 min\n\n\nHow to plot one von Bertalanffy growth model with data.\n\n\n\nDerek H. Ogle\n\n\nDec 31, 2019\n\n\n\n\n\nMar 17, 2023\n\n\n\n\n\n\n\n\n\n\n\n\n\nLength Frequency Histograms in ggplot2\n\n\n5 min\n\n\nFlexibly construct length frequency histograms using ggplot2\n\n\n\nDerek H. Ogle\n\n\nDec 28, 2019\n\n\n\n\n\nMar 19, 2023\n\n\n\n\n\n\n\n\n\n\n\n\n\nvon Bertalanffy Growth Plots II\n\n\n19 min\n\n\nHow to plot multiple von Bertalanffy growth models with data.\n\n\n\nDerek H. Ogle\n\n\nJan 2, 2019\n\n\n\n\n\nFeb 13, 2023\n\n\n\n\n\n\n\n\n\n\n\n\n\nCollapsing Categories or Values\n\n\n7 min\n\n\nHow to collapse categories or values into other categories\n\n\n\nDerek H. Ogle\n\n\nMar 30, 2018\n\n\n\n\n\nDec 19, 2022\n\n\n\n\n\n\n\n\n\n\n\n\n\nStock-Recruitment Graphing Questions\n\n\n7 min\n\n\nA reply to a user’s questions with respect to stock-recruitment function graphics.\n\n\n\nDerek H. Ogle\n\n\nDec 12, 2017\n\n\n\n\n\nDec 18, 2022\n\n\n\n\n\n\n\n\n\n\n\n\n\nPlots of Back-Calculated Lengths-At-Age\n\n\n8 min\n\n\nInitial thoughts on displaying back-calculated lengths-at-age.\n\n\n\nDerek H. Ogle\n\n\nNov 7, 2017\n\n\n\n\n\nFeb 13, 2023\n\n\n\n\n\n\n\n\n\n\n\n\n\nMean Weights at Ages From Lengths\n\n\n15 min\n\n\nDemonstrates concerns and corrections with estimating mean weight from observed lengths and a weight-length relationship.\n\n\n\nDerek H. Ogle\n\n\nAug 9, 2017\n\n\n\n\n\nFeb 13, 2023\n\n\n\n\n\n\n\n\n\n\n\n\n\nRidgeline Length Frequency Plots\n\n\n2 min\n\n\nHow to visualize multiple length frequencies as ridgline plots.\n\n\n\nDerek H. Ogle\n\n\nJul 28, 2017\n\n\n\n\n\nFeb 13, 2023\n\n\n\n\n\n\n\n\n\n\n\n\n\nBland-Altman Plot for Age Comparisons?\n\n\n10 min\n\n\nExplore the use of Bland-Altman plots for comparing paired age estimates.\n\n\n\nDerek H. Ogle\n\n\nApr 20, 2017\n\n\n\n\n\nFeb 13, 2023\n\n\n\n\n\n\n\n\n\n\n\n\n\nComputing SE for PSD indices\n\n\n1 min\n\n\nDemonstrate how to compute SE for PSD indices.\n\n\n\nDerek H. Ogle\n\n\nDec 9, 2016\n\n\n\n\n\nDec 19, 2022\n\n\n\n\n\n\n\n\n\n\n\n\n\nPauly et al. (1992) Seasonal Cessation Growth Model\n\n\n2 min\n\n\nAnnouncement of an algorithm to fit the Pauly et al. (1992) seasonal cessation growth model\n\n\n\nDerek H. Ogle\n\n\nNov 11, 2016\n\n\n\n\n\nFeb 13, 2023\n\n\n\n\n\n\n\n\n\n\n\n\n\nTwo New Cumulative Sum Functions\n\n\n1 min\n\n\nIntroducing the missing current and reverse cumulative sum functions.\n\n\n\nDerek H. Ogle\n\n\nSep 6, 2015\n\n\n\n\n\nDec 19, 2022\n\n\n\n\n\n\n\n\n\n\n\n\n\nAge Comparison Results for Individual Fish\n\n\n1 min\n\n\nDemonstrates how to extract age comparison results for individual fish from the object returned by ageComparisons().\n\n\n\nDerek H. Ogle\n\n\nSep 5, 2015\n\n\n\n\n\nDec 7, 2022\n\n\n\n\n\n\n\nNo matching items" + "text": "Order By\n Default\n \n Published - Oldest\n \n \n Published - Newest\n \n \n Modified - Oldest\n \n \n Modified - Newest\n \n \n Author\n \n \n \n\n\n\n\n\n\n\n\n\n\nMcCarrick et al. (2022) Age Composition Plot\n\n\n10 min\n\n\nUsing ggplot2 to recreate the age composition by year figure in McCarrick et al. (2022).\n\n\n\nDerek H. Ogle\n\n\nMar 27, 2023\n\n\n\n\n\nMar 25, 2023\n\n\n\n\n\n\n\n\n\n\n\n\n\nMcCarrick et al. (2022) Wr Plot\n\n\n7 min\n\n\nUsing ggplot2 to recreate the relative weight (wr) by year figure in McCarrick et al. (2022).\n\n\n\nDerek H. Ogle\n\n\nMar 26, 2023\n\n\n\n\n\nMar 24, 2023\n\n\n\n\n\n\n\n\n\n\n\n\n\nMcCarrick et al. (2022) PSD Plot\n\n\n11 min\n\n\nUsing ggplot2 to recreate the PSD by year figure in McCarrick et al. (2022). Extended it to include CIs.\n\n\n\nDerek H. Ogle\n\n\nMar 25, 2023\n\n\n\n\n\nMar 23, 2023\n\n\n\n\n\n\n\n\n\n\n\n\n\nMcCarrick et al. (2022) CPE Plot\n\n\n14 min\n\n\nUsing ggplot2 to recreate the cpe by species, year, and length category figure in McCarrick et al. (2022).\n\n\n\nDerek H. Ogle\n\n\nMar 22, 2023\n\n\n\n\n\nMar 21, 2023\n\n\n\n\n\n\n\n\n\n\n\n\n\nRook et al. (2022) Estimated Cisco Stocking Densities\n\n\n13 min\n\n\nUsing ggplot2 to recreate the figure of estimated Cisco stocking densities in Rook et al. (2022).\n\n\n\nDerek H. Ogle\n\n\nMar 20, 2023\n\n\n\n\n\nMar 19, 2023\n\n\n\n\n\n\n\n\n\n\n\n\n\nRook et al. (2022) Cisco Harvest Figure\n\n\n13 min\n\n\nUsing ggplot2 to recreate the figure of Great Lakes Coregonid harvest in Rook et al. (2022).\n\n\n\nDerek H. Ogle\n\n\nMar 17, 2023\n\n\n\n\n\nMar 19, 2023\n\n\n\n\n\n\n\n\n\n\n\n\n\nAxis Magic\n\n\n24 min\n\n\nSome tricks with respect to axes in ggplot2.\n\n\n\nDerek H. Ogle\n\n\nMar 15, 2023\n\n\n\n\n\nMar 17, 2023\n\n\n\n\n\n\n\n\n\n\n\n\n\nUsing vjust= and hjust=\n\n\n10 min\n\n\nExplaining the use of vjust= and hjust= to position objects in ggplots.\n\n\n\nDerek H. Ogle\n\n\nMar 10, 2023\n\n\n\n\n\nMar 19, 2023\n\n\n\n\n\n\n\n\n\n\n\n\n\nClemens (2022) Temperature Figure\n\n\n9 min\n\n\nUsing ggplot2 to recreate the temperature figure in Clemens (2022).\n\n\n\nDerek H. Ogle\n\n\nMar 9, 2023\n\n\n\n\n\nMar 19, 2023\n\n\n\n\n\n\n\n\n\n\n\n\n\nMack and Cheatwood (2022) Cumulative Sums Figure\n\n\n7 min\n\n\nUsing ggplot2 to recreate the cumulative sums figures in Mack and Cheatwood (2022).\n\n\n\nDerek H. Ogle\n\n\nMar 8, 2023\n\n\n\n\n\nMar 19, 2023\n\n\n\n\n\n\n\n\n\n\n\n\n\nLandry et al. (2022) Logistic Regression Figures\n\n\n14 min\n\n\nUsing ggplot2 to recreate the logistic regression figures in Landry et al. (2022).\n\n\n\nDerek H. Ogle\n\n\nMar 6, 2023\n\n\n\n\n\nMar 6, 2023\n\n\n\n\n\n\n\n\n\n\n\n\n\nUlaski et al. (2022) Growth-Maturity Figure\n\n\n16 min\n\n\nUsing ggplot2 to recreate the growth and maturity figure in Ulaski et al. (2022).\n\n\n\nDerek H. Ogle\n\n\nFeb 16, 2023\n\n\n\n\n\nMar 19, 2023\n\n\n\n\n\n\n\n\n\n\n\n\n\nVaisvil et al. (2022) Hatching Date Figure\n\n\n9 min\n\n\nUsing ggplot2 to recreate the bass hatching date figure in Vaisvil et al. (2022).\n\n\n\nDerek H. Ogle\n\n\nFeb 15, 2023\n\n\n\n\n\nMar 19, 2023\n\n\n\n\n\n\n\n\n\n\n\n\n\nQuist et al. (2022) Back-Calculation Figure\n\n\n6 min\n\n\nUsing ggplot2 to recreate the back-calculated length-at-age figure in Quist et al. (2022).\n\n\n\nDerek H. Ogle\n\n\nFeb 14, 2023\n\n\n\n\n\nFeb 14, 2023\n\n\n\n\n\n\n\n\n\n\n\n\n\nQuist et al. (2022) Age Comparison Figures\n\n\n13 min\n\n\nUsing ggplot2 to recreate the age comparison figures in Quist et al. (2022).\n\n\n\nDerek H. Ogle\n\n\nFeb 13, 2023\n\n\n\n\n\nFeb 13, 2023\n\n\n\n\n\n\n\n\n\n\n\n\n\nAFS Style in ggplot2 Figures\n\n\n16 min\n\n\nSuggestions for the Glassic et al. (2019) process for modifying ggplot2 graphs to match the AFS Style Guide.\n\n\n\nDerek H. Ogle\n\n\nDec 22, 2022\n\n\n\n\n\nFeb 13, 2023\n\n\n\n\n\n\n\n\n\n\n\n\n\nReplace residPlot() with ggplot\n\n\n8 min\n\n\nUsing ggplot() as an alternative to residPlot() which was removed from FSA.\n\n\n\nDerek H. Ogle\n\n\nJun 1, 2021\n\n\n\n\n\nDec 14, 2022\n\n\n\n\n\n\n\n\n\n\n\n\n\nReplace filterD()\n\n\n1 min\n\n\nAn alternative to filterD() which was removed from FSA.\n\n\n\nDerek H. Ogle\n\n\nMay 26, 2021\n\n\n\n\n\nDec 19, 2022\n\n\n\n\n\n\n\n\n\n\n\n\n\nReplace fitPlot() with ggplot\n\n\n12 min\n\n\nUsing ggplot() as an alternative to fitPlot() which was removed from FSA.\n\n\n\nDerek H. Ogle\n\n\nMay 25, 2021\n\n\n\n\n\nDec 27, 2022\n\n\n\n\n\n\n\n\n\n\n\n\n\nReplace compIntercepts() with emmeans()\n\n\n5 min\n\n\nUsing emmeans() from emmeans as an alternative to compIntercepts() which was removed from FSA.\n\n\n\nDerek H. Ogle\n\n\nMay 12, 2021\n\n\n\n\n\nJan 1, 2023\n\n\n\n\n\n\n\n\n\n\n\n\n\nReplace compSlopes() with emtrends()\n\n\n5 min\n\n\nUsing emtrends() from emmeans as an alternative to compSlopes() which was removed from FSA.\n\n\n\nDerek H. Ogle\n\n\nMay 11, 2021\n\n\n\n\n\nJan 1, 2023\n\n\n\n\n\n\n\n\n\n\n\n\n\nAge Bias Plots in ggplot2\n\n\n8 min\n\n\nFlexibly construct age bias and age difference plots using ggplot2\n\n\n\nMichael Lant\n\n\nMar 15, 2021\n\n\n\n\n\nDec 7, 2022\n\n\n\n\n\n\n\n\n\n\n\n\n\nvon Bertalanffy Growth Plots I\n\n\n10 min\n\n\nHow to plot one von Bertalanffy growth model with data.\n\n\n\nDerek H. Ogle\n\n\nDec 31, 2019\n\n\n\n\n\nMar 17, 2023\n\n\n\n\n\n\n\n\n\n\n\n\n\nLength Frequency Histograms in ggplot2\n\n\n5 min\n\n\nFlexibly construct length frequency histograms using ggplot2\n\n\n\nDerek H. Ogle\n\n\nDec 28, 2019\n\n\n\n\n\nMar 19, 2023\n\n\n\n\n\n\n\n\n\n\n\n\n\nvon Bertalanffy Growth Plots II\n\n\n19 min\n\n\nHow to plot multiple von Bertalanffy growth models with data.\n\n\n\nDerek H. Ogle\n\n\nJan 2, 2019\n\n\n\n\n\nFeb 13, 2023\n\n\n\n\n\n\n\n\n\n\n\n\n\nCollapsing Categories or Values\n\n\n7 min\n\n\nHow to collapse categories or values into other categories\n\n\n\nDerek H. Ogle\n\n\nMar 30, 2018\n\n\n\n\n\nDec 19, 2022\n\n\n\n\n\n\n\n\n\n\n\n\n\nStock-Recruitment Graphing Questions\n\n\n7 min\n\n\nA reply to a user’s questions with respect to stock-recruitment function graphics.\n\n\n\nDerek H. Ogle\n\n\nDec 12, 2017\n\n\n\n\n\nDec 18, 2022\n\n\n\n\n\n\n\n\n\n\n\n\n\nPlots of Back-Calculated Lengths-At-Age\n\n\n8 min\n\n\nInitial thoughts on displaying back-calculated lengths-at-age.\n\n\n\nDerek H. Ogle\n\n\nNov 7, 2017\n\n\n\n\n\nFeb 13, 2023\n\n\n\n\n\n\n\n\n\n\n\n\n\nMean Weights at Ages From Lengths\n\n\n15 min\n\n\nDemonstrates concerns and corrections with estimating mean weight from observed lengths and a weight-length relationship.\n\n\n\nDerek H. Ogle\n\n\nAug 9, 2017\n\n\n\n\n\nFeb 13, 2023\n\n\n\n\n\n\n\n\n\n\n\n\n\nRidgeline Length Frequency Plots\n\n\n2 min\n\n\nHow to visualize multiple length frequencies as ridgline plots.\n\n\n\nDerek H. Ogle\n\n\nJul 28, 2017\n\n\n\n\n\nFeb 13, 2023\n\n\n\n\n\n\n\n\n\n\n\n\n\nBland-Altman Plot for Age Comparisons?\n\n\n10 min\n\n\nExplore the use of Bland-Altman plots for comparing paired age estimates.\n\n\n\nDerek H. Ogle\n\n\nApr 20, 2017\n\n\n\n\n\nFeb 13, 2023\n\n\n\n\n\n\n\n\n\n\n\n\n\nComputing SE for PSD indices\n\n\n1 min\n\n\nDemonstrate how to compute SE for PSD indices.\n\n\n\nDerek H. Ogle\n\n\nDec 9, 2016\n\n\n\n\n\nDec 19, 2022\n\n\n\n\n\n\n\n\n\n\n\n\n\nPauly et al. (1992) Seasonal Cessation Growth Model\n\n\n2 min\n\n\nAnnouncement of an algorithm to fit the Pauly et al. (1992) seasonal cessation growth model\n\n\n\nDerek H. Ogle\n\n\nNov 11, 2016\n\n\n\n\n\nFeb 13, 2023\n\n\n\n\n\n\n\n\n\n\n\n\n\nTwo New Cumulative Sum Functions\n\n\n1 min\n\n\nIntroducing the missing current and reverse cumulative sum functions.\n\n\n\nDerek H. Ogle\n\n\nSep 6, 2015\n\n\n\n\n\nDec 19, 2022\n\n\n\n\n\n\n\n\n\n\n\n\n\nAge Comparison Results for Individual Fish\n\n\n1 min\n\n\nDemonstrates how to extract age comparison results for individual fish from the object returned by ageComparisons().\n\n\n\nDerek H. Ogle\n\n\nSep 5, 2015\n\n\n\n\n\nDec 7, 2022\n\n\n\n\n\n\n\nNo matching items" }, { "objectID": "blog/posts/2015-9-5_Age_Comparison_Results/index.html", @@ -328,6 +328,34 @@ "section": "Putting It Together", "text": "Putting It Together\nThe basic bar plot is constructed from the summarized data in dat using geom_col() with Lake mapped to the x-axis, MEDIAN mapped to the y-axis, and Stage mapped to the fill= color. The bars will not be sided-by-side by default; they need to be “dodged” by setting postion= to the dodge position value set above. color= is set to black to outline each bar as in Rook et al. (2022). facet_wrap() is used to separate the plots by Type, with only one column used. The x-axis was “freed” so that the axis and labels would be shown in both facets as in Rook et al. (2022).\n\nggplot() +\n geom_col(data=dat,mapping=aes(x=Lake,y=MEDIAN,fill=Stage),\n position=pd,color=\"black\") +\n facet_wrap(vars(Type),ncol=1,scales=\"free_x\")\n\n\n\n\n\n\n\n\nConfidence intervals are added with geom_errorbar() with Lake again mapped to the x-axis, L95 and U95 mapped to the minimum and maximum y interval values, and Stage set as a group.5 To match the bars the confidence intervals must be dodged in the same way with postion= and the “cap” on the interval was made smaller with width=.5 The data needs a group here to match the group created by fill= in geom_col().\n\nggplot() +\n geom_col(data=dat,mapping=aes(x=Lake,y=MEDIAN,fill=Stage),\n position=pd,color=\"black\") +\n geom_errorbar(data=dat,mapping=aes(x=Lake,ymin=L95,ymax=U95,group=Stage),\n position=pd,width=0.5) +\n facet_wrap(vars(Type),ncol=1,scales=\"free_x\")\n\n\n\n\n\n\n\n\nColors were then set with scale_fill_manual() using the sclrs vector defined above. In addition, the y-axis was given a better title, the limits were set, axis expansion was removed, major breaks (i.e., labelled) were set at intervals of 200, and minor breaks were set at intervals of 100.66 These axis modifications were described in more detail in this post.\n\nggplot() +\n geom_col(data=dat,mapping=aes(x=Lake,y=MEDIAN,fill=Stage),\n position=pd,color=\"black\") +\n geom_errorbar(data=dat,mapping=aes(x=Lake,ymin=L95,ymax=U95,group=Stage),\n position=pd,width=0.5) +\n facet_wrap(vars(Type),ncol=1,scales=\"free_x\") +\n scale_fill_manual(values=sclrs) +\n scale_y_continuous(name=\"Stocking Density (fish/ha)\",\n limits=c(0,1800),expand=expansion(mult=0),\n breaks=scales::breaks_width(200),\n minor_breaks=scales::breaks_width(100),\n guide=\"axis_minor\")\n\n\n\n\n\n\n\n\nLabels are now added to the facets with geom_richtext() from the ggtext package. Here data= is set to datlbls, which is why data=dat was used in geom_col() and geom_errobar() rather than being set in ggplot().7 The Label in datlbls is mapped to the labels, but x= and y= are defined outside of the data frame. Specifically, x= is set to 3.5 because each category is listed behind the scenes with sequential numbers beginning at 1. With six categories on the x-axis, the center will be at 3.5. y= is set to Inf to generically be set at the largest y value plotted. Thus, the labels will be centered from left-to-right (x-axis orientation) and at the top (y-axis orientation). vjust= is used to move the label down slightly (see this post), label.color=NA removes the default box around the label, and size= was used to reduce the default size slightly.7 If multiple data frames are used when constructing a figure, then those data frames are usually declared in the geoms rather than in ggplot().\n\nggplot() +\n geom_col(data=dat,mapping=aes(x=Lake,y=MEDIAN,fill=Stage),\n position=pd,color=\"black\") +\n geom_errorbar(data=dat,mapping=aes(x=Lake,ymin=L95,ymax=U95,group=Stage),\n position=pd,width=0.5) +\n ggtext::geom_richtext(dat=datlbls,mapping=aes(label=Label),x=3.5,y=Inf,\n vjust=0.9,label.color=NA,size=3.5) +\n facet_wrap(vars(Type),ncol=1,scales=\"free_x\") +\n scale_fill_manual(values=sclrs) +\n scale_y_continuous(name=\"Stocking Density (fish/ha)\",\n limits=c(0,1800),expand=expansion(mult=0),\n breaks=scales::breaks_width(200),\n minor_breaks=scales::breaks_width(100),\n guide=\"axis_minor\")\n\n\n\n\n\n\n\n\nFinally, the theme was modified to more closely match Figure 4 in Rook et al. (2022). Specifically, theme_class() was used as the base and facet labels were removed, the x-axis title was removed, major tick mark size was increased, minor tick mark size was set to 50% of the major tick mark size, the legend was moved to the upper right of the plot, the legend title was removed, the legend text was made smaller, and the legend box size was made smaller.\n\nggplot() +\n geom_col(data=dat,mapping=aes(x=Lake,y=MEDIAN,fill=Stage),\n position=pd,color=\"black\") +\n geom_errorbar(data=dat,mapping=aes(x=Lake,ymin=L95,ymax=U95,group=Stage),\n position=pd,width=0.5) +\n ggtext::geom_richtext(dat=datlbls,mapping=aes(label=Label),x=3.5,y=Inf,\n vjust=0.9,label.color=NA,size=3.5) +\n facet_wrap(vars(Type),ncol=1,scales=\"free_x\") +\n scale_fill_manual(values=sclrs) +\n scale_y_continuous(name=\"Stocking Density (fish/ha)\",\n limits=c(0,1800),expand=expansion(mult=0),\n breaks=scales::breaks_width(200),\n minor_breaks=scales::breaks_width(100),\n guide=\"axis_minor\") +\n theme_classic() +\n theme(strip.text=element_blank(),\n axis.title.x=element_blank(),\n axis.ticks.length=unit(5,units=\"pt\"),\n ggh4x.axis.ticks.length.minor=rel(0.5),\n legend.position=c(1,1),\n legend.justification=c(1.05,0.95),\n legend.title=element_blank(),\n legend.text=element_text(size=7),\n legend.key.size = unit(0.75,units=\"line\")\n )\n\n\n\n\n\n\n\n\nThis largely reproduces Figure 4 in Rook et al. (2022) with the exceptions that (a) the tick marks don’t cross the x-axes and (b) the x-axis tick marks are centered on the group of bars rather than between the group of bars." }, + { + "objectID": "blog/posts/2023-3-22_McCarricketal2022_Fig2/index.html", + "href": "blog/posts/2023-3-22_McCarricketal2022_Fig2/index.html", + "title": "McCarrick et al. (2022) CPE Plot", + "section": "", + "text": "Series Note\n\n\n\nThis is the first of several posts related to McCarrick et al. (2022).\n\n\n\nIntroduction\nMcCarrick et al. (2022) examined the population dynamics of Yellowstone Cutthroat Trout (Oncorhynchus clarkii bouvieri) in Henrys Lake, Idaho over a nearly two decade period. Their Figure 2 shows the catch-per-unit-effort (CPE) of both Cutthroat Trout and Utah Chub (Gila atraria) by size categories across years. I use ggplot2 to recreate that figure here.\nThe following packages are loaded for use below. A few functions from each of lubridate, FSA, plyr, scales, gghrx, and lemon are used with :: such that the entire packages are not attached here.\n\nlibrary(tidyverse) # for dplyr, ggplot2 packages\nlibrary(patchwork) # for arranging multiple plots\n\n\n\n\n\n\n\nNote\n\n\n\nYou will see below that I could recreate the structure but not the exact results of the author’s Figure 2. This may be due to issues present in the data provided with the publication that I discuss below, but it could also be that my data wrangling differs from theirs. I defer to the authors here as they are the experts with their day; I am just an interloper. I actually appreciate these data issues from an educational perspective as they provide rich opportunities to demonstrate a variety of techniques with “real” “messy” data.\n\n\n \n\n\nData Wrangling\n\nReading Excel File and Handling Dates\nMcCarrick et al. (2022) provided raw data for Figure 2 as an Excel file in their Data Supplement S1. Several “issues” were apparent on my first attempts to load these data.\n\nMissing data was recorded as missing cells, with “??”, and with “UNK”.\nThere were oddly placed strings in some data fields (e.g., “Qty=”, “Qty =”, and “No Tag”). [I treated these as missing data below.]\nDates were recorded as just year, full date with two-digit year, and full date with four-digit year. [More on this below.]\nInconsistent “species” abbreviations. [More on this below.]\nIncorrect length and weight measurements (e.g., <10 mm, >2000 mm). [I treated these “as is” (i.e., without correction) for this post.]\n\nThe missing data and oddly named cells were handled with na= below. In addition, the column types were specifically defined in col_types=, primarily so that the first column would be largely correctly read as a date. The year was then extracted from the Date variable using year() from lubridate. However, the dates recorded in the original file as only a year were interpreted as an “Excel date code” rather than a date and, thus, the year was not extracted correctly. Fortunately, this “date” format was only used for one year (2002) such that the extracted year was consistently “1905.” Thus, the “1905” was replaced with “2002” for the extracted year with ifelse() as shown below. Several years did not exist (because the date was not recorded) and were removed with filter(). Finally, the variables were rearranged slightly, Species was changed to species for consistency with other variables, and the long effort variable was changed to the shorter netNights.11 Note that this code still produced a large number of warnings, all related to the “2002” “date”.\n\ndat <- readxl::read_xlsx(\"download.xlsx\",\n na=c(\"\",\"??\",\"QTY =\",\"QTY=\",\"UNK\",\"NO TAG\"),\n col_types=c(\"date\",\"numeric\",\"text\",\n \"numeric\",\"numeric\",\"text\")) |>\n mutate(year=lubridate::year(Date),\n year=ifelse(year==1905,2002,year)) |>\n filter(!is.na(year)) |>\n select(species=Species,year,length,weight,netNights=`number of net nights`)\nFSA::headtail(dat)\n\n#R| species year length weight netNights\n#R| 1 YCT 2002 150 NA 18\n#R| 2 YCT 2002 160 NA 18\n#R| 3 YCT 2002 160 NA 18\n#R| 23971 YCT 2020 391 550 30\n#R| 23972 YCT 2020 284 229 30\n#R| 23973 YCT 2020 440 853 30\n\n\n\n\nNew Effort Data Frame\nThe effort (i.e., netNights) variable seems out-of-place in the sense that each row of this data frame is a single fish. I suspected that this effort is actually for a year and was repeated for each fish captured in the same year. To examine my suspicion, I computed the minimum and maximum effort (and the difference between the two) for each year.\n\ndat |>\n group_by(year) |>\n summarize(minF=min(netNights,na.rm=TRUE),\n maxF=max(netNights,na.rm=TRUE),\n diff=maxF-minF)\n\n#R| # A tibble: 19 × 4\n#R| year minF maxF diff\n#R| \n#R| 1 2002 18 18 0\n#R| 2 2003 18 18 0\n#R| 3 2004 50 50 0\n#R| 4 2005 46 46 0\n#R| 5 2006 48 48 0\n#R| 6 2007 44 44 0\n#R| 7 2008 12 12 0\n#R| 8 2009 23 23 0\n#R| 9 2010 50 50 0\n#R| 10 2011 30 30 0\n#R| 11 2012 50 50 0\n#R| 12 2013 50 50 0\n#R| 13 2014 48 48 0\n#R| 14 2015 50 50 0\n#R| 15 2016 48 48 0\n#R| 16 2017 50 50 0\n#R| 17 2018 50 50 0\n#R| 18 2019 50 50 0\n#R| 19 2020 30 50 20\n\n\nThe minimum and maximum efforts are the same for each, with the exception of 2020. I suspect that this is a typo. A quick table of efforts for 2020 shows that the vast majority are 30, rather than 50, net-nights. Further, my initial analysis with these data resulted in CPE values for 2020 that were lower than what was shown in McCarrick et al. (2022). Thus, I am going to assume that 30 net-nights of effort was used in 2020 (see how this is corrected below).\n\nxtabs(~netNights,data=filter(dat,year==2020))\n\n#R| netNights\n#R| 30 50 \n#R| 865 9\n\n\nFor my purposes, I am going to create a new data frame of annual levels of effort by finding the minimum netNights in each year. The minimum is used here because it is the actual effort for all years that properly had a constant netNights entered and it is the assumed correct netNights for 2020 when a constant value was not entered.\n\neff <- dat |>\n group_by(year) |>\n summarize(netNights=min(netNights,na.rm=TRUE))\neff\n\n#R| # A tibble: 19 × 2\n#R| year netNights\n#R| \n#R| 1 2002 18\n#R| 2 2003 18\n#R| 3 2004 50\n#R| 4 2005 46\n#R| 5 2006 48\n#R| 6 2007 44\n#R| 7 2008 12\n#R| 8 2009 23\n#R| 9 2010 50\n#R| 10 2011 30\n#R| 11 2012 50\n#R| 12 2013 50\n#R| 13 2014 48\n#R| 14 2015 50\n#R| 15 2016 48\n#R| 16 2017 50\n#R| 17 2018 50\n#R| 18 2019 50\n#R| 19 2020 30\n\n\nThe netNights variables is no longer needed in the individual fish data frame.\n\ndat <- dat |>\n select(-netNights)\n\n\n\nFiltering to Two Species\nFigure 2 in McCarrick et al. (2022) only displays results for Cutthroat Trout and Utah Chub. Thus, the data frame should be reduced to just these species. First, a look at how species are identified.\n\nunique(dat$species)\n\n#R| [1] \"YCT\" \"BKT\" \"HYB\" \"CHB\" \"RSS\" \"UTC\" \"KOK\" \n#R| [8] \"BRT\" \"CHUB\" NA \"HB\" \"Yct\" \"NO FISH\" \"SCU\"\n\n\nFrom the published paper it is apparent that “YCT” is for Yellowstone Cutthroat Trout and “UTC” is for Utah Chub. But note the “Yct” and the “CHB” and “CHUB”. A little closer look at just these abbreviations by year suggests that “Yct” is a “one-off” typo, but that “CHB” and “CHUB” appeared to be used in some years when “UTC” was mostly not used. This suggested to me that “CHB” and “CHUB” were likely synonyms for “UTC”.\n\nxtabs(~year+species,data=filter(dat,species %in% c(\"YCT\",\"Yct\",\"UTC\",\"CHB\",\"CHUB\")))\n\n#R| species\n#R| year CHB CHUB UTC Yct YCT\n#R| 2002 0 0 0 0 55\n#R| 2003 84 0 2 0 162\n#R| 2004 0 0 728 0 323\n#R| 2005 0 0 294 0 305\n#R| 2006 0 0 424 0 269\n#R| 2007 0 0 895 0 658\n#R| 2008 0 606 0 0 100\n#R| 2009 0 0 512 0 91\n#R| 2010 0 0 0 0 502\n#R| 2011 0 440 0 0 374\n#R| 2012 0 0 692 0 500\n#R| 2013 0 0 1858 0 478\n#R| 2014 0 0 1767 1 475\n#R| 2015 0 0 1660 0 254\n#R| 2016 0 0 1078 0 265\n#R| 2017 0 0 1025 0 149\n#R| 2018 0 0 1273 0 76\n#R| 2019 0 0 696 0 219\n#R| 2020 0 0 414 0 198\n\n\nThus, species is modified below by combining “YCT” and “Yct” into “YCT”, and combining “UTC”, “CHB”, and “CHUB” into “UTC”.2 The data frame was subsequently reduced to just these two species.2 And leaving all other species “names” as-is.\n\ndat <- dat |>\n mutate(species=case_when(\n species %in% c(\"YCT\",\"Yct\") ~ \"YCT\",\n species %in% c(\"UTC\",\"CHB\",\"CHUB\") ~ \"UTC\",\n TRUE ~ species\n )\n ) |>\n filter(species %in% c(\"YCT\",\"UTC\"))\n\n# just checking\nunique(dat$species)\n\n#R| [1] \"YCT\" \"UTC\"\n\n\n\n\nAdding Gabelhouse Length Categories\nFigure 2 separates the data into panels based on Gabelhouse length categories (i.e., “Stock”, “Quality”, etc.). These categories can be efficiently added to the data frame using psdAdd() from FSA, but psdAdd() requires full species names rather than abbreviations. mapvalues() from plyr is used below to create a new variable with the full names derived from the abbreviations.\n\ndat <- dat |>\n mutate(species2=plyr::mapvalues(species,\n from=c(\"YCT\",\"UTC\"),\n to=c(\"Cutthroat Trout\",\"Utah Chub\")))\n# just checking\nxtabs(~species+species2,data=dat)\n\n#R| species2\n#R| species Cutthroat Trout Utah Chub\n#R| UTC 0 14448\n#R| YCT 5454 0\n\n\nNow the length categories may be added using species2.\n\ndat <- dat |>\n mutate(gcat=FSA::psdAdd(len=length,species=species2))\nFSA::headtail(dat)\n\n#R| species year length weight species2 gcat\n#R| 1 YCT 2002 150 NA Cutthroat Trout substock\n#R| 2 YCT 2002 160 NA Cutthroat Trout substock\n#R| 3 YCT 2002 160 NA Cutthroat Trout substock\n#R| 19900 YCT 2020 391 550 Cutthroat Trout quality\n#R| 19901 YCT 2020 284 229 Cutthroat Trout stock\n#R| 19902 YCT 2020 440 853 Cutthroat Trout quality\n\n\n\n\nComputing CPE\nFrom this, the data needs to be summarized to produce the CPE for each species for each year for each length category and for all fish regardless of length category. Development of this data frame will begin by counting the number of fish (i.e., rows) for each length category within each year within each species.\n\ncatch_gcat <- dat |>\n group_by(species,year,gcat) |>\n summarize(catch=n())\ncatch_gcat\n\n#R| # A tibble: 162 × 4\n#R| # Groups: species, year [36]\n#R| species year gcat catch\n#R| \n#R| 1 UTC 2003 substock 5\n#R| 2 UTC 2003 stock 41\n#R| 3 UTC 2003 quality 21\n#R| 4 UTC 2003 preferred 15\n#R| 5 UTC 2003 memorable 4\n#R| 6 UTC 2004 substock 2\n#R| 7 UTC 2004 stock 535\n#R| 8 UTC 2004 quality 128\n#R| 9 UTC 2004 preferred 52\n#R| 10 UTC 2004 memorable 11\n#R| # … with 152 more rows\n\n\nNote in the previous output that catch_gcat is still “grouped” by year within species. Thus, catch can summed from this data frame to find the total catch per year for each species.33 Ungroup this data frame as we will not summarize it further.\n\ncatch_all <- catch_gcat |>\n summarize(catch=sum(catch)) |>\n ungroup()\ncatch_all\n\n#R| # A tibble: 36 × 3\n#R| species year catch\n#R| \n#R| 1 UTC 2003 86\n#R| 2 UTC 2004 728\n#R| 3 UTC 2005 294\n#R| 4 UTC 2006 424\n#R| 5 UTC 2007 895\n#R| 6 UTC 2008 606\n#R| 7 UTC 2009 512\n#R| 8 UTC 2011 440\n#R| 9 UTC 2012 692\n#R| 10 UTC 2013 1858\n#R| # … with 26 more rows\n\n\nAs Figure 2 displays all fish and fish by length category, these two data frames should be row-bound (i.e., stacked) together. Figure 2 does not have panels for “substock”, “memorable”, or “trophy” sized fish so fish in those length categories were removed from the resultant data frame. Finally, a new variable called type was created that has the names from gcat, or “All” if gcat was NA4.4 gcat for “all fish” after bind_rows() was NA as gcat was not present in catch_all\n\ncpe_dat <- bind_rows(catch_all,catch_gcat) |>\n filter(!(gcat %in% c(\"substock\",\"memorable\",\"trophy\"))) |>\n mutate(type=ifelse(is.na(gcat),\"All\",as.character(gcat)))\nFSA::headtail(cpe_dat)\n\n#R| species year catch gcat type\n#R| 1 UTC 2003 86 All\n#R| 2 UTC 2004 728 All\n#R| 3 UTC 2005 294 All\n#R| 143 YCT 2020 52 stock stock\n#R| 144 YCT 2020 132 quality quality\n#R| 145 YCT 2020 13 preferred preferred\n\n\nFinally, these data are left-join()ed (by year) with eff to add netNights, from which a new cpe variable is created. type was converted to a factor to match the vertical order of Figure 2, and the levels were given longer labels to match the labels in Figure 2. Finally, the variables were re-ordered (and gcat was dropped) for personal preference.\n\ncpe_dat <- cpe_dat |>\n left_join(eff,by=\"year\") |>\n mutate(cpe=catch/netNights,\n type=factor(type,levels=c(\"All\",\"stock\",\"quality\",\"preferred\"),\n labels=c(\"All fish\",\"Stock to Quality\",\n \"Quality to Preferred\",\"Preferred to Memorable\"))) |>\n select(species,year,type,catch,netNights,cpe)\nFSA::headtail(cpe_dat)\n\n#R| species year type catch netNights cpe\n#R| 1 UTC 2003 All fish 86 18 4.7777778\n#R| 2 UTC 2004 All fish 728 50 14.5600000\n#R| 3 UTC 2005 All fish 294 46 6.3913043\n#R| 143 YCT 2020 Stock to Quality 52 30 1.7333333\n#R| 144 YCT 2020 Quality to Preferred 132 30 4.4000000\n#R| 145 YCT 2020 Preferred to Memorable 13 30 0.4333333\n\n\nThis data frame, now called cpe_dat, is now ready for recreating Figure 2.\n\n\nQuick Summaries of CPE\nBefore recreating Figure 2, I summarized the CPE data by species and year for comparison to results in McCarrick et al. (2022).\n\ncpe_dat |>\n filter(type==\"All fish\") |>\n group_by(species) |>\n summarize(n=n(),\n ttlcatch=sum(catch),\n mncpe=mean(cpe),\n sdcpe=sd(cpe),\n mincpe=min(cpe),\n minyr=year[cpe==mincpe],\n maxcpe=max(cpe),\n maxyr=year[cpe==maxcpe])\n\n#R| # A tibble: 2 × 9\n#R| species n ttlcatch mncpe sdcpe mincpe minyr maxcpe maxyr\n#R| \n#R| 1 UTC 18 14459 20.0 12.9 0.239 2005 50.5 2008\n#R| 2 YCT 19 5454 7.16 3.48 1.52 2018 15.0 2007\n\n\nIn the first paragraph of the results, McCarrick et al. (2022) found the overall mean (and SD) CPE was 7.4 (3.6) for YCT and 19.9 (13.0) for UTC, which is close to what I obtained for UTC but not for YTC. In addition, they found a peak CPE of 15.4 for YCT in 2007 and 50.5 for UTC in 2008, again very close to my results for UTC but not that close for YCT. Finally, in the label for Figure 2 they reported 5,524 YCT were captured, whereas my results only show 5,454.\n \n\n\n\nRecreating Figure 2\nMy general strategy for recreating Figure 2 was to create the left and right panels of subplots separately and then combine them using patchwork. Each side can be constructed via faceting on type, but I will use facet_rep_wrap() from lemon so as to have the x-axis tick marks on each panel.5 Each panel will be create with geom_col() using width=1 so that the bars touch and geom_text() to place the labels.6 The x- and y-axes were modified as is commonly done.7 Finally, I used theme_bw() as a base, removed the gridlines and removed the facet labels and background.8 As you examine the code below, make sure to realize that the data was filtered to just “YCT”.5 See this post about facet_rep_wrap().6 See this post for more explanation of how to use geom_text() in this way.7 And is described more in this post.8 As described in this post.\n\nYCT <- ggplot(data=filter(cpe_dat,species==\"YCT\"),\n mapping=aes(x=year,y=cpe)) +\n geom_col(color=\"black\",fill=\"gray70\",width=1) +\n geom_text(mapping=aes(label=type),x=Inf,y=Inf,vjust=1.25,hjust=1.05,\n check_overlap=TRUE,size=3) +\n scale_y_continuous(name=\"YCT per net night\",\n limits=c(0,16),breaks=scales::breaks_width(2),\n expand=expansion(mult=0)) +\n scale_x_continuous(name=\"Year\",\n limits=c(2000,2022),breaks=scales::breaks_width(2),\n expand=expansion(mult=0)) +\n lemon::facet_rep_wrap(vars(type),ncol=1) +\n theme_bw() +\n theme(panel.grid=element_blank(),\n strip.background=element_blank(),\n strip.text=element_blank())\nYCT\n\n\n\n\n\n\n\n\nThe code above was largely repeated but with data filtered to just “UTC” and adjusting the y-axis accordingly. The plot is not shown here but is the right side in the plot further below.\n\nUTC <- ggplot(data=filter(cpe_dat,species==\"UTC\"),mapping=aes(x=year,y=cpe)) +\n geom_col(color=\"black\",fill=\"gray70\",width=1) +\n geom_text(mapping=aes(label=type),x=Inf,y=Inf,vjust=1.25,hjust=1.05,\n check_overlap=TRUE,size=3) +\n scale_y_continuous(name=\"UTC per net night\",\n limits=c(0,60),breaks=scales::breaks_width(10),\n expand=expansion(mult=0)) +\n scale_x_continuous(name=\"Year\",\n limits=c(2000,2022),breaks=scales::breaks_width(2),\n expand=expansion(mult=0)) +\n lemon::facet_rep_wrap(vars(type),ncol=1) +\n theme_bw() +\n theme(panel.grid=element_blank(),\n strip.background=element_blank(),\n strip.text=element_blank())\n\nThe two subplots are then placed side-by-side.\n\nYCT + UTC\n\n\n\n\n\n\n\n\n \n\n\nFurther Thoughts\nI wanted to see if I could make a similar looking plot using facet_grid(). It turns out to be a bit of a challenge because each panel on the left- and right-sides has the same y-axis, but those axes differ between the two sides. I found a way around this.\nFirst, I changed species to a factor with “YCT” in the first position so it would be plotted on the left (i.e., first). I also gave the levels longer labels so that the facets would have useful labels.\n\ncpe_dat <- cpe_dat |>\n mutate(species=factor(species,levels=c(\"YCT\",\"UTC\"),\n labels=c(\"Yellowstone Cutthroat Trout\",\"Utah Chub\")))\n\nThe y-axis needs to be defined for each facet. However, these definitions should be constant within species. Thus, I define limits and breaks for both YCT and UTC and saved them as objects. In addition, to save typing, I also defined the expansion factor as an object.\n\nYCT_lmts <- c(0,16)\nYCT_brks <- scales::breaks_width(2)\nUTC_lmts <- c(0,60)\nUTC_brks <- scales::breaks_width(10)\nyexp <- expansion(mult=0)\n\nThe basic plot uses the same ggplot() (except the data is not filtered), geom_col(), scale_x_continous(), and theme_bw() as before. The geom_text() has been eliminated because the “type” labels are going to be in the facet labels rather than “on the plot.” The part of theme() that removed the facet labels has been eliminated as facet labels are needed here. The spacing between panels was increased in theme() here. facet_rep_wrap() was replaced with facet_grid2() from ggh4x, where the rows are defined by type, the columns are defined by species, the y-axes are “free” and “independent” from facet to facet.9 Finally, facetted_pos_scales() from ggh4x is used to apply a different scale_y_continous() to each panel.109 The independent=\"y\" part is the main thing that facet_grid2() adds over facet_grid() from ggplot2.10 facetted_pos_scales() is described in more detail in this post.\n\nggplot(data=cpe_dat,mapping=aes(x=year,y=cpe)) +\n geom_col(color=\"black\",fill=\"gray70\",width=1) +\n scale_x_continuous(name=\"Year\",\n limits=c(2000,2022),breaks=scales::breaks_width(2),\n expand=expansion(mult=0)) +\n ggh4x::facet_grid2(rows=vars(type),cols=vars(species),\n scales=\"free_y\",independent=\"y\") +\n theme_bw() +\n theme(panel.grid=element_blank(),\n panel.spacing=unit(10,units=\"pt\")) +\n ggh4x::facetted_pos_scales(\n y=list(\n scale_y_continuous(name=\"# Fish per net night\",\n limits=YCT_lmts,breaks=YCT_brks,expand=yexp),\n scale_y_continuous(limits=UTC_lmts,breaks=UTC_brks,expand=yexp),\n scale_y_continuous(limits=YCT_lmts,breaks=YCT_brks,expand=yexp),\n scale_y_continuous(limits=UTC_lmts,breaks=UTC_brks,expand=yexp),\n scale_y_continuous(limits=YCT_lmts,breaks=YCT_brks,expand=yexp),\n scale_y_continuous(limits=UTC_lmts,breaks=UTC_brks,expand=yexp),\n scale_y_continuous(limits=YCT_lmts,breaks=YCT_brks,expand=yexp),\n scale_y_continuous(limits=UTC_lmts,breaks=UTC_brks,expand=yexp)\n )\n )\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n\n\nReferences\n\nMcCarrick, D. K., J. C. Dillon, B. High, and M. C. Quist. 2022. Population dynamics of Yellowstone Cutthroat Trout in Henrys Lake, Idaho. Journal of Fish and Wildlife Management 13(1):169–181.\n\nReusehttps://creativecommons.org/licenses/by/4.0/CitationBibTeX citation:@online{h.ogle2023,\n author = {Derek H. Ogle},\n title = {McCarrick Et Al. (2022) {CPE} {Plot}},\n date = {2023-03-22},\n url = {https://fishr-core-team.github.io/fishR//blog/posts/2023-3-22_McCarricketal2022_Fig2},\n langid = {en}\n}\nFor attribution, please cite this work as:\nDerek H. Ogle. 2023, March 22. McCarrick et al. (2022) CPE Plot. https://fishr-core-team.github.io/fishR//blog/posts/2023-3-22_McCarricketal2022_Fig2." + }, + { + "objectID": "blog/posts/2023-3-25_McCarricketal2022_Fig3/index.html", + "href": "blog/posts/2023-3-25_McCarricketal2022_Fig3/index.html", + "title": "McCarrick et al. (2022) PSD Plot", + "section": "", + "text": "Series Note\n\n\n\nThis is the second of several posts related to McCarrick et al. (2022).\n\n\n\nIntroduction\nMcCarrick et al. (2022) examined the population dynamics of Yellowstone Cutthroat Trout (Oncorhynchus clarkii bouvieri) in Henrys Lake, Idaho over a nearly two decade period. Their Figure 3 showed various proportional stock distribution (PSD) calculations of Cutthroat Trout across years. I use ggplot2 to recreate that figure here. I also modified their plot by adding confidence intervals to the calculations.\nThe following packages are loaded for use below. A few functions from each of lubridate, FSA, plyr, tidyr, scales, gghrx, and lemon are used with :: such that the entire packages are not attached here.\n\nlibrary(tidyverse) # for dplyr, ggplot2 packages\n\nMcCarrick et al. (2022) computed what I am calling an overall PSD1 and what are called “incremental” PSD indices. I assume that these are familar to most fisheries scientists, but they are described in more detail in Chapter 6 of Ogle (2016).21 This is the most common PSD measure.2 This provides a decent description of the overall PSD.\n \n\n\nData Wrangling\n\nIndividual Fish Data Frame\nMcCarrick et al. (2022) provided raw data for Figure 2 as an Excel file in their Data Supplement S1. The same data wrangling, up to where catch-per-unit-effort was calculated, used in this previous post is used here and, thus, will not be discussed in detail.\n\ndat <- readxl::read_xlsx(\"../2023-3-22_McCarricketal2022_Fig2/download.xlsx\",\n na=c(\"\",\"??\",\"QTY =\",\"QTY=\",\"UNK\",\"NO TAG\"),\n col_types=c(\"date\",\"numeric\",\"text\",\n \"numeric\",\"numeric\",\"text\")) |>\n mutate(year=lubridate::year(Date),\n year=ifelse(year==1905,2002,year)) |>\n filter(!is.na(year)) |>\n select(species=Species,year,length,weight) |>\n mutate(species=case_when(\n species %in% c(\"YCT\",\"Yct\") ~ \"YCT\",\n species %in% c(\"UTC\",\"CHB\",\"CHUB\") ~ \"UTC\",\n TRUE ~ species\n )) |>\n filter(species %in% c(\"YCT\",\"UTC\")) |>\n mutate(species2=plyr::mapvalues(species,\n from=c(\"YCT\",\"UTC\"),\n to=c(\"Cutthroat Trout\",\"Utah Chub\"))) |>\n mutate(gcat=FSA::psdAdd(len=length,species=species2))\n\nFSA::headtail(dat)\n\n#R| species year length weight species2 gcat\n#R| 1 YCT 2002 150 NA Cutthroat Trout substock\n#R| 2 YCT 2002 160 NA Cutthroat Trout substock\n#R| 3 YCT 2002 160 NA Cutthroat Trout substock\n#R| 19900 YCT 2020 391 550 Cutthroat Trout quality\n#R| 19901 YCT 2020 284 229 Cutthroat Trout stock\n#R| 19902 YCT 2020 440 853 Cutthroat Trout quality\n\n\n\n\nPSD Summary Data Frame\nThe data frame was filtered to only Cutthroat Trout (the only species shown in Figure 3) and sub-stock-sized fish were removed (PSD calculations do not consider sub-stock-sized fish).\n\npsd_dat <- dat |>\n filter(species==\"YCT\",gcat!=\"substock\")\n\nThe calculation of PSD values begins by counting the number of fish in each of the remaining Gabelhouse length categories, within each year.\n\npsd_dat <- psd_dat |>\n group_by(year,gcat) |>\n summarize(count=n()) |>\n ungroup()\nFSA::headtail(psd_dat)\n\n#R| year gcat count\n#R| 1 2002 stock 20\n#R| 2 2002 quality 28\n#R| 3 2002 preferred 1\n#R| 61 2020 stock 52\n#R| 62 2020 quality 132\n#R| 63 2020 preferred 13\n\n\nThis data frame was then made wider by creating columns with the length category names, each with the “count” in that category underneath it for each year.\n\npsd_dat <- psd_dat |>\n pivot_wider(names_from=gcat,values_from=count)\nFSA::headtail(psd_dat)\n\n#R| year stock quality preferred memorable trophy\n#R| 1 2002 20 28 1 NA NA\n#R| 2 2003 31 57 43 NA NA\n#R| 3 2004 141 36 27 1 NA\n#R| 17 2018 34 16 22 1 NA\n#R| 18 2019 176 20 17 3 NA\n#R| 19 2020 52 132 13 NA NA\n\n\nFor example, in 2002 there were 20 stock- to quality-sized fish, 28 quality- to preferred-size fish, 1 preferred- to memorable-sized fish, and no fish in the other categories. Each PSD calculation requires the total number of stock-size and larger fish as the denominator; i.e., 49 fish in 2002. In addition, the overall PSD calculation requires the total number of quality-sized and larger fish as the numerator; i.e., 28 fish in 2002. These two quantities are computed in mutate() below, but note that rowwise() is used before that to force the calculations to be computed by row (i.e., by year).33 If rowwise is not used then, for example, sum(stock+quality) would be the sum of both the stock and quality columns; i.e., the sum across all years.\n\npsd_dat <- psd_dat |>\n rowwise() |>\n mutate(qualityplus=sum(quality,preferred,memorable,trophy,na.rm=TRUE),\n stockplus=sum(stock,qualityplus,na.rm=TRUE))\nFSA::headtail(psd_dat)\n\n#R| year stock quality preferred memorable trophy qualityplus stockplus\n#R| 1 2002 20 28 1 NA NA 29 49\n#R| 2 2003 31 57 43 NA NA 100 131\n#R| 3 2004 141 36 27 1 NA 64 205\n#R| 17 2018 34 16 22 1 NA 39 73\n#R| 18 2019 176 20 17 3 NA 40 216\n#R| 19 2020 52 132 13 NA NA 145 197\n\n\nThe overall PSD is calculated as quality-sized and larger fish divided by stock-sized and larger fish multiplied by 100. The three incremental PSD values are calculated as the number in the incremental length group (e.g., stock- to quality-sized) divided by stock-sized and larger fish multiplied by 100. These calculations are made below within mutate().44 The incremental PSD names are within single back-ticks because the name contains a space (and a hyphen).\n\npsd_dat <- psd_dat |>\n mutate(PSD=qualityplus/stockplus*100,\n `PSD S-Q`=stock/stockplus*100,\n `PSD Q-P`=quality/stockplus*100,\n `PSD P-M`=preferred/stockplus*100) |>\n ungroup()\nFSA::headtail(psd_dat)\n\n#R| year stock quality preferred memorable trophy qualityplus stockplus PSD\n#R| 1 2002 20 28 1 NA NA 29 49 59.18367\n#R| 2 2003 31 57 43 NA NA 100 131 76.33588\n#R| 3 2004 141 36 27 1 NA 64 205 31.21951\n#R| 17 2018 34 16 22 1 NA 39 73 53.42466\n#R| 18 2019 176 20 17 3 NA 40 216 18.51852\n#R| 19 2020 52 132 13 NA NA 145 197 73.60406\n#R| PSD S-Q PSD Q-P PSD P-M\n#R| 1 40.81633 57.142857 2.040816\n#R| 2 23.66412 43.511450 32.824427\n#R| 3 68.78049 17.560976 13.170732\n#R| 17 46.57534 21.917808 30.136986\n#R| 18 81.48148 9.259259 7.870370\n#R| 19 26.39594 67.005076 6.598985\n\n\nFinally, this data frame should be made longer such that the calculated PSD values will appear under one column (called values) and another column will be created with the name of the PSD metric. This process begins by restricting the data frame to the year and all calculated PSD values, then pivoting the values in all of the PSD columns into one column with the names of the PSD metric stored in metric, and then factoring metric with the levels controlled so that they will be plotted in the same order as in Figure 3. This new data frame has a new name, as the original psd_dat data frame is used further below.\n\npsd_dat2 <- psd_dat |>\n select(year,contains(\"PSD\")) |>\n pivot_longer(cols=contains(\"PSD\"),names_to=\"metric\") |>\n mutate(metric=factor(metric,levels=c(\"PSD\",\"PSD S-Q\",\"PSD Q-P\",\"PSD P-M\")))\nFSA::headtail(psd_dat2)\n\n#R| year metric value\n#R| 1 2002 PSD 59.183673\n#R| 2 2002 PSD S-Q 40.816327\n#R| 3 2002 PSD Q-P 57.142857\n#R| 74 2020 PSD S-Q 26.395939\n#R| 75 2020 PSD Q-P 67.005076\n#R| 76 2020 PSD P-M 6.598985\n\n\nThis data frame, now called psd_dat2, is ready for recreating Figure 3.\n \n\n\n\nRecreating Figure 3\nFigure 3 is a simple bar plot facetted across years similar to the CPE plot in this previous post. Thus, I don’t discuss the details further here.\n\nggplot(data=psd_dat2,mapping=aes(x=year,y=value)) +\n geom_col(color=\"black\",fill=\"gray70\",width=1) +\n geom_text(mapping=aes(label=metric),x=Inf,y=Inf,vjust=1.25,hjust=1.05,size=3,\n check_overlap=TRUE) +\n scale_y_continuous(name=\"PSD\",limits=c(0,100),expand=expansion(mult=0),\n breaks=scales::breaks_width(20)) +\n scale_x_continuous(name=\"Year\",\n limits=c(2000,2022),breaks=scales::breaks_width(2),\n expand=expansion(mult=0)) +\n lemon::facet_rep_wrap(vars(metric),ncol=1) +\n theme_bw() +\n theme(panel.grid=element_blank(),\n strip.background=element_blank(),\n strip.text=element_blank())\n\n\n\n\n\n\n\n\n \n\n\nAdding Confidence Intervals\nI wanted to see if I could make Figure 3 as above, but add confidence intervals to the PSD calculations.55 The authors added CIs to the relative weight calculations in their Figure 4, but did not do that here for their PSD calculations.\nAs discussed in Ogle (2016) confidence intervals for a PSD can be made from binomial distribution theory using binCI() from FSA. This is a simple process of giving binCI() the number of “successes” (i.e., the numerator in the PSD calculation), the number of “trials”(i.e., the denominator), and the type of algorithm to use (we will use the “Wilson” algorithm here). For example, the CI for the overall PSD in 2002 is computed below.\n\nFSA::binCI(29,49,type=\"wilson\")*100\n\n#R| 95% LCI 95% UCI\n#R| 45.24732 71.78476\n\n\nThis becomes complicated here for several reasons:\n\nThe CIs are computed across multiple years.\nThe numerators differ among the PSD metrics (e.g., quality-sized and larger fish for the overall PSD but just quality-sized fish for PSD S-Q).\nbinCI() returns two values rather than 1 (thus, complicating the use of mutate()).\nbinCI() returns a matrix with column names rather than a named vector.\n\nGiven these issues, confidence intervals the PSD, PSD S-Q, etc. will each be calculated separately and then combined into a single data frame. I begin by calculating the CIs for the PSD.\nHere we return to the wide psd_dat data frame from above. The calculation will be for each year so again use rowwise(). FSA::binCI() will be used with mutate() but its result must first be converted to a vector with as.vector() (addresses last issue above) and then put in a list(). In this case the ci “variable” will be a list with two items (the lower and upper CI values) for each year. We want to get the two values out of this list and into their own variables, which is accomplished with unnest_wider() from tidyr (addressing the third issue above). The results from binCI() (after as.vector()) were unnamed, so names_sep= must be used in unnest_wider(). With this set to \"\", the unnested variables will be the original name (“ci”) followed by sequential numbers (i.e., “ci1” and “ci2” here). Finally,the data frame is reduced to the year, PSD, ci1, and ci2 variables, but PSD is renamed value along the way.66 This renaming is necessary for bind_rows() further below.\n\ntmp1 <- psd_dat |>\n rowwise() |>\n mutate(ci=list(as.vector(FSA::binCI(qualityplus,stockplus,type=\"wilson\")))) |>\n tidyr::unnest_wider(ci,names_sep=\"\") |>\n select(year,value=PSD,ci1,ci2)\nFSA::headtail(tmp1)\n\n#R| year value ci1 ci2\n#R| 1 2002 59.18367 0.4524732 0.7178476\n#R| 2 2003 76.33588 0.6837273 0.8279848\n#R| 3 2004 31.21951 0.2527076 0.3785916\n#R| 17 2018 53.42466 0.4209895 0.6440796\n#R| 18 2019 18.51852 0.1390441 0.2423283\n#R| 19 2020 73.60406 0.6703995 0.7926523\n\n\nThis exact code is repeated for PSD S-Q but making sure that stock is the first argument to binCI(), the new value variable comes from PSD S-Q, and the resulting data frame is given a different name.\n\ntmp2 <- psd_dat |>\n rowwise() |>\n mutate(ci=list(as.vector(FSA::binCI(stock,stockplus,type=\"wilson\")))) |>\n tidyr::unnest_wider(ci,names_sep=\"\") |>\n select(year,value=`PSD S-Q`,ci1,ci2)\n\nThis process is repeated for the other two metrics.\n\ntmp3 <- psd_dat |>\n rowwise() |>\n mutate(ci=list(as.vector(FSA::binCI(quality,stockplus,type=\"wilson\")))) |>\n tidyr::unnest_wider(ci,names_sep=\"\") |>\n select(year,value=`PSD Q-P`,ci1,ci2)\n\n\ntmp4 <- psd_dat |>\n rowwise() |>\n mutate(ci=list(as.vector(FSA::binCI(preferred,stockplus,type=\"wilson\")))) |>\n tidyr::unnest_wider(ci,names_sep=\"\") |>\n select(year,value=`PSD P-M`,ci1,ci2)\n\nThese four temporary data frames are bound together with a metric variable added to indicate which PSD metric appears in each row of the new data frame. Additionally, ci1 and ci2 were renamed to LCI and UCI for clarity, each CI endpoint was muliplied by 100 to put it on the same scale as the point estimates (i.e., percentages rather than proportions returned from binCI()), and metric was factored with controlled levels as above.\n\npsd_dat3 <- bind_rows(list(\"PSD\"=tmp1,\"PSD S-Q\"=tmp2,\"PSD Q-P\"=tmp3,\"PSD P-M\"=tmp4),\n .id=\"metric\") |>\n rename(LCI=`ci1`,UCI=`ci2`) |>\n mutate(LCI=LCI*100,UCI=UCI*100,\n metric=factor(metric,levels=c(\"PSD\",\"PSD S-Q\",\"PSD Q-P\",\"PSD P-M\")))\nFSA::headtail(psd_dat3)\n\n#R| metric year value LCI UCI\n#R| 1 PSD 2002 59.183673 45.247319 71.78476\n#R| 2 PSD 2003 76.335878 68.372730 82.79848\n#R| 3 PSD 2004 31.219512 25.270764 37.85916\n#R| 74 PSD P-M 2018 30.136986 20.822591 41.43737\n#R| 75 PSD P-M 2019 7.870370 4.971693 12.24137\n#R| 76 PSD P-M 2020 6.598985 3.896693 10.96152\n\n\nThe same code used above to recreate Figure 3 is repeated below, but geom_errorbar() is used with LCI mapped to ymin= and UCI mapped to ymax= to form the confidence intervals. geom_errorbar() is before geom_col() which gives the appearance of only showing the upper portion of the confidence interval (i.e., the lower portion is behind the bar). width=0.25 was used to narrow the “caps” on the intervals.\n\nggplot(data=psd_dat3,mapping=aes(x=year,y=value)) +\n geom_errorbar(mapping=aes(ymin=LCI,ymax=UCI),width=0.25) +\n geom_col(color=\"black\",fill=\"gray70\",width=1) +\n geom_text(mapping=aes(label=metric),x=Inf,y=Inf,vjust=1.25,hjust=1.05,size=3,\n check_overlap=TRUE) +\n scale_y_continuous(name=\"PSD\",limits=c(0,100),expand=expansion(mult=0),\n breaks=scales::breaks_width(20)) +\n scale_x_continuous(name=\"Year\",\n limits=c(2000,2022),breaks=scales::breaks_width(2),\n expand=expansion(mult=0)) +\n lemon::facet_rep_wrap(vars(metric),ncol=1) +\n theme_bw() +\n theme(panel.grid=element_blank(),\n strip.background=element_blank(),\n strip.text=element_blank())\n\n\n\n\n\n\n\n\n \n\n\nFurther Thoughts\n\nPoint-and-Lines Plot\nAs mentioned in this previous post I understand that these are the much derided “dynamite plots”. Personally, I find the bars distracting (so much gray with little purpose) and find a point-and-lines plot more appealing.\n\nggplot(data=psd_dat3,mapping=aes(x=year,y=value)) +\n geom_errorbar(mapping=aes(ymin=LCI,ymax=UCI),linewidth=0.5,width=0.25) +\n geom_line(linewidth=0.75,color=\"gray70\") +\n geom_point(size=1) +\n geom_text(mapping=aes(label=metric),x=Inf,y=Inf,vjust=1.25,hjust=1.05,size=3,\n check_overlap=TRUE) +\n scale_y_continuous(name=\"PSD\",limits=c(0,100),expand=expansion(mult=0),\n breaks=scales::breaks_width(20)) +\n scale_x_continuous(name=\"Year\",\n limits=c(2000,2022),breaks=scales::breaks_width(2),\n expand=expansion(mult=0)) +\n lemon::facet_rep_wrap(vars(metric),ncol=1) +\n theme_bw() +\n theme(panel.grid=element_blank(),\n strip.background=element_blank(),\n strip.text=element_blank())\n\n\n\n\n\n\n\n\n\n\nLoess Smoother\nA loess smoother could also be added with geom_smooth() to highlight any trends (or lack thereof).\n\nggplot(data=psd_dat3,mapping=aes(x=year,y=value)) +\n geom_errorbar(mapping=aes(ymin=LCI,ymax=UCI),linewidth=0.5,width=0.25) +\n geom_line(linewidth=0.75,color=\"gray70\") +\n geom_point(size=1) +\n geom_smooth(se=FALSE,color=\"gray30\",linetype=\"dashed\",linewidth=0.5) +\n geom_text(mapping=aes(label=metric),x=Inf,y=Inf,vjust=1.25,hjust=1.05,size=3,\n check_overlap=TRUE) +\n scale_y_continuous(name=\"PSD\",limits=c(0,100),expand=expansion(mult=0),\n breaks=scales::breaks_width(20)) +\n scale_x_continuous(name=\"Year\",\n limits=c(2000,2022),breaks=scales::breaks_width(2),\n expand=expansion(mult=0)) +\n lemon::facet_rep_wrap(vars(metric),ncol=1) +\n theme_bw() +\n theme(panel.grid=element_blank(),\n strip.background=element_blank(),\n strip.text=element_blank())\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n\n\n\nReferences\n\nMcCarrick, D. K., J. C. Dillon, B. High, and M. C. Quist. 2022. Population dynamics of Yellowstone Cutthroat Trout in Henrys Lake, Idaho. Journal of Fish and Wildlife Management 13(1):169–181.\n\n\nOgle, D. H. 2016. Introductory Fisheries Analyses with R. CRC Press, Boca Raton, FL.\n\nReusehttps://creativecommons.org/licenses/by/4.0/CitationBibTeX citation:@online{h.ogle2023,\n author = {Derek H. Ogle},\n title = {McCarrick Et Al. (2022) {PSD} {Plot}},\n date = {2023-03-25},\n url = {https://fishr-core-team.github.io/fishR//blog/posts/2023-3-25_McCarricketal2022_Fig3},\n langid = {en}\n}\nFor attribution, please cite this work as:\nDerek H. Ogle. 2023, March 25. McCarrick et al. (2022) PSD Plot. https://fishr-core-team.github.io/fishR//blog/posts/2023-3-25_McCarricketal2022_Fig3." + }, + { + "objectID": "blog/posts/2023-3-26_McCarricketal2022_Fig4/index.html", + "href": "blog/posts/2023-3-26_McCarricketal2022_Fig4/index.html", + "title": "McCarrick et al. (2022) Wr Plot", + "section": "", + "text": "Series Note\n\n\n\nThis is the third of several posts related to McCarrick et al. (2022).\n\n\n\nIntroduction\nMcCarrick et al. (2022) examined the population dynamics of Yellowstone Cutthroat Trout (Oncorhynchus clarkii bouvieri) in Henrys Lake, Idaho over a nearly two decade period. Their Figure 4 showed mean (with confidence interval) relative weight (Wr) for various length categories of Cutthroat Trout across years. I use ggplot2 to recreate that figure here.\nThe following packages are loaded for use below. A few functions from each of lubridate, FSA, plyr, scales, gghrx, lemon, and ggtext are used with :: such that the entire packages are not attached here.\n\nlibrary(tidyverse) # for dplyr, ggplot2 packages\n\nMcCarrick et al. (2022) computed what I am calling an overall PSD1 and what are called “incremental” PSD indices. I assume that these are familar to most fisheries scientists, but they are described in more detail in Chapter 8 of Ogle (2016).21 This is the most common PSD measure.2 Also see Blackwell et al. (2000).\n \n\n\nData Wrangling\n\nIndividual Fish Data Frame\nMcCarrick et al. (2022) provided raw data for Figure 2 as an Excel file in their Data Supplement S1. The same data wrangling, up to where catch-per-unit-effort was calculated, used in this previous post is used here3 and, thus, will not be discussed in detail.3 And in this post\n\ndat <- readxl::read_xlsx(\"../2023-3-22_McCarricketal2022_Fig2/download.xlsx\",\n na=c(\"\",\"??\",\"QTY =\",\"QTY=\",\"UNK\",\"NO TAG\"),\n col_types=c(\"date\",\"numeric\",\"text\",\n \"numeric\",\"numeric\",\"text\")) |>\n mutate(year=lubridate::year(Date),\n year=ifelse(year==1905,2002,year)) |>\n filter(!is.na(year)) |>\n select(species=Species,year,length,weight) |>\n mutate(species=case_when(\n species %in% c(\"YCT\",\"Yct\") ~ \"YCT\",\n species %in% c(\"UTC\",\"CHB\",\"CHUB\") ~ \"UTC\",\n TRUE ~ species\n )) |>\n filter(species %in% c(\"YCT\",\"UTC\")) |>\n mutate(species2=plyr::mapvalues(species,\n from=c(\"YCT\",\"UTC\"),\n to=c(\"Cutthroat Trout\",\"Utah Chub\"))) |>\n mutate(gcat=FSA::psdAdd(len=length,species=species2))\n\nFSA::headtail(dat)\n\n#R| species year length weight species2 gcat\n#R| 1 YCT 2002 150 NA Cutthroat Trout substock\n#R| 2 YCT 2002 160 NA Cutthroat Trout substock\n#R| 3 YCT 2002 160 NA Cutthroat Trout substock\n#R| 19900 YCT 2020 391 550 Cutthroat Trout quality\n#R| 19901 YCT 2020 284 229 Cutthroat Trout stock\n#R| 19902 YCT 2020 440 853 Cutthroat Trout quality\n\n\nThe relative weigt for each fish needs to be added to this data frame, preferably with wrAdd() from FSA. Note, however, that there are two standard weight equations for Cutthroat Trout, one for lentic and one for lotic populations. We want to make sure to use the one for lentic populations here and, thus, cannot use the species name found in the data frame within wrAdd(). Note below that the data frame was also reduced to just Cutthroat Trout for which a weight was recorded, and the two species variables were dropped (just to simplify the output).\n\ndat <- dat |>\n filter(species==\"YCT\",!is.na(weight)) |>\n mutate(wr=FSA::wrAdd(weight,length,spec=\"Cutthroat Trout (lentic)\")) |>\n select(-starts_with(\"species\"))\nFSA::headtail(dat)\n\n#R| year length weight gcat wr\n#R| 1 2004 174 54 substock 102.34315\n#R| 2 2004 227 130 stock 108.45450\n#R| 3 2004 305 380 stock 127.41903\n#R| 5208 2020 391 550 quality 85.68508\n#R| 5209 2020 284 229 stock 95.69629\n#R| 5210 2020 440 853 quality 92.31113\n\n\n\n\nWr Summary Data Frame\nSummary statistics of relative weight for all fish is computed below.\n\nwr_all <- dat |>\n group_by(year) |>\n summarize(n=n(),\n mn_wr=mean(wr,na.rm=TRUE),\n sd_wr=sd(wr,na.rm=TRUE),\n se_wr=FSA::se(wr,na.rm=TRUE))\nFSA::headtail(wr_all)\n\n#R| year n mn_wr sd_wr se_wr\n#R| 1 2004 300 116.50388 16.405045 0.9650026\n#R| 2 2005 305 103.70058 14.860984 0.8509375\n#R| 3 2006 269 107.66011 20.258635 1.2351908\n#R| 15 2018 76 107.05779 25.899713 2.9709008\n#R| 16 2019 219 97.20635 7.485436 0.5058189\n#R| 17 2020 198 94.78333 8.648857 0.6146475\n\n\nSummary statistics of relative weight for each length category is computed below.\n\nwr_gcat <- dat |>\n group_by(year,gcat) |>\n summarize(n=n(),\n mn_wr=mean(wr,na.rm=TRUE),\n sd_wr=sd(wr,na.rm=TRUE),\n se_wr=FSA::se(wr,na.rm=TRUE)) |>\n ungroup()\nFSA::headtail(wr_gcat)\n\n#R| year gcat n mn_wr sd_wr se_wr\n#R| 1 2004 substock 110 103.54857 13.477955 1.3545854\n#R| 2 2004 stock 130 123.09751 11.535665 1.0117447\n#R| 3 2004 quality 34 127.50055 12.158543 2.0851728\n#R| 68 2020 stock 52 95.40331 10.326851 1.4320766\n#R| 69 2020 quality 132 94.78427 8.119609 0.7067213\n#R| 70 2020 preferred 13 92.28008 6.826683 1.8933812\n\n\nMcCarrick et al. (2022) only plotted fish in the “stock”, “quality”, and “preferred” length categories in Figure 4; thus, only these length categories are retained below.\n\nwr_gcat <- wr_gcat |>\n filter(gcat %in% c(\"stock\",\"quality\",\"preferred\"))\n\nThe summaries for all fish and fish by length categories are row-bound (i.e., stacked) together to form an overall summary data frame. Because the data frame for all fish did not have a gcat variable, that variable will be populated with NA when the two data frames are bound. The ifelse() below converts these NA values to All, before gcat is factored with levels ordered as they would appear in Figure 4 and with more descriptive labels. Finally, for aesthetic purposes, I moved gcat to be the first variable and sorted the results by year within length category.\n\nwr_dat <- bind_rows(wr_all,wr_gcat) |>\n mutate(gcat=ifelse(is.na(gcat),\"All\",as.character(gcat)),\n gcat=factor(gcat,levels=c(\"All\",\"stock\",\"quality\",\"preferred\"),\n labels=c(\"All fish\",\"Stock to Quality\",\n \"Quality to Preferred\",\"Preferred to Memorable\"))) |>\n relocate(gcat) |>\n arrange(gcat,year)\nFSA::headtail(wr_dat)\n\n#R| gcat year n mn_wr sd_wr se_wr\n#R| 1 All fish 2004 300 116.50388 16.405045 0.9650026\n#R| 2 All fish 2005 305 103.70058 14.860984 0.8509375\n#R| 3 All fish 2006 269 107.66011 20.258635 1.2351908\n#R| 66 Preferred to Memorable 2018 22 98.79180 17.476556 3.7260144\n#R| 67 Preferred to Memorable 2019 17 98.61326 8.666677 2.1019780\n#R| 68 Preferred to Memorable 2020 13 92.28008 6.826683 1.8933812\n\n\nFinally, the lower and upper confidence intervals for each mean are added to the data frame using normal distribution theory.44 qt() returns a the 97.5th percent critical value from a t-distribution with df degrees-of-freedom.\n\nwr_dat <- wr_dat |>\n mutate(lci=mn_wr-qt(0.975,df=n-1)*se_wr,\n uci=mn_wr+qt(0.975,df=n-1)*se_wr)\nFSA::headtail(wr_dat)\n\n#R| gcat year n mn_wr sd_wr se_wr lci\n#R| 1 All fish 2004 300 116.50388 16.405045 0.9650026 114.60482\n#R| 2 All fish 2005 305 103.70058 14.860984 0.8509375 102.02610\n#R| 3 All fish 2006 269 107.66011 20.258635 1.2351908 105.22820\n#R| 66 Preferred to Memorable 2018 22 98.79180 17.476556 3.7260144 91.04313\n#R| 67 Preferred to Memorable 2019 17 98.61326 8.666677 2.1019780 94.15727\n#R| 68 Preferred to Memorable 2020 13 92.28008 6.826683 1.8933812 88.15476\n#R| uci\n#R| 1 118.4029\n#R| 2 105.3750\n#R| 3 110.0920\n#R| 66 106.5405\n#R| 67 103.0693\n#R| 68 96.4054\n\n\nThis data frame, now called wr_dat, is ready for recreating Figure 4.\n \n\n\n\nRecreating Figure 4\nFigure 4 is a simple bar plot facetted across years similar to the PSD plot in this previous post. Confidence intervals are added as described in that same post. Thus, many of the details below are not discussed further here. However, there are two new things to consider here.\nFirst, the y-axis in Figure 4 in (mccarricketal_2020?) is limited from 70 to 140. If limits=c(70,140) is used in scale_y_continuous() as described in this post the bars will be removed because their “data” extends to zero.5 Thus, the limits of the y-axis must be set with ylim= in coord_cartesian() to preserved the bars.5 Data points outside axis limits created in this way are treated as missing and are removed from the figure.\nSecond, the y-axis label in Figure 4 in (mccaricketal_2020?) is italicized with a subscript “r”. In the markdown language, asterisks are used to denoted italics and the tilde is used to create a subscript, which can be seen in name= in scale_y_continuous(). However, to make this markdown code render properly axis.title.y= in theme must be set to element_markdown() from ggtext.\n\nggplot(data=wr_dat,mapping=aes(x=year,y=mn_wr)) +\n geom_errorbar(mapping=aes(ymin=lci,ymax=uci),width=0.25) +\n geom_col(color=\"black\",fill=\"gray70\",width=1) +\n geom_text(mapping=aes(label=gcat),x=Inf,y=Inf,vjust=1.25,hjust=1.05,size=3,\n check_overlap=TRUE) +\n scale_y_continuous(name=\"*W~r~*\",expand=expansion(mult=0),\n breaks=scales::breaks_width(10)) +\n scale_x_continuous(name=\"Year\",\n limits=c(2000,2022),breaks=scales::breaks_width(2),\n expand=expansion(mult=0)) +\n coord_cartesian(ylim=c(70,140)) +\n lemon::facet_rep_wrap(vars(gcat),ncol=1) +\n theme_bw() +\n theme(panel.grid=element_blank(),\n strip.background=element_blank(),\n strip.text=element_blank(),\n axis.title.y=ggtext::element_markdown())\n\n\n\n\n\n\n\n\n \n\n\nFurther Thoughts\n\nPoint-and-Lines Plot\nAs mentioned in this previous post I understand that these are the much derided “dynamite plots”. Personally, I find the bars distracting (so much gray with little purpose and starting at 70) and find a point-and-lines plot, possibly with a horizontal line at the common reference value of 100.\n\nggplot(data=wr_dat,mapping=aes(x=year,y=mn_wr)) +\n geom_errorbar(mapping=aes(ymin=lci,ymax=uci),width=0.25) +\n geom_line(linewidth=0.75,color=\"gray70\") +\n geom_point(size=1) +\n geom_hline(yintercept=100,color=\"gray30\",linetype=\"dashed\",linewidth=0.5) +\n geom_text(mapping=aes(label=gcat),x=Inf,y=Inf,vjust=1.25,hjust=1.05,size=3,\n check_overlap=TRUE) +\n scale_y_continuous(name=\"*W~r~*\",limits=c(70,140),expand=expansion(mult=0),\n breaks=scales::breaks_width(10)) +\n scale_x_continuous(name=\"Year\",\n limits=c(2000,2022),breaks=scales::breaks_width(2),\n expand=expansion(mult=0)) +\n lemon::facet_rep_wrap(vars(gcat),ncol=1) +\n theme_bw() +\n theme(panel.grid=element_blank(),\n strip.background=element_blank(),\n strip.text=element_blank(),\n axis.title.y=ggtext::element_markdown())\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n\n\n\nReferences\n\nBlackwell, B., M. Brown, and D. Willis. 2000. Relative Weight (Wr) Status and Current Use in Fisheries Assessment and Management. Reviews in Fisheries Science 8:1–44.\n\n\nMcCarrick, D. K., J. C. Dillon, B. High, and M. C. Quist. 2022. Population dynamics of Yellowstone Cutthroat Trout in Henrys Lake, Idaho. Journal of Fish and Wildlife Management 13(1):169–181.\n\n\nOgle, D. H. 2016. Introductory Fisheries Analyses with R. CRC Press, Boca Raton, FL.\n\nReusehttps://creativecommons.org/licenses/by/4.0/CitationBibTeX citation:@online{h.ogle2023,\n author = {Derek H. Ogle},\n title = {McCarrick Et Al. (2022) {Wr} {Plot}},\n date = {2023-03-26},\n url = {https://fishr-core-team.github.io/fishR//blog/posts/2023-3-26_McCarricketal2022_Fig4},\n langid = {en}\n}\nFor attribution, please cite this work as:\nDerek H. Ogle. 2023, March 26. McCarrick et al. (2022) Wr Plot. https://fishr-core-team.github.io/fishR//blog/posts/2023-3-26_McCarricketal2022_Fig4." + }, + { + "objectID": "blog/posts/2023-3-27_McCarricketal2022_Fig5/index.html", + "href": "blog/posts/2023-3-27_McCarricketal2022_Fig5/index.html", + "title": "McCarrick et al. (2022) Age Composition Plot", + "section": "", + "text": "Series Note\n\n\n\nThis is the fourth of several posts related to McCarrick et al. (2022).\n\n\n\nIntroduction\nMcCarrick et al. (2022) examined the population dynamics of Yellowstone Cutthroat Trout (Oncorhynchus clarkii bouvieri) in Henrys Lake, Idaho over a nearly two decade period. Their Figure 5 showed the relative age composition of Cutthroat Trout across years. I use ggplot2 to recreate that figure here.\nThe following packages are loaded for use below. A few functions from each of FSA, plyr, lemon, and forcats are used with :: such that the entire packages are not attached here.\n\nlibrary(tidyverse) # for dplyr, ggplot2 packages\n\n \n\n\nData Wrangling\nMcCarrick et al. (2022) provided raw data for Figure 2 in a MSWord table as a supplement. I copied the table from Word, pasted it into Excel, and saved it for loading here.\n\ndat <- readxl::read_xlsx(\"YCT_AgeComp.xlsx\")\ndat\n\n#R| # A tibble: 19 × 12\n#R| Year `Age 1` `Age 2` `Age 3` `Age 4` `Age 5` `Age 6` `Age 7` `Age 8` `Age 9`\n#R| \n#R| 1 2002 0.113 0.46 0.394 0.034 0 0 0 0 0 \n#R| 2 2003 0.207 0.207 0.194 0.289 0.058 0.025 0 0 0.019\n#R| 3 2004 0.39 0.472 0.084 0.034 0.003 0.007 0.007 0.003 0 \n#R| 4 2005 0.368 0.527 0.078 0.015 0.013 0 0 0 0 \n#R| 5 2006 0.091 0.276 0.52 0.107 0.002 0.004 0 0 0 \n#R| 6 2007 0.025 0.708 0.13 0.128 0.009 0 0 0 0 \n#R| 7 2008 0 0.536 0.298 0.146 0.021 0 0 0 0 \n#R| 8 2009 0.051 0.27 0.502 0.177 0 0 0 0 0 \n#R| 9 2010 0.028 0.753 0.092 0.116 0.008 0.003 0 0 0 \n#R| 10 2011 0.003 0.774 0.187 0.029 0.005 0.003 0 0 0 \n#R| 11 2012 0.017 0.594 0.348 0.029 0.004 0.006 0 0 0 \n#R| 12 2013 0.004 0.61 0.22 0.14 0.02 0.002 0.004 0 0 \n#R| 13 2014 0.007 0.353 0.437 0.136 0.05 0.013 0.002 0.002 0 \n#R| 14 2015 0.021 0.399 0.239 0.271 0.031 0.04 0 0 0 \n#R| 15 2016 0 0.594 0.238 0.082 0.053 0.033 0 0 0 \n#R| 16 2017 0.02 0.518 0.197 0.197 0.027 0.035 0 0.007 0 \n#R| 17 2018 0.053 0.137 0.505 0.148 0.101 0.013 0.031 0.013 0 \n#R| 18 2019 0.013 0.765 0.127 0.037 0.027 0.014 0.004 0.013 0 \n#R| 19 2020 0.005 0.206 0.677 0.096 0.003 0.005 0.005 0.002 0 \n#R| # … with 2 more variables: `Age 10` , `Age 11` \n\n\nThe data were provided in a wide format that needs to be “tidied” to a long format with the proportions at age in the Age X columns stacked on top of each other with a corresponding variable that indicates the age. Note that the columns to pivot in cols= were selected by ignoring year and, thus, leaving all of the Age X columns.11 The columns also could have been selected with starts_with(\"Age\"), among other possibilities.\n\ndat <- dat |>\n pivot_longer(cols=-Year,names_to=\"Age\",values_to=\"Proportion\")\nFSA::headtail(dat)\n\n#R| Year Age Proportion\n#R| 1 2002 Age 1 0.113\n#R| 2 2002 Age 2 0.460\n#R| 3 2002 Age 3 0.394\n#R| 207 2020 Age 9 0.000\n#R| 208 2020 Age 10 0.001\n#R| 209 2020 Age 11 0.000\n\n\nThe Age variable should be converted to a factor so that the levels can be controlled, otherwise “Age 10” will follow “Age 1”.\n\ndat <- dat |>\n mutate(Age=factor(Age,levels=c(\"Age 1\",\"Age 2\",\"Age 3\",\"Age 4\",\"Age 5\",\"Age 6\",\n \"Age 7\",\"Age 8\",\"Age 9\",\"Age 10\",\"Age 11\")))\n\nThis data frame is ready for recreating Figure 5.\n \n\n\nRecreating Figure 5\nFigure 5 is an “area plot” which is easily constructed in ggplot2 with geom_area(), with the variable that defines the colored areas (i.e., Age) mapped to fill=.22 I plotted every other on the x-axis as the font needed to be so small to show every year at in McCarrick et al. (2022).\n\nggplot(data=dat,mapping=aes(x=Year,y=Proportion,fill=Age)) +\n geom_area() +\n scale_y_continuous(expand=expansion(mult=0),\n breaks=scales::breaks_width(0.1)) +\n scale_x_continuous(expand=expansion(mult=0),\n limits=c(2002,2020),breaks=scales::breaks_width(2)) +\n theme_bw() +\n theme(panel.grid=element_blank())\n\n\n\n\n\n\n\n\nI won’t address color here (but see further below) as these colors are no uglier than what is shown in the published Figure 5. However, there are other adjustments that need to be made to match Figure 5.\nFirst, the ages above are stacked opposite of what is in Figure 5; i.e., age-1 is at the top, age-2 below that, etc. rather than age-1 at the bottom, age-2 on top of that, etc. The order of stacking is reversed with position= in geom_area() as shown below. Second, the authors included two digits for the values on the y-axis for some reason. Assuming this behavior is desired it can be obtained with scales::label_number() in scale_y_continuous() as shown below.33 This was demonstrated in this post.\n\nggplot(data=dat,mapping=aes(x=Year,y=Proportion,fill=Age)) +\n geom_area(position=position_stack(reverse=TRUE)) +\n scale_y_continuous(expand=expansion(mult=0),\n breaks=scales::breaks_width(0.1),\n label=scales::label_number(0.01)) +\n scale_x_continuous(expand=expansion(mult=0),\n limits=c(2002,2020),breaks=scales::breaks_width(2)) +\n theme_bw() +\n theme(panel.grid=element_blank())\n\n\n\n\n\n\n\n\nThird, the legend needs to be moved to below the x-axis. This is easily accomplished with legend.position=\"bottom\" in theme(). However, doing this alone shows the legend in three rows. One row was used for the legend as shown below with guides(). Finally, other theme options were altered to remove the legend title and make the legend symbols and text smaller.\n\nggplot(data=dat,mapping=aes(x=Year,y=Proportion,fill=Age)) +\n geom_area(position=position_stack(reverse=TRUE)) +\n scale_y_continuous(expand=expansion(mult=0),\n breaks=scales::breaks_width(0.1),\n label=scales::label_number(0.01)) +\n scale_x_continuous(expand=expansion(mult=0),\n limits=c(2002,2020),breaks=scales::breaks_width(2)) +\n guides(fill=guide_legend(nrow=1)) +\n theme_bw() +\n theme(panel.grid=element_blank(),\n legend.position=\"bottom\",\n legend.title=element_blank(),\n legend.key.size=unit(2,\"mm\"),\n legend.text=element_text(size=7))\n\n\n\n\n\n\n\n\nThis largely recreates Figure 5 in McCarrick et al. (2022).\n \n\n\nPossible Modifications\nArea plots are notorious for being difficult for readers to interpret.4 Below I offer some modifications that may(?) aid interpretation.4 See this for example.\n\nLump Ages\nMany potential ages are shown in Figure 5 though ages greater than age-5 are rarely visible (or noticeable) as they never represent more than 10% in total or 4% individually of the fish in any given year.\n\n# Find maximum proportion by age, is that more than 5%\ndat |> group_by(Age) |> summarize(maxP=max(Proportion))\n\n#R| # A tibble: 11 × 2\n#R| Age maxP\n#R| \n#R| 1 Age 1 0.39 \n#R| 2 Age 2 0.774\n#R| 3 Age 3 0.677\n#R| 4 Age 4 0.289\n#R| 5 Age 5 0.101\n#R| 6 Age 6 0.04 \n#R| 7 Age 7 0.031\n#R| 8 Age 8 0.013\n#R| 9 Age 9 0.019\n#R| 10 Age 10 0.002\n#R| 11 Age 11 0.001\n\n\nThe number of colors used in the plot, and the number of areas that the reader looks for, can be reduced by lumping together ages that are not well-represented in the data. Below fct_collapse() from forcats is used to collapse the “Age 6” to “Age 11” levels in Age to one level called “Age 6+”. To preserve the original data this data frame was called dat2.\n\ndat2 <- dat |>\n mutate(Age=forcats::fct_collapse(Age,`Age 6+`=c(\"Age 6\",\"Age 7\",\"Age 7\",\"Age 8\",\n \"Age 9\",\"Age 10\",\"Age 11\")))\nFSA::headtail(dat2)\n\n#R| Year Age Proportion\n#R| 1 2002 Age 1 0.113\n#R| 2 2002 Age 2 0.460\n#R| 3 2002 Age 3 0.394\n#R| 207 2020 Age 6+ 0.000\n#R| 208 2020 Age 6+ 0.001\n#R| 209 2020 Age 6+ 0.000\n\n\nHowever, “Age 6+” was simply repeated for the original “Age 6”, “Age 7”, etc. The proportions for these ages should be summed, within each year, to get a proper proportion of “Age 6+” fish.55 Summing the proportions for the ages that were lumped will just return the proportion for those ages.\n\ndat2 <- dat2 |>\n group_by(Year,Age) |>\n summarize(Proportion=sum(Proportion)) |>\n ungroup()\nFSA::headtail(dat2)\n\n#R| Year Age Proportion\n#R| 1 2002 Age 1 0.113\n#R| 2 2002 Age 2 0.460\n#R| 3 2002 Age 3 0.394\n#R| 112 2020 Age 4 0.096\n#R| 113 2020 Age 5 0.003\n#R| 114 2020 Age 6+ 0.013\n\n\nTo save some typing below, I set the theme to the theme items above with the exception that I moved the legend back to the right where I think it is more appropriate.\n\ntheme_set(\n theme_bw() +\n theme(panel.grid=element_blank(),\n legend.title=element_blank(),\n legend.key.size=unit(3,\"mm\"),\n legend.text=element_text(size=8))\n)\n\nThe code for Figure 5 is largely repeated below with these data. However, I reversed the order of the labels in the legend with guides() so that the labels more naturally followed how the areas were plotted and I removed the unnecessary extra digit in the y-axis labels.\n\nggplot(data=dat2,mapping=aes(x=Year,y=Proportion,fill=Age)) +\n geom_area(position=position_stack(reverse=TRUE)) +\n scale_y_continuous(expand=expansion(mult=0),\n breaks=scales::breaks_width(0.1)) +\n scale_x_continuous(expand=expansion(mult=0),\n limits=c(2002,2020),breaks=scales::breaks_width(2)) +\n guides(fill=guide_legend(reverse=TRUE))\n\n\n\n\n\n\n\n\n\n\nColor\nChanging the color is not necessarily going to make the figure easier to interpret. However, a gradient of color can be used to more clearly represent the gradient of age. Here, I form a gradient of grays with scale_fill_grey().\n\nggplot(data=dat2,mapping=aes(x=Year,y=Proportion,fill=Age)) +\n geom_area(position=position_stack(reverse=TRUE)) +\n scale_y_continuous(expand=expansion(mult=0),\n breaks=scales::breaks_width(0.1)) +\n scale_x_continuous(expand=expansion(mult=0),\n limits=c(2002,2020),breaks=scales::breaks_width(2)) +\n scale_fill_grey(start=0.2,end=0.8) +\n guides(fill=guide_legend(reverse=TRUE))\n\n\n\n\n\n\n\n\nA sequential palette that ranges from dark green to light blue is used below with scale_fill_brewer(). A variety of palettes may be chosen in this function as described in its documentation. Note that direction=-1 was used here to reverse the palette order as I preferred the darker colors for age-1 and the lighter colors for age-6+.\n\nggplot(data=dat2,mapping=aes(x=Year,y=Proportion,fill=Age)) +\n geom_area(position=position_stack(reverse=TRUE)) +\n scale_y_continuous(expand=expansion(mult=0),\n breaks=scales::breaks_width(0.1)) +\n scale_x_continuous(expand=expansion(mult=0),\n limits=c(2002,2020),breaks=scales::breaks_width(2)) +\n scale_fill_brewer(palette=\"BuGn\",direction=-1) +\n guides(fill=guide_legend(reverse=TRUE))\n\n\n\n\n\n\n\n\nOther palette algorithms can also be used. Below, scale_fill_viridis_d() is used as an example.\n\nggplot(data=dat2,mapping=aes(x=Year,y=Proportion,fill=Age)) +\n geom_area(position=position_stack(reverse=TRUE)) +\n scale_y_continuous(expand=expansion(mult=0),\n breaks=scales::breaks_width(0.1)) +\n scale_x_continuous(expand=expansion(mult=0),\n limits=c(2002,2020),breaks=scales::breaks_width(2)) +\n scale_fill_viridis_d(begin=0.25,end=0.9) +\n guides(fill=guide_legend(reverse=TRUE))\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nTip\n\n\n\nThere is both an art and a science behind choosing colors for plots. Unfortunately, I am not strong nor fully knowledgeable in either. Thus, I show how to alter colors here, but I don’t claim that these choices are ideal.\n\n\n\n\nAdd Lines\nI sometimes feel that the colors in area plots “run together” in my eyes. One way to make more clear “breaks” is to highlight the color changes. Below I also map Age to color=, use scale_color_viridis_d() with the same options as scale_fill_viridis_d(), except that for the fill I set a slight transparency with alpha=. Here color= is used for the boundaries of the areas and since the fill was made transparent these boundaries are a bit darker and, thus, appear as lines between the areas. Further note that both fill= and color= had to be “reversed” in guides().\n\nggplot(data=dat2,mapping=aes(x=Year,y=Proportion,fill=Age,color=Age)) +\n geom_area(position=position_stack(reverse=TRUE),linewidth=0.75) +\n scale_y_continuous(expand=expansion(mult=0),\n breaks=scales::breaks_width(0.1)) +\n scale_x_continuous(expand=expansion(mult=0),\n limits=c(2002,2020),breaks=scales::breaks_width(2)) +\n scale_color_viridis_d(begin=0.25,end=0.9) +\n scale_fill_viridis_d(begin=0.25,end=0.9,alpha=0.75) +\n guides(fill=guide_legend(reverse=TRUE),\n color=guide_legend(reverse=TRUE))\n\n\n\n\n\n\n\n\n\n\nBar Chart\nMost people that eschew the use of area plots suggests using bar charts instead. This is easily accomplished here by replacing geom_area() with geom_col(). However, the limits of the x-axis will need to be extended by one year on both sides so that the first and last year will be shown correctly.\n\nggplot(data=dat2,mapping=aes(x=Year,y=Proportion,fill=Age)) +\n geom_col(position=position_stack(reverse=TRUE)) +\n scale_y_continuous(expand=expansion(mult=0),\n breaks=scales::breaks_width(0.1)) +\n scale_x_continuous(expand=expansion(mult=0),\n limits=c(2001,2021),breaks=scales::breaks_width(2)) +\n scale_fill_viridis_d(begin=0.25,end=0.9) +\n guides(fill=guide_legend(reverse=TRUE))\n\n\n\n\n\n\n\n\n\n\nFacets\nFinally, I think that if the goal is to show annular trends for the specific ages, that they should be plotted as lines for each age. Here lines are used with geom_line() and faceting was used on Age. The use of color is superfluous here, but I kept it for comparing with the previous options.\n\nggplot(data=dat2,mapping=aes(x=Year,y=Proportion,color=Age)) +\n geom_line(linewidth=0.75) +\n scale_y_continuous(expand=expansion(mult=c(0,0.025)),\n breaks=scales::breaks_width(0.1)) +\n scale_x_continuous(expand=expansion(mult=0),\n limits=c(2002,2020),breaks=scales::breaks_width(2)) +\n scale_color_viridis_d(begin=0.25,end=0.9) +\n lemon::facet_rep_wrap(vars(Age),ncol=1,strip.position=\"right\") +\n theme(legend.position=\"none\")\n\n\n\n\n\n\n\n\nIn my view, it is much easier to decipher what is going on with age-2 to age-4 fish from this plot.\n \n\n\n\n\n\n\n\n\n\n\nReferences\n\nMcCarrick, D. K., J. C. Dillon, B. High, and M. C. Quist. 2022. Population dynamics of Yellowstone Cutthroat Trout in Henrys Lake, Idaho. Journal of Fish and Wildlife Management 13(1):169–181.\n\nReusehttps://creativecommons.org/licenses/by/4.0/CitationBibTeX citation:@online{h.ogle2023,\n author = {Derek H. Ogle},\n title = {McCarrick Et Al. (2022) {Age} {Composition} {Plot}},\n date = {2023-03-27},\n url = {https://fishr-core-team.github.io/fishR//blog/posts/2023-3-27_McCarricketal2022_Fig5},\n langid = {en}\n}\nFor attribution, please cite this work as:\nDerek H. Ogle. 2023, March 27. McCarrick et al. (2022) Age Composition\nPlot. https://fishr-core-team.github.io/fishR//blog/posts/2023-3-27_McCarricketal2022_Fig5." + }, { "objectID": "blog/posts/2023-3-6_Landryetal2022_LogRegress/index.html", "href": "blog/posts/2023-3-6_Landryetal2022_LogRegress/index.html", @@ -880,40 +908,5 @@ "title": "Yellow Perch Harvest Summaries", "section": "", "text": "Table 1: Frequency, percent, and reverse cumulative sum of percent of anglers by number of Yellow Perch harvested. \n \n \n Harvested \n Frequency \n % \n Reverse Cum % \n \n \n\n \n 0 \n 277 \n 17.2% \n 100.0% \n \n \n 10 \n 920 \n 57.0% \n 82.8% \n \n \n 20 \n 244 \n 15.1% \n 25.9% \n \n \n 30 \n 87 \n 5.4% \n 10.8% \n \n \n 40 \n 44 \n 2.7% \n 5.4% \n \n \n 50 \n 26 \n 1.6% \n 2.7% \n \n \n 60 \n 5 \n 0.3% \n 1.1% \n \n \n 70 \n 2 \n 0.1% \n 0.7% \n \n \n 80 \n 3 \n 0.2% \n 0.6% \n \n \n 90 \n 2 \n 0.1% \n 0.4% \n \n \n 100 \n 5 \n 0.3% \n 0.3% \n \n\n\n\n\n\n\n \n\n\n\n\n\nFigure 1: Percentage (left) and reverse cumulative percentage (right) of anglers by number of Yellow Perch harvested." - }, - { - "objectID": "blog/posts/2023-3-22_McCarricketal2022_Fig2/index.html", - "href": "blog/posts/2023-3-22_McCarricketal2022_Fig2/index.html", - "title": "McCarrick et al. (2022) CPE Plot", - "section": "", - "text": "Series Note\n\n\n\nThis is the first of several posts related to McCarrick et al. (2022).\n\n\n\nIntroduction\nMcCarrick et al. (2022) examined the population dynamics of Yellowstone Cutthroat Trout (Oncorhynchus clarkii bouvieri) in Henrys Lake, Idaho over a nearly two decade period. Their Figure 2 shows the catch-per-unit-effort (CPE) of both Cutthroat Trout and Utah Chub (Gila atraria) by size categories across years. I use ggplot2 to recreate that figure here.\nThe following packages are loaded for use below. A few functions from each of lubridate, FSA, plyr, scales, gghrx, and lemon are used with :: such that the entire packages are not attached here.\n\nlibrary(tidyverse) # for dplyr, ggplot2 packages\nlibrary(patchwork) # for arranging multiple plots\n\n\n\n\n\n\n\nNote\n\n\n\nYou will see below that I could recreate the structure but not the exact results of the author’s Figure 2. This may be due to issues present in the data provided with the publication that I discuss below, but it could also be that my data wrangling differs from theirs. I defer to the authors here as they are the experts with their day; I am just an interloper. I actually appreciate these data issues from an educational perspective as they provide rich opportunities to demonstrate a variety of techniques with “real” “messy” data.\n\n\n \n\n\nData Wrangling\n\nReading Excel File and Handling Dates\nMcCarrick et al. (2022) provided raw data for Figure 2 as an Excel file in their Data Supplement S1. Several “issues” were apparent on my first attempts to load these data.\n\nMissing data was recorded as missing cells, with “??”, and with “UNK”.\nThere were oddly placed strings in some data fields (e.g., “Qty=”, “Qty =”, and “No Tag”). [I treated these as missing data below.]\nDates were recorded as just year, full date with two-digit year, and full date with four-digit year. [More on this below.]\nInconsistent “species” abbreviations. [More on this below.]\nIncorrect length and weight measurements (e.g., <10 mm, >2000 mm). [I treated these “as is” (i.e., without correction) for this post.]\n\nThe missing data and oddly named cells were handled with na= below. In addition, the column types were specifically defined in col_types=, primarily so that the first column would be largely correctly read as a date. The year was then extracted from the Date variable using year() from lubridate. However, the dates recorded in the original file as only a year were interpreted as an “Excel date code” rather than a date and, thus, the year was not extracted correctly. Fortunately, this “date” format was only used for one year (2002) such that the extracted year was consistently “1905.” Thus, the “1905” was replaced with “2002” for the extracted year with ifelse() as shown below. Several years did not exist (because the date was not recorded) and were removed with filter(). Finally, the variables were rearranged slightly, Species was changed to species for consistency with other variables, and the long effort variable was changed to the shorter netNights.11 Note that this code still produced a large number of warnings, all related to the “2002” “date”.\n\ndat <- readxl::read_xlsx(\"download.xlsx\",\n na=c(\"\",\"??\",\"QTY =\",\"QTY=\",\"UNK\",\"NO TAG\"),\n col_types=c(\"date\",\"numeric\",\"text\",\n \"numeric\",\"numeric\",\"text\")) |>\n mutate(year=lubridate::year(Date),\n year=ifelse(year==1905,2002,year)) |>\n filter(!is.na(year)) |>\n select(species=Species,year,length,weight,netNights=`number of net nights`)\nFSA::headtail(dat)\n\n#R| species year length weight netNights\n#R| 1 YCT 2002 150 NA 18\n#R| 2 YCT 2002 160 NA 18\n#R| 3 YCT 2002 160 NA 18\n#R| 23971 YCT 2020 391 550 30\n#R| 23972 YCT 2020 284 229 30\n#R| 23973 YCT 2020 440 853 30\n\n\n\n\nNew Effort Data Frame\nThe effort (i.e., netNights) variable seems out-of-place in the sense that each row of this data frame is a single fish. I suspected that this effort is actually for a year and was repeated for each fish captured in the same year. To examine my suspicion, I computed the minimum and maximum effort (and the difference between the two) for each year.\n\ndat |>\n group_by(year) |>\n summarize(minF=min(netNights,na.rm=TRUE),\n maxF=max(netNights,na.rm=TRUE),\n diff=maxF-minF)\n\n#R| # A tibble: 19 × 4\n#R| year minF maxF diff\n#R| \n#R| 1 2002 18 18 0\n#R| 2 2003 18 18 0\n#R| 3 2004 50 50 0\n#R| 4 2005 46 46 0\n#R| 5 2006 48 48 0\n#R| 6 2007 44 44 0\n#R| 7 2008 12 12 0\n#R| 8 2009 23 23 0\n#R| 9 2010 50 50 0\n#R| 10 2011 30 30 0\n#R| 11 2012 50 50 0\n#R| 12 2013 50 50 0\n#R| 13 2014 48 48 0\n#R| 14 2015 50 50 0\n#R| 15 2016 48 48 0\n#R| 16 2017 50 50 0\n#R| 17 2018 50 50 0\n#R| 18 2019 50 50 0\n#R| 19 2020 30 50 20\n\n\nThe minimum and maximum efforts are the same for each, with the exception of 2020. I suspect that this is a typo. A quick table of efforts for 2020 shows that the vast majority are 30, rather than 50, net-nights. Further, my initial analysis with these data resulted in CPE values for 2020 that were lower than what was shown in McCarrick et al. (2022). Thus, I am going to assume that 30 net-nights of effort was used in 2020 (see how this is corrected below).\n\nxtabs(~netNights,data=filter(dat,year==2020))\n\n#R| netNights\n#R| 30 50 \n#R| 865 9\n\n\nFor my purposes, I am going to create a new data frame of annual levels of effort by finding the minimum netNights in each year. The minimum is used here because it is the actual effort for all years that properly had a constant netNights entered and it is the assumed correct netNights for 2020 when a constant value was not entered.\n\neff <- dat |>\n group_by(year) |>\n summarize(netNights=min(netNights,na.rm=TRUE))\neff\n\n#R| # A tibble: 19 × 2\n#R| year netNights\n#R| \n#R| 1 2002 18\n#R| 2 2003 18\n#R| 3 2004 50\n#R| 4 2005 46\n#R| 5 2006 48\n#R| 6 2007 44\n#R| 7 2008 12\n#R| 8 2009 23\n#R| 9 2010 50\n#R| 10 2011 30\n#R| 11 2012 50\n#R| 12 2013 50\n#R| 13 2014 48\n#R| 14 2015 50\n#R| 15 2016 48\n#R| 16 2017 50\n#R| 17 2018 50\n#R| 18 2019 50\n#R| 19 2020 30\n\n\nThe netNights variables is no longer needed in the individual fish data frame.\n\ndat <- dat |>\n select(-netNights)\n\n\n\nFiltering to Two Species\nFigure 2 in McCarrick et al. (2022) only displays results for Cutthroat Trout and Utah Chub. Thus, the data frame should be reduced to just these species. First, a look at how species are identified.\n\nunique(dat$species)\n\n#R| [1] \"YCT\" \"BKT\" \"HYB\" \"CHB\" \"RSS\" \"UTC\" \"KOK\" \n#R| [8] \"BRT\" \"CHUB\" NA \"HB\" \"Yct\" \"NO FISH\" \"SCU\"\n\n\nFrom the published paper it is apparent that “YCT” is for Yellowstone Cutthroat Trout and “UTC” is for Utah Chub. But note the “Yct” and the “CHB” and “CHUB”. A little closer look at just these abbreviations by year suggests that “Yct” is a “one-off” typo, but that “CHB” and “CHUB” appeared to be used in some years when “UTC” was mostly not used. This suggested to me that “CHB” and “CHUB” were likely synonyms for “UTC”.\n\nxtabs(~year+species,data=filter(dat,species %in% c(\"YCT\",\"Yct\",\"UTC\",\"CHB\",\"CHUB\")))\n\n#R| species\n#R| year CHB CHUB UTC Yct YCT\n#R| 2002 0 0 0 0 55\n#R| 2003 84 0 2 0 162\n#R| 2004 0 0 728 0 323\n#R| 2005 0 0 294 0 305\n#R| 2006 0 0 424 0 269\n#R| 2007 0 0 895 0 658\n#R| 2008 0 606 0 0 100\n#R| 2009 0 0 512 0 91\n#R| 2010 0 0 0 0 502\n#R| 2011 0 440 0 0 374\n#R| 2012 0 0 692 0 500\n#R| 2013 0 0 1858 0 478\n#R| 2014 0 0 1767 1 475\n#R| 2015 0 0 1660 0 254\n#R| 2016 0 0 1078 0 265\n#R| 2017 0 0 1025 0 149\n#R| 2018 0 0 1273 0 76\n#R| 2019 0 0 696 0 219\n#R| 2020 0 0 414 0 198\n\n\nThus, species is modified below by combining “YCT” and “Yct” into “YCT”, and combining “UTC”, “CHB”, and “CHUB” into “UTC”.2 The data frame was subsequently reduced to just these two species.2 And leaving all other species “names” as-is.\n\ndat <- dat |>\n mutate(species=case_when(\n species %in% c(\"YCT\",\"Yct\") ~ \"YCT\",\n species %in% c(\"UTC\",\"CHB\",\"CHUB\") ~ \"UTC\",\n TRUE ~ species\n )\n ) |>\n filter(species %in% c(\"YCT\",\"UTC\"))\n\n# just checking\nunique(dat$species)\n\n#R| [1] \"YCT\" \"UTC\"\n\n\n\n\nAdding Gabelhouse Length Categories\nFigure 2 separates the data into panels based on Gabelhouse length categories (i.e., “Stock”, “Quality”, etc.). These categories can be efficiently added to the data frame using psdAdd() from FSA, but psdAdd() requires full species names rather than abbreviations. mapvalues() from plyr is used below to create a new variable with the full names derived from the abbreviations.\n\ndat <- dat |>\n mutate(species2=plyr::mapvalues(species,\n from=c(\"YCT\",\"UTC\"),\n to=c(\"Cutthroat Trout\",\"Utah Chub\")))\n# just checking\nxtabs(~species+species2,data=dat)\n\n#R| species2\n#R| species Cutthroat Trout Utah Chub\n#R| UTC 0 14448\n#R| YCT 5454 0\n\n\nNow the length categories may be added using species2.\n\ndat <- dat |>\n mutate(gcat=FSA::psdAdd(len=length,species=species2))\nFSA::headtail(dat)\n\n#R| species year length weight species2 gcat\n#R| 1 YCT 2002 150 NA Cutthroat Trout substock\n#R| 2 YCT 2002 160 NA Cutthroat Trout substock\n#R| 3 YCT 2002 160 NA Cutthroat Trout substock\n#R| 19900 YCT 2020 391 550 Cutthroat Trout quality\n#R| 19901 YCT 2020 284 229 Cutthroat Trout stock\n#R| 19902 YCT 2020 440 853 Cutthroat Trout quality\n\n\n\n\nComputing CPE\nFrom this, the data needs to be summarized to produce the CPE for each species for each year for each length category and for all fish regardless of length category. Development of this data frame will begin by counting the number of fish (i.e., rows) for each length category within each year within each species.\n\ncatch_gcat <- dat |>\n group_by(species,year,gcat) |>\n summarize(catch=n())\ncatch_gcat\n\n#R| # A tibble: 162 × 4\n#R| # Groups: species, year [36]\n#R| species year gcat catch\n#R| \n#R| 1 UTC 2003 substock 5\n#R| 2 UTC 2003 stock 41\n#R| 3 UTC 2003 quality 21\n#R| 4 UTC 2003 preferred 15\n#R| 5 UTC 2003 memorable 4\n#R| 6 UTC 2004 substock 2\n#R| 7 UTC 2004 stock 535\n#R| 8 UTC 2004 quality 128\n#R| 9 UTC 2004 preferred 52\n#R| 10 UTC 2004 memorable 11\n#R| # … with 152 more rows\n\n\nNote in the previous output that catch_gcat is still “grouped” by year within species. Thus, catch can summed from this data frame to find the total catch per year for each species.33 Ungroup this data frame as we will not summarize it further.\n\ncatch_all <- catch_gcat |>\n summarize(catch=sum(catch)) |>\n ungroup()\ncatch_all\n\n#R| # A tibble: 36 × 3\n#R| species year catch\n#R| \n#R| 1 UTC 2003 86\n#R| 2 UTC 2004 728\n#R| 3 UTC 2005 294\n#R| 4 UTC 2006 424\n#R| 5 UTC 2007 895\n#R| 6 UTC 2008 606\n#R| 7 UTC 2009 512\n#R| 8 UTC 2011 440\n#R| 9 UTC 2012 692\n#R| 10 UTC 2013 1858\n#R| # … with 26 more rows\n\n\nAs Figure 2 displays all fish and fish by length category, these two data frames should be row-bound (i.e., stacked) together. Figure 2 does not have panels for “substock”, “memorable”, or “trophy” sized fish so fish in those length categories were removed from the resultant data frame. Finally, a new variable called type was created that has the names from gcat, or “All” if gcat was NA4.4 gcat for “all fish” after bind_rows() was NA as gcat was not present in catch_all\n\ncpe_dat <- bind_rows(catch_all,catch_gcat) |>\n filter(!(gcat %in% c(\"substock\",\"memorable\",\"trophy\"))) |>\n mutate(type=ifelse(is.na(gcat),\"All\",as.character(gcat)))\nFSA::headtail(cpe_dat)\n\n#R| species year catch gcat type\n#R| 1 UTC 2003 86 All\n#R| 2 UTC 2004 728 All\n#R| 3 UTC 2005 294 All\n#R| 143 YCT 2020 52 stock stock\n#R| 144 YCT 2020 132 quality quality\n#R| 145 YCT 2020 13 preferred preferred\n\n\nFinally, these data are left-join()ed (by year) with eff to add netNights, from which a new cpe variable is created. type was converted to a factor to match the vertical order of Figure 2, and the levels were given longer labels to match the labels in Figure 2. Finally, the variables were re-ordered (and gcat was dropped) for personal preference.\n\ncpe_dat <- cpe_dat |>\n left_join(eff,by=\"year\") |>\n mutate(cpe=catch/netNights,\n type=factor(type,levels=c(\"All\",\"stock\",\"quality\",\"preferred\"),\n labels=c(\"All fish\",\"Stock to Quality\",\n \"Quality to Preferred\",\"Preferred to Memorable\"))) |>\n select(species,year,type,catch,netNights,cpe)\nFSA::headtail(cpe_dat)\n\n#R| species year type catch netNights cpe\n#R| 1 UTC 2003 All fish 86 18 4.7777778\n#R| 2 UTC 2004 All fish 728 50 14.5600000\n#R| 3 UTC 2005 All fish 294 46 6.3913043\n#R| 143 YCT 2020 Stock to Quality 52 30 1.7333333\n#R| 144 YCT 2020 Quality to Preferred 132 30 4.4000000\n#R| 145 YCT 2020 Preferred to Memorable 13 30 0.4333333\n\n\nThis data frame, now called cpe_dat, is now ready for recreating Figure 2.\n\n\nQuick Summaries of CPE\nBefore recreating Figure 2, I summarized the CPE data by species and year for comparison to results in McCarrick et al. (2022).\n\ncpe_dat |>\n filter(type==\"All fish\") |>\n group_by(species) |>\n summarize(n=n(),\n ttlcatch=sum(catch),\n mncpe=mean(cpe),\n sdcpe=sd(cpe),\n mincpe=min(cpe),\n minyr=year[cpe==mincpe],\n maxcpe=max(cpe),\n maxyr=year[cpe==maxcpe])\n\n#R| # A tibble: 2 × 9\n#R| species n ttlcatch mncpe sdcpe mincpe minyr maxcpe maxyr\n#R| \n#R| 1 UTC 18 14459 20.0 12.9 0.239 2005 50.5 2008\n#R| 2 YCT 19 5454 7.16 3.48 1.52 2018 15.0 2007\n\n\nIn the first paragraph of the results, McCarrick et al. (2022) found the overall mean (and SD) CPE was 7.4 (3.6) for YCT and 19.9 (13.0) for UTC, which is close to what I obtained for UTC but not for YTC. In addition, they found a peak CPE of 15.4 for YCT in 2007 and 50.5 for UTC in 2008, again very close to my results for UTC but not that close for YCT. Finally, in the label for Figure 2 they reported 5,524 YCT were captured, whereas my results only show 5,454.\n \n\n\n\nRecreating Figure 2\nMy general strategy for recreating Figure 2 was to create the left and right panels of subplots separately and then combine them using patchwork. Each side can be constructed via faceting on type, but I will use facet_rep_wrap() from lemon so as to have the x-axis tick marks on each panel.5 Each panel will be create with geom_col() using width=1 so that the bars touch and geom_text() to place the labels.6 The x- and y-axes were modified as is commonly done.7 Finally, I used theme_bw() as a base, removed the gridlines and removed the facet labels and background.8 As you examine the code below, make sure to realize that the data was filtered to just “YCT”.5 See this post about facet_rep_wrap().6 See this post for more explanation of how to use geom_text() in this way.7 And is described more in this post.8 As described in this post.\n\nYCT <- ggplot(data=filter(cpe_dat,species==\"YCT\"),\n mapping=aes(x=year,y=cpe)) +\n geom_col(color=\"black\",fill=\"gray70\",width=1) +\n geom_text(mapping=aes(label=type),x=Inf,y=Inf,vjust=1.25,hjust=1.05,\n check_overlap=TRUE,size=3) +\n scale_y_continuous(name=\"YCT per net night\",\n limits=c(0,16),breaks=scales::breaks_width(2),\n expand=expansion(mult=0)) +\n scale_x_continuous(name=\"Year\",\n limits=c(2000,2022),breaks=scales::breaks_width(2),\n expand=expansion(mult=0)) +\n lemon::facet_rep_wrap(vars(type),ncol=1) +\n theme_bw() +\n theme(panel.grid=element_blank(),\n strip.background=element_blank(),\n strip.text=element_blank())\nYCT\n\n\n\n\n\n\n\n\nThe code above was largely repeated but with data filtered to just “UTC” and adjusting the y-axis accordingly. The plot is not shown here but is the right side in the plot further below.\n\nUTC <- ggplot(data=filter(cpe_dat,species==\"UTC\"),mapping=aes(x=year,y=cpe)) +\n geom_col(color=\"black\",fill=\"gray70\",width=1) +\n geom_text(mapping=aes(label=type),x=Inf,y=Inf,vjust=1.25,hjust=1.05,\n check_overlap=TRUE,size=3) +\n scale_y_continuous(name=\"UTC per net night\",\n limits=c(0,60),breaks=scales::breaks_width(10),\n expand=expansion(mult=0)) +\n scale_x_continuous(name=\"Year\",\n limits=c(2000,2022),breaks=scales::breaks_width(2),\n expand=expansion(mult=0)) +\n lemon::facet_rep_wrap(vars(type),ncol=1) +\n theme_bw() +\n theme(panel.grid=element_blank(),\n strip.background=element_blank(),\n strip.text=element_blank())\n\nThe two subplots are then placed side-by-side.\n\nYCT + UTC\n\n\n\n\n\n\n\n\n \n\n\nFurther Thoughts\nI wanted to see if I could make a similar looking plot using facet_grid(). It turns out to be a bit of a challenge because each panel on the left- and right-sides has the same y-axis, but those axes differ between the two sides. I found a way around this.\nFirst, I changed species to a factor with “YCT” in the first position so it would be plotted on the left (i.e., first). I also gave the levels longer labels so that the facets would have useful labels.\n\ncpe_dat <- cpe_dat |>\n mutate(species=factor(species,levels=c(\"YCT\",\"UTC\"),\n labels=c(\"Yellowstone Cutthroat Trout\",\"Utah Chub\")))\n\nThe y-axis needs to be defined for each facet. However, these definitions should be constant within species. Thus, I define limits and breaks for both YCT and UTC and saved them as objects. In addition, to save typing, I also defined the expansion factor as an object.\n\nYCT_lmts <- c(0,16)\nYCT_brks <- scales::breaks_width(2)\nUTC_lmts <- c(0,60)\nUTC_brks <- scales::breaks_width(10)\nyexp <- expansion(mult=0)\n\nThe basic plot uses the same ggplot() (except the data is not filtered), geom_col(), scale_x_continous(), and theme_bw() as before. The geom_text() has been eliminated because the “type” labels are going to be in the facet labels rather than “on the plot.” The part of theme() that removed the facet labels has been eliminated as facet labels are needed here. The spacing between panels was increased in theme() here. facet_rep_wrap() was replaced with facet_grid2() from ggh4x, where the rows are defined by type, the columns are defined by species, the y-axes are “free” and “independent” from facet to facet.9 Finally, facetted_pos_scales() from ggh4x is used to apply a different scale_y_continous() to each panel.109 The independent=\"y\" part is the main thing that facet_grid2() adds over facet_grid() from ggplot2.10 facetted_pos_scales() is described in more detail in this post.\n\nggplot(data=cpe_dat,mapping=aes(x=year,y=cpe)) +\n geom_col(color=\"black\",fill=\"gray70\",width=1) +\n scale_x_continuous(name=\"Year\",\n limits=c(2000,2022),breaks=scales::breaks_width(2),\n expand=expansion(mult=0)) +\n ggh4x::facet_grid2(rows=vars(type),cols=vars(species),\n scales=\"free_y\",independent=\"y\") +\n theme_bw() +\n theme(panel.grid=element_blank(),\n panel.spacing=unit(10,units=\"pt\")) +\n ggh4x::facetted_pos_scales(\n y=list(\n scale_y_continuous(name=\"# Fish per net night\",\n limits=YCT_lmts,breaks=YCT_brks,expand=yexp),\n scale_y_continuous(limits=UTC_lmts,breaks=UTC_brks,expand=yexp),\n scale_y_continuous(limits=YCT_lmts,breaks=YCT_brks,expand=yexp),\n scale_y_continuous(limits=UTC_lmts,breaks=UTC_brks,expand=yexp),\n scale_y_continuous(limits=YCT_lmts,breaks=YCT_brks,expand=yexp),\n scale_y_continuous(limits=UTC_lmts,breaks=UTC_brks,expand=yexp),\n scale_y_continuous(limits=YCT_lmts,breaks=YCT_brks,expand=yexp),\n scale_y_continuous(limits=UTC_lmts,breaks=UTC_brks,expand=yexp)\n )\n )\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n\n\nReferences\n\nMcCarrick, D. K., J. C. Dillon, B. High, and M. C. Quist. 2022. Population dynamics of Yellowstone Cutthroat Trout in Henrys Lake, Idaho. Journal of Fish and Wildlife Management 13(1):169–181.\n\nReusehttps://creativecommons.org/licenses/by/4.0/CitationBibTeX citation:@online{h.ogle2023,\n author = {Derek H. Ogle},\n title = {McCarrick Et Al. (2022) {CPE} {Plot}},\n date = {2023-03-22},\n url = {https://fishr-core-team.github.io/fishR//blog/posts/2023-3-22_McCarricketal2022_Fig2},\n langid = {en}\n}\nFor attribution, please cite this work as:\nDerek H. Ogle. 2023, March 22. McCarrick et al. (2022) CPE Plot. https://fishr-core-team.github.io/fishR//blog/posts/2023-3-22_McCarricketal2022_Fig2." - }, - { - "objectID": "blog/posts/2023-3-25_McCarricketal2022_Fig3/index.html", - "href": "blog/posts/2023-3-25_McCarricketal2022_Fig3/index.html", - "title": "McCarrick et al. (2022) PSD Plot", - "section": "", - "text": "Series Note\n\n\n\nThis is the second of several posts related to McCarrick et al. (2022).\n\n\n\nIntroduction\nMcCarrick et al. (2022) examined the population dynamics of Yellowstone Cutthroat Trout (Oncorhynchus clarkii bouvieri) in Henrys Lake, Idaho over a nearly two decade period. Their Figure 3 showed various proportional stock distribution (PSD) calculations of Cutthroat Trout across years. I use ggplot2 to recreate that figure here. I also modified their plot by adding confidence intervals to the calculations.\nThe following packages are loaded for use below. A few functions from each of lubridate, FSA, plyr, tidyr, scales, gghrx, and lemon are used with :: such that the entire packages are not attached here.\n\nlibrary(tidyverse) # for dplyr, ggplot2 packages\n\nMcCarrick et al. (2022) computed what I am calling an overall PSD1 and what are called “incremental” PSD indices. I assume that these are familar to most fisheries scientists, but they are described in more detail in Chapter 6 of Ogle (2016).21 This is the most common PSD measure.2 This provides a decent description of the overall PSD.\n \n\n\nData Wrangling\n\nIndividual Fish Data Frame\nMcCarrick et al. (2022) provided raw data for Figure 2 as an Excel file in their Data Supplement S1. The same data wrangling, up to where catch-per-unit-effort was calculated, used in this previous post is used here and, thus, will not be discussed in detail.\n\ndat <- readxl::read_xlsx(\"../2023-3-22_McCarricketal2022_Fig2/download.xlsx\",\n na=c(\"\",\"??\",\"QTY =\",\"QTY=\",\"UNK\",\"NO TAG\"),\n col_types=c(\"date\",\"numeric\",\"text\",\n \"numeric\",\"numeric\",\"text\")) |>\n mutate(year=lubridate::year(Date),\n year=ifelse(year==1905,2002,year)) |>\n filter(!is.na(year)) |>\n select(species=Species,year,length,weight) |>\n mutate(species=case_when(\n species %in% c(\"YCT\",\"Yct\") ~ \"YCT\",\n species %in% c(\"UTC\",\"CHB\",\"CHUB\") ~ \"UTC\",\n TRUE ~ species\n )) |>\n filter(species %in% c(\"YCT\",\"UTC\")) |>\n mutate(species2=plyr::mapvalues(species,\n from=c(\"YCT\",\"UTC\"),\n to=c(\"Cutthroat Trout\",\"Utah Chub\"))) |>\n mutate(gcat=FSA::psdAdd(len=length,species=species2))\n\nFSA::headtail(dat)\n\n#R| species year length weight species2 gcat\n#R| 1 YCT 2002 150 NA Cutthroat Trout substock\n#R| 2 YCT 2002 160 NA Cutthroat Trout substock\n#R| 3 YCT 2002 160 NA Cutthroat Trout substock\n#R| 19900 YCT 2020 391 550 Cutthroat Trout quality\n#R| 19901 YCT 2020 284 229 Cutthroat Trout stock\n#R| 19902 YCT 2020 440 853 Cutthroat Trout quality\n\n\n\n\nPSD Summary Data Frame\nThe data frame was filtered to only Cutthroat Trout (the only species shown in Figure 3) and sub-stock-sized fish were removed (PSD calculations do not consider sub-stock-sized fish).\n\npsd_dat <- dat |>\n filter(species==\"YCT\",gcat!=\"substock\")\n\nThe calculation of PSD values begins by counting the number of fish in each of the remaining Gabelhouse length categories, within each year.\n\npsd_dat <- psd_dat |>\n group_by(year,gcat) |>\n summarize(count=n()) |>\n ungroup()\nFSA::headtail(psd_dat)\n\n#R| year gcat count\n#R| 1 2002 stock 20\n#R| 2 2002 quality 28\n#R| 3 2002 preferred 1\n#R| 61 2020 stock 52\n#R| 62 2020 quality 132\n#R| 63 2020 preferred 13\n\n\nThis data frame was then made wider by creating columns with the length category names, each with the “count” in that category underneath it for each year.\n\npsd_dat <- psd_dat |>\n pivot_wider(names_from=gcat,values_from=count)\nFSA::headtail(psd_dat)\n\n#R| year stock quality preferred memorable trophy\n#R| 1 2002 20 28 1 NA NA\n#R| 2 2003 31 57 43 NA NA\n#R| 3 2004 141 36 27 1 NA\n#R| 17 2018 34 16 22 1 NA\n#R| 18 2019 176 20 17 3 NA\n#R| 19 2020 52 132 13 NA NA\n\n\nFor example, in 2002 there were 20 stock- to quality-sized fish, 28 quality- to preferred-size fish, 1 preferred- to memorable-sized fish, and no fish in the other categories. Each PSD calculation requires the total number of stock-size and larger fish as the denominator; i.e., 49 fish in 2002. In addition, the overall PSD calculation requires the total number of quality-sized and larger fish as the numerator; i.e., 28 fish in 2002. These two quantities are computed in mutate() below, but note that rowwise() is used before that to force the calculations to be computed by row (i.e., by year).33 If rowwise is not used then, for example, sum(stock+quality) would be the sum of both the stock and quality columns; i.e., the sum across all years.\n\npsd_dat <- psd_dat |>\n rowwise() |>\n mutate(qualityplus=sum(quality,preferred,memorable,trophy,na.rm=TRUE),\n stockplus=sum(stock,qualityplus,na.rm=TRUE))\nFSA::headtail(psd_dat)\n\n#R| year stock quality preferred memorable trophy qualityplus stockplus\n#R| 1 2002 20 28 1 NA NA 29 49\n#R| 2 2003 31 57 43 NA NA 100 131\n#R| 3 2004 141 36 27 1 NA 64 205\n#R| 17 2018 34 16 22 1 NA 39 73\n#R| 18 2019 176 20 17 3 NA 40 216\n#R| 19 2020 52 132 13 NA NA 145 197\n\n\nThe overall PSD is calculated as quality-sized and larger fish divided by stock-sized and larger fish multiplied by 100. The three incremental PSD values are calculated as the number in the incremental length group (e.g., stock- to quality-sized) divided by stock-sized and larger fish multiplied by 100. These calculations are made below within mutate().44 The incremental PSD names are within single back-ticks because the name contains a space (and a hyphen).\n\npsd_dat <- psd_dat |>\n mutate(PSD=qualityplus/stockplus*100,\n `PSD S-Q`=stock/stockplus*100,\n `PSD Q-P`=quality/stockplus*100,\n `PSD P-M`=preferred/stockplus*100) |>\n ungroup()\nFSA::headtail(psd_dat)\n\n#R| year stock quality preferred memorable trophy qualityplus stockplus PSD\n#R| 1 2002 20 28 1 NA NA 29 49 59.18367\n#R| 2 2003 31 57 43 NA NA 100 131 76.33588\n#R| 3 2004 141 36 27 1 NA 64 205 31.21951\n#R| 17 2018 34 16 22 1 NA 39 73 53.42466\n#R| 18 2019 176 20 17 3 NA 40 216 18.51852\n#R| 19 2020 52 132 13 NA NA 145 197 73.60406\n#R| PSD S-Q PSD Q-P PSD P-M\n#R| 1 40.81633 57.142857 2.040816\n#R| 2 23.66412 43.511450 32.824427\n#R| 3 68.78049 17.560976 13.170732\n#R| 17 46.57534 21.917808 30.136986\n#R| 18 81.48148 9.259259 7.870370\n#R| 19 26.39594 67.005076 6.598985\n\n\nFinally, this data frame should be made longer such that the calculated PSD values will appear under one column (called values) and another column will be created with the name of the PSD metric. This process begins by restricting the data frame to the year and all calculated PSD values, then pivoting the values in all of the PSD columns into one column with the names of the PSD metric stored in metric, and then factoring metric with the levels controlled so that they will be plotted in the same order as in Figure 3. This new data frame has a new name, as the original psd_dat data frame is used further below.\n\npsd_dat2 <- psd_dat |>\n select(year,contains(\"PSD\")) |>\n pivot_longer(cols=contains(\"PSD\"),names_to=\"metric\") |>\n mutate(metric=factor(metric,levels=c(\"PSD\",\"PSD S-Q\",\"PSD Q-P\",\"PSD P-M\")))\nFSA::headtail(psd_dat2)\n\n#R| year metric value\n#R| 1 2002 PSD 59.183673\n#R| 2 2002 PSD S-Q 40.816327\n#R| 3 2002 PSD Q-P 57.142857\n#R| 74 2020 PSD S-Q 26.395939\n#R| 75 2020 PSD Q-P 67.005076\n#R| 76 2020 PSD P-M 6.598985\n\n\nThis data frame, now called psd_dat2, is ready for recreating Figure 3.\n \n\n\n\nRecreating Figure 3\nFigure 3 is a simple bar plot facetted across years similar to the CPE plot in this previous post. Thus, I don’t discuss the details further here.\n\nggplot(data=psd_dat2,mapping=aes(x=year,y=value)) +\n geom_col(color=\"black\",fill=\"gray70\",width=1) +\n geom_text(mapping=aes(label=metric),x=Inf,y=Inf,vjust=1.25,hjust=1.05,size=3,\n check_overlap=TRUE) +\n scale_y_continuous(name=\"PSD\",limits=c(0,100),expand=expansion(mult=0),\n breaks=scales::breaks_width(20)) +\n scale_x_continuous(name=\"Year\",\n limits=c(2000,2022),breaks=scales::breaks_width(2),\n expand=expansion(mult=0)) +\n lemon::facet_rep_wrap(vars(metric),ncol=1) +\n theme_bw() +\n theme(panel.grid=element_blank(),\n strip.background=element_blank(),\n strip.text=element_blank())\n\n\n\n\n\n\n\n\n \n\n\nAdding Confidence Intervals\nI wanted to see if I could make Figure 3 as above, but add confidence intervals to the PSD calculations.55 The authors added CIs to the relative weight calculations in their Figure 4, but did not do that here for their PSD calculations.\nAs discussed in Ogle (2016) confidence intervals for a PSD can be made from binomial distribution theory using binCI() from FSA. This is a simple process of giving binCI() the number of “successes” (i.e., the numerator in the PSD calculation), the number of “trials”(i.e., the denominator), and the type of algorithm to use (we will use the “Wilson” algorithm here). For example, the CI for the overall PSD in 2002 is computed below.\n\nFSA::binCI(29,49,type=\"wilson\")*100\n\n#R| 95% LCI 95% UCI\n#R| 45.24732 71.78476\n\n\nThis becomes complicated here for several reasons:\n\nThe CIs are computed across multiple years.\nThe numerators differ among the PSD metrics (e.g., quality-sized and larger fish for the overall PSD but just quality-sized fish for PSD S-Q).\nbinCI() returns two values rather than 1 (thus, complicating the use of mutate()).\nbinCI() returns a matrix with column names rather than a named vector.\n\nGiven these issues, confidence intervals the PSD, PSD S-Q, etc. will each be calculated separately and then combined into a single data frame. I begin by calculating the CIs for the PSD.\nHere we return to the wide psd_dat data frame from above. The calculation will be for each year so again use rowwise(). FSA::binCI() will be used with mutate() but its result must first be converted to a vector with as.vector() (addresses last issue above) and then put in a list(). In this case the ci “variable” will be a list with two items (the lower and upper CI values) for each year. We want to get the two values out of this list and into their own variables, which is accomplished with unnest_wider() from tidyr (addressing the third issue above). The results from binCI() (after as.vector()) were unnamed, so names_sep= must be used in unnest_wider(). With this set to \"\", the unnested variables will be the original name (“ci”) followed by sequential numbers (i.e., “ci1” and “ci2” here). Finally,the data frame is reduced to the year, PSD, ci1, and ci2 variables, but PSD is renamed value along the way.66 This renaming is necessary for bind_rows() further below.\n\ntmp1 <- psd_dat |>\n rowwise() |>\n mutate(ci=list(as.vector(FSA::binCI(qualityplus,stockplus,type=\"wilson\")))) |>\n tidyr::unnest_wider(ci,names_sep=\"\") |>\n select(year,value=PSD,ci1,ci2)\nFSA::headtail(tmp1)\n\n#R| year value ci1 ci2\n#R| 1 2002 59.18367 0.4524732 0.7178476\n#R| 2 2003 76.33588 0.6837273 0.8279848\n#R| 3 2004 31.21951 0.2527076 0.3785916\n#R| 17 2018 53.42466 0.4209895 0.6440796\n#R| 18 2019 18.51852 0.1390441 0.2423283\n#R| 19 2020 73.60406 0.6703995 0.7926523\n\n\nThis exact code is repeated for PSD S-Q but making sure that stock is the first argument to binCI(), the new value variable comes from PSD S-Q, and the resulting data frame is given a different name.\n\ntmp2 <- psd_dat |>\n rowwise() |>\n mutate(ci=list(as.vector(FSA::binCI(stock,stockplus,type=\"wilson\")))) |>\n tidyr::unnest_wider(ci,names_sep=\"\") |>\n select(year,value=`PSD S-Q`,ci1,ci2)\n\nThis process is repeated for the other two metrics.\n\ntmp3 <- psd_dat |>\n rowwise() |>\n mutate(ci=list(as.vector(FSA::binCI(quality,stockplus,type=\"wilson\")))) |>\n tidyr::unnest_wider(ci,names_sep=\"\") |>\n select(year,value=`PSD Q-P`,ci1,ci2)\n\n\ntmp4 <- psd_dat |>\n rowwise() |>\n mutate(ci=list(as.vector(FSA::binCI(preferred,stockplus,type=\"wilson\")))) |>\n tidyr::unnest_wider(ci,names_sep=\"\") |>\n select(year,value=`PSD P-M`,ci1,ci2)\n\nThese four temporary data frames are bound together with a metric variable added to indicate which PSD metric appears in each row of the new data frame. Additionally, ci1 and ci2 were renamed to LCI and UCI for clarity, each CI endpoint was muliplied by 100 to put it on the same scale as the point estimates (i.e., percentages rather than proportions returned from binCI()), and metric was factored with controlled levels as above.\n\npsd_dat3 <- bind_rows(list(\"PSD\"=tmp1,\"PSD S-Q\"=tmp2,\"PSD Q-P\"=tmp3,\"PSD P-M\"=tmp4),\n .id=\"metric\") |>\n rename(LCI=`ci1`,UCI=`ci2`) |>\n mutate(LCI=LCI*100,UCI=UCI*100,\n metric=factor(metric,levels=c(\"PSD\",\"PSD S-Q\",\"PSD Q-P\",\"PSD P-M\")))\nFSA::headtail(psd_dat3)\n\n#R| metric year value LCI UCI\n#R| 1 PSD 2002 59.183673 45.247319 71.78476\n#R| 2 PSD 2003 76.335878 68.372730 82.79848\n#R| 3 PSD 2004 31.219512 25.270764 37.85916\n#R| 74 PSD P-M 2018 30.136986 20.822591 41.43737\n#R| 75 PSD P-M 2019 7.870370 4.971693 12.24137\n#R| 76 PSD P-M 2020 6.598985 3.896693 10.96152\n\n\nThe same code used above to recreate Figure 3 is repeated below, but geom_errorbar() is used with LCI mapped to ymin= and UCI mapped to ymax= to form the confidence intervals. geom_errorbar() is before geom_col() which gives the appearance of only showing the upper portion of the confidence interval (i.e., the lower portion is behind the bar). width=0.25 was used to narrow the “caps” on the intervals.\n\nggplot(data=psd_dat3,mapping=aes(x=year,y=value)) +\n geom_errorbar(mapping=aes(ymin=LCI,ymax=UCI),width=0.25) +\n geom_col(color=\"black\",fill=\"gray70\",width=1) +\n geom_text(mapping=aes(label=metric),x=Inf,y=Inf,vjust=1.25,hjust=1.05,size=3,\n check_overlap=TRUE) +\n scale_y_continuous(name=\"PSD\",limits=c(0,100),expand=expansion(mult=0),\n breaks=scales::breaks_width(20)) +\n scale_x_continuous(name=\"Year\",\n limits=c(2000,2022),breaks=scales::breaks_width(2),\n expand=expansion(mult=0)) +\n lemon::facet_rep_wrap(vars(metric),ncol=1) +\n theme_bw() +\n theme(panel.grid=element_blank(),\n strip.background=element_blank(),\n strip.text=element_blank())\n\n\n\n\n\n\n\n\n \n\n\nFurther Thoughts\n\nPoint-and-Lines Plot\nAs mentioned in this previous post I understand that these are the much derided “dynamite plots”. Personally, I find the bars distracting (so much gray with little purpose) and find a point-and-lines plot more appealing.\n\nggplot(data=psd_dat3,mapping=aes(x=year,y=value)) +\n geom_errorbar(mapping=aes(ymin=LCI,ymax=UCI),linewidth=0.5,width=0.25) +\n geom_line(linewidth=0.75,color=\"gray70\") +\n geom_point(size=1) +\n geom_text(mapping=aes(label=metric),x=Inf,y=Inf,vjust=1.25,hjust=1.05,size=3,\n check_overlap=TRUE) +\n scale_y_continuous(name=\"PSD\",limits=c(0,100),expand=expansion(mult=0),\n breaks=scales::breaks_width(20)) +\n scale_x_continuous(name=\"Year\",\n limits=c(2000,2022),breaks=scales::breaks_width(2),\n expand=expansion(mult=0)) +\n lemon::facet_rep_wrap(vars(metric),ncol=1) +\n theme_bw() +\n theme(panel.grid=element_blank(),\n strip.background=element_blank(),\n strip.text=element_blank())\n\n\n\n\n\n\n\n\n\n\nLoess Smoother\nA loess smoother could also be added with geom_smooth() to highlight any trends (or lack thereof).\n\nggplot(data=psd_dat3,mapping=aes(x=year,y=value)) +\n geom_errorbar(mapping=aes(ymin=LCI,ymax=UCI),linewidth=0.5,width=0.25) +\n geom_line(linewidth=0.75,color=\"gray70\") +\n geom_point(size=1) +\n geom_smooth(se=FALSE,color=\"gray30\",linetype=\"dashed\",linewidth=0.5) +\n geom_text(mapping=aes(label=metric),x=Inf,y=Inf,vjust=1.25,hjust=1.05,size=3,\n check_overlap=TRUE) +\n scale_y_continuous(name=\"PSD\",limits=c(0,100),expand=expansion(mult=0),\n breaks=scales::breaks_width(20)) +\n scale_x_continuous(name=\"Year\",\n limits=c(2000,2022),breaks=scales::breaks_width(2),\n expand=expansion(mult=0)) +\n lemon::facet_rep_wrap(vars(metric),ncol=1) +\n theme_bw() +\n theme(panel.grid=element_blank(),\n strip.background=element_blank(),\n strip.text=element_blank())\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n\n\n\nReferences\n\nMcCarrick, D. K., J. C. Dillon, B. High, and M. C. Quist. 2022. Population dynamics of Yellowstone Cutthroat Trout in Henrys Lake, Idaho. Journal of Fish and Wildlife Management 13(1):169–181.\n\n\nOgle, D. H. 2016. Introductory Fisheries Analyses with R. CRC Press, Boca Raton, FL.\n\nReusehttps://creativecommons.org/licenses/by/4.0/CitationBibTeX citation:@online{h.ogle2023,\n author = {Derek H. Ogle},\n title = {McCarrick Et Al. (2022) {PSD} {Plot}},\n date = {2023-03-25},\n url = {https://fishr-core-team.github.io/fishR//blog/posts/2023-3-25_McCarricketal2022_Fig3},\n langid = {en}\n}\nFor attribution, please cite this work as:\nDerek H. Ogle. 2023, March 25. McCarrick et al. (2022) PSD Plot. https://fishr-core-team.github.io/fishR//blog/posts/2023-3-25_McCarricketal2022_Fig3." - }, - { - "objectID": "blog/posts/2023-3-26_McCarricketal2022_Fig4/index.html", - "href": "blog/posts/2023-3-26_McCarricketal2022_Fig4/index.html", - "title": "McCarrick et al. (2022) Wr Plot", - "section": "", - "text": "Series Note\n\n\n\nThis is the third of several posts related to McCarrick et al. (2022).\n\n\n\nIntroduction\nMcCarrick et al. (2022) examined the population dynamics of Yellowstone Cutthroat Trout (Oncorhynchus clarkii bouvieri) in Henrys Lake, Idaho over a nearly two decade period. Their Figure 4 showed mean (with confidence interval) relative weight (Wr) for various length categories of Cutthroat Trout across years. I use ggplot2 to recreate that figure here.\nThe following packages are loaded for use below. A few functions from each of lubridate, FSA, plyr, scales, gghrx, lemon, and ggtext are used with :: such that the entire packages are not attached here.\n\nlibrary(tidyverse) # for dplyr, ggplot2 packages\n\nMcCarrick et al. (2022) computed what I am calling an overall PSD1 and what are called “incremental” PSD indices. I assume that these are familar to most fisheries scientists, but they are described in more detail in Chapter 8 of Ogle (2016).21 This is the most common PSD measure.2 Also see Blackwell et al. (2000).\n \n\n\nData Wrangling\n\nIndividual Fish Data Frame\nMcCarrick et al. (2022) provided raw data for Figure 2 as an Excel file in their Data Supplement S1. The same data wrangling, up to where catch-per-unit-effort was calculated, used in this previous post is used here3 and, thus, will not be discussed in detail.3 And in this post\n\ndat <- readxl::read_xlsx(\"../2023-3-22_McCarricketal2022_Fig2/download.xlsx\",\n na=c(\"\",\"??\",\"QTY =\",\"QTY=\",\"UNK\",\"NO TAG\"),\n col_types=c(\"date\",\"numeric\",\"text\",\n \"numeric\",\"numeric\",\"text\")) |>\n mutate(year=lubridate::year(Date),\n year=ifelse(year==1905,2002,year)) |>\n filter(!is.na(year)) |>\n select(species=Species,year,length,weight) |>\n mutate(species=case_when(\n species %in% c(\"YCT\",\"Yct\") ~ \"YCT\",\n species %in% c(\"UTC\",\"CHB\",\"CHUB\") ~ \"UTC\",\n TRUE ~ species\n )) |>\n filter(species %in% c(\"YCT\",\"UTC\")) |>\n mutate(species2=plyr::mapvalues(species,\n from=c(\"YCT\",\"UTC\"),\n to=c(\"Cutthroat Trout\",\"Utah Chub\"))) |>\n mutate(gcat=FSA::psdAdd(len=length,species=species2))\n\nFSA::headtail(dat)\n\n#R| species year length weight species2 gcat\n#R| 1 YCT 2002 150 NA Cutthroat Trout substock\n#R| 2 YCT 2002 160 NA Cutthroat Trout substock\n#R| 3 YCT 2002 160 NA Cutthroat Trout substock\n#R| 19900 YCT 2020 391 550 Cutthroat Trout quality\n#R| 19901 YCT 2020 284 229 Cutthroat Trout stock\n#R| 19902 YCT 2020 440 853 Cutthroat Trout quality\n\n\nThe relative weigt for each fish needs to be added to this data frame, preferably with wrAdd() from FSA. Note, however, that there are two standard weight equations for Cutthroat Trout, one for lentic and one for lotic populations. We want to make sure to use the one for lentic populations here and, thus, cannot use the species name found in the data frame within wrAdd(). Note below that the data frame was also reduced to just Cutthroat Trout for which a weight was recorded, and the two species variables were dropped (just to simplify the output).\n\ndat <- dat |>\n filter(species==\"YCT\",!is.na(weight)) |>\n mutate(wr=FSA::wrAdd(weight,length,spec=\"Cutthroat Trout (lentic)\")) |>\n select(-starts_with(\"species\"))\nFSA::headtail(dat)\n\n#R| year length weight gcat wr\n#R| 1 2004 174 54 substock 102.34315\n#R| 2 2004 227 130 stock 108.45450\n#R| 3 2004 305 380 stock 127.41903\n#R| 5208 2020 391 550 quality 85.68508\n#R| 5209 2020 284 229 stock 95.69629\n#R| 5210 2020 440 853 quality 92.31113\n\n\n\n\nWr Summary Data Frame\nSummary statistics of relative weight for all fish is computed below.\n\nwr_all <- dat |>\n group_by(year) |>\n summarize(n=n(),\n mn_wr=mean(wr,na.rm=TRUE),\n sd_wr=sd(wr,na.rm=TRUE),\n se_wr=FSA::se(wr,na.rm=TRUE))\nFSA::headtail(wr_all)\n\n#R| year n mn_wr sd_wr se_wr\n#R| 1 2004 300 116.50388 16.405045 0.9650026\n#R| 2 2005 305 103.70058 14.860984 0.8509375\n#R| 3 2006 269 107.66011 20.258635 1.2351908\n#R| 15 2018 76 107.05779 25.899713 2.9709008\n#R| 16 2019 219 97.20635 7.485436 0.5058189\n#R| 17 2020 198 94.78333 8.648857 0.6146475\n\n\nSummary statistics of relative weight for each length category is computed below.\n\nwr_gcat <- dat |>\n group_by(year,gcat) |>\n summarize(n=n(),\n mn_wr=mean(wr,na.rm=TRUE),\n sd_wr=sd(wr,na.rm=TRUE),\n se_wr=FSA::se(wr,na.rm=TRUE)) |>\n ungroup()\nFSA::headtail(wr_gcat)\n\n#R| year gcat n mn_wr sd_wr se_wr\n#R| 1 2004 substock 110 103.54857 13.477955 1.3545854\n#R| 2 2004 stock 130 123.09751 11.535665 1.0117447\n#R| 3 2004 quality 34 127.50055 12.158543 2.0851728\n#R| 68 2020 stock 52 95.40331 10.326851 1.4320766\n#R| 69 2020 quality 132 94.78427 8.119609 0.7067213\n#R| 70 2020 preferred 13 92.28008 6.826683 1.8933812\n\n\nMcCarrick et al. (2022) only plotted fish in the “stock”, “quality”, and “preferred” length categories in Figure 4; thus, only these length categories are retained below.\n\nwr_gcat <- wr_gcat |>\n filter(gcat %in% c(\"stock\",\"quality\",\"preferred\"))\n\nThe summaries for all fish and fish by length categories are row-bound (i.e., stacked) together to form an overall summary data frame. Because the data frame for all fish did not have a gcat variable, that variable will be populated with NA when the two data frames are bound. The ifelse() below converts these NA values to All, before gcat is factored with levels ordered as they would appear in Figure 4 and with more descriptive labels. Finally, for aesthetic purposes, I moved gcat to be the first variable and sorted the results by year within length category.\n\nwr_dat <- bind_rows(wr_all,wr_gcat) |>\n mutate(gcat=ifelse(is.na(gcat),\"All\",as.character(gcat)),\n gcat=factor(gcat,levels=c(\"All\",\"stock\",\"quality\",\"preferred\"),\n labels=c(\"All fish\",\"Stock to Quality\",\n \"Quality to Preferred\",\"Preferred to Memorable\"))) |>\n relocate(gcat) |>\n arrange(gcat,year)\nFSA::headtail(wr_dat)\n\n#R| gcat year n mn_wr sd_wr se_wr\n#R| 1 All fish 2004 300 116.50388 16.405045 0.9650026\n#R| 2 All fish 2005 305 103.70058 14.860984 0.8509375\n#R| 3 All fish 2006 269 107.66011 20.258635 1.2351908\n#R| 66 Preferred to Memorable 2018 22 98.79180 17.476556 3.7260144\n#R| 67 Preferred to Memorable 2019 17 98.61326 8.666677 2.1019780\n#R| 68 Preferred to Memorable 2020 13 92.28008 6.826683 1.8933812\n\n\nFinally, the lower and upper confidence intervals for each mean are added to the data frame using normal distribution theory.44 qt() returns a the 97.5th percent critical value from a t-distribution with df degrees-of-freedom.\n\nwr_dat <- wr_dat |>\n mutate(lci=mn_wr-qt(0.975,df=n-1)*se_wr,\n uci=mn_wr+qt(0.975,df=n-1)*se_wr)\nFSA::headtail(wr_dat)\n\n#R| gcat year n mn_wr sd_wr se_wr lci\n#R| 1 All fish 2004 300 116.50388 16.405045 0.9650026 114.60482\n#R| 2 All fish 2005 305 103.70058 14.860984 0.8509375 102.02610\n#R| 3 All fish 2006 269 107.66011 20.258635 1.2351908 105.22820\n#R| 66 Preferred to Memorable 2018 22 98.79180 17.476556 3.7260144 91.04313\n#R| 67 Preferred to Memorable 2019 17 98.61326 8.666677 2.1019780 94.15727\n#R| 68 Preferred to Memorable 2020 13 92.28008 6.826683 1.8933812 88.15476\n#R| uci\n#R| 1 118.4029\n#R| 2 105.3750\n#R| 3 110.0920\n#R| 66 106.5405\n#R| 67 103.0693\n#R| 68 96.4054\n\n\nThis data frame, now called wr_dat, is ready for recreating Figure 4.\n \n\n\n\nRecreating Figure 4\nFigure 4 is a simple bar plot facetted across years similar to the PSD plot in this previous post. Confidence intervals are added as described in that same post. Thus, many of the details below are not discussed further here. However, there are two new things to consider here.\nFirst, the y-axis in Figure 4 in (mccarricketal_2020?) is limited from 70 to 140. If limits=c(70,140) is used in scale_y_continuous() as described in this post the bars will be removed because their “data” extends to zero.5 Thus, the limits of the y-axis must be set with ylim= in coord_cartesian() to preserved the bars.5 Data points outside axis limits created in this way are treated as missing and are removed from the figure.\nSecond, the y-axis label in Figure 4 in (mccaricketal_2020?) is italicized with a subscript “r”. In the markdown language, asterisks are used to denoted italics and the tilde is used to create a subscript, which can be seen in name= in scale_y_continuous(). However, to make this markdown code render properly axis.title.y= in theme must be set to element_markdown() from ggtext.\n\nggplot(data=wr_dat,mapping=aes(x=year,y=mn_wr)) +\n geom_errorbar(mapping=aes(ymin=lci,ymax=uci),width=0.25) +\n geom_col(color=\"black\",fill=\"gray70\",width=1) +\n geom_text(mapping=aes(label=gcat),x=Inf,y=Inf,vjust=1.25,hjust=1.05,size=3,\n check_overlap=TRUE) +\n scale_y_continuous(name=\"*W~r~*\",expand=expansion(mult=0),\n breaks=scales::breaks_width(10)) +\n scale_x_continuous(name=\"Year\",\n limits=c(2000,2022),breaks=scales::breaks_width(2),\n expand=expansion(mult=0)) +\n coord_cartesian(ylim=c(70,140)) +\n lemon::facet_rep_wrap(vars(gcat),ncol=1) +\n theme_bw() +\n theme(panel.grid=element_blank(),\n strip.background=element_blank(),\n strip.text=element_blank(),\n axis.title.y=ggtext::element_markdown())\n\n\n\n\n\n\n\n\n \n\n\nFurther Thoughts\n\nPoint-and-Lines Plot\nAs mentioned in this previous post I understand that these are the much derided “dynamite plots”. Personally, I find the bars distracting (so much gray with little purpose and starting at 70) and find a point-and-lines plot, possibly with a horizontal line at the common reference value of 100.\n\nggplot(data=wr_dat,mapping=aes(x=year,y=mn_wr)) +\n geom_errorbar(mapping=aes(ymin=lci,ymax=uci),width=0.25) +\n geom_line(linewidth=0.75,color=\"gray70\") +\n geom_point(size=1) +\n geom_hline(yintercept=100,color=\"gray30\",linetype=\"dashed\",linewidth=0.5) +\n geom_text(mapping=aes(label=gcat),x=Inf,y=Inf,vjust=1.25,hjust=1.05,size=3,\n check_overlap=TRUE) +\n scale_y_continuous(name=\"*W~r~*\",limits=c(70,140),expand=expansion(mult=0),\n breaks=scales::breaks_width(10)) +\n scale_x_continuous(name=\"Year\",\n limits=c(2000,2022),breaks=scales::breaks_width(2),\n expand=expansion(mult=0)) +\n lemon::facet_rep_wrap(vars(gcat),ncol=1) +\n theme_bw() +\n theme(panel.grid=element_blank(),\n strip.background=element_blank(),\n strip.text=element_blank(),\n axis.title.y=ggtext::element_markdown())\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n\n\n\nReferences\n\nBlackwell, B., M. Brown, and D. Willis. 2000. Relative Weight (Wr) Status and Current Use in Fisheries Assessment and Management. Reviews in Fisheries Science 8:1–44.\n\n\nMcCarrick, D. K., J. C. Dillon, B. High, and M. C. Quist. 2022. Population dynamics of Yellowstone Cutthroat Trout in Henrys Lake, Idaho. Journal of Fish and Wildlife Management 13(1):169–181.\n\n\nOgle, D. H. 2016. Introductory Fisheries Analyses with R. CRC Press, Boca Raton, FL.\n\nReusehttps://creativecommons.org/licenses/by/4.0/CitationBibTeX citation:@online{h.ogle2023,\n author = {Derek H. Ogle},\n title = {McCarrick Et Al. (2022) {Wr} {Plot}},\n date = {2023-03-26},\n url = {https://fishr-core-team.github.io/fishR//blog/posts/2023-3-26_McCarricketal2022_Fig4},\n langid = {en}\n}\nFor attribution, please cite this work as:\nDerek H. Ogle. 2023, March 26. McCarrick et al. (2022) Wr Plot. https://fishr-core-team.github.io/fishR//blog/posts/2023-3-26_McCarricketal2022_Fig4." - }, - { - "objectID": "blog/posts/2023-3-27_McCarricketal2022_Fig5/index.html", - "href": "blog/posts/2023-3-27_McCarricketal2022_Fig5/index.html", - "title": "McCarrick et al. (2022) Age Composition Plot", - "section": "", - "text": "Series Note\n\n\n\nThis is the fourth of several posts related to McCarrick et al. (2022).\n\n\n\nIntroduction\nMcCarrick et al. (2022) examined the population dynamics of Yellowstone Cutthroat Trout (Oncorhynchus clarkii bouvieri) in Henrys Lake, Idaho over a nearly two decade period. Their Figure 5 showed the relative age composition of Cutthroat Trout across years. I use ggplot2 to recreate that figure here.\nThe following packages are loaded for use below. A few functions from each of FSA, plyr, lemon, and forcats are used with :: such that the entire packages are not attached here.\n\nlibrary(tidyverse) # for dplyr, ggplot2 packages\n\n \n\n\nData Wrangling\nMcCarrick et al. (2022) provided raw data for Figure 2 in a MSWord table as a supplement. I copied the table from Word, pasted it into Excel, and saved it for loading here.\n\ndat <- readxl::read_xlsx(\"YCT_AgeComp.xlsx\")\ndat\n\n#R| # A tibble: 19 × 12\n#R| Year `Age 1` `Age 2` `Age 3` `Age 4` `Age 5` `Age 6` `Age 7` `Age 8` `Age 9`\n#R| \n#R| 1 2002 0.113 0.46 0.394 0.034 0 0 0 0 0 \n#R| 2 2003 0.207 0.207 0.194 0.289 0.058 0.025 0 0 0.019\n#R| 3 2004 0.39 0.472 0.084 0.034 0.003 0.007 0.007 0.003 0 \n#R| 4 2005 0.368 0.527 0.078 0.015 0.013 0 0 0 0 \n#R| 5 2006 0.091 0.276 0.52 0.107 0.002 0.004 0 0 0 \n#R| 6 2007 0.025 0.708 0.13 0.128 0.009 0 0 0 0 \n#R| 7 2008 0 0.536 0.298 0.146 0.021 0 0 0 0 \n#R| 8 2009 0.051 0.27 0.502 0.177 0 0 0 0 0 \n#R| 9 2010 0.028 0.753 0.092 0.116 0.008 0.003 0 0 0 \n#R| 10 2011 0.003 0.774 0.187 0.029 0.005 0.003 0 0 0 \n#R| 11 2012 0.017 0.594 0.348 0.029 0.004 0.006 0 0 0 \n#R| 12 2013 0.004 0.61 0.22 0.14 0.02 0.002 0.004 0 0 \n#R| 13 2014 0.007 0.353 0.437 0.136 0.05 0.013 0.002 0.002 0 \n#R| 14 2015 0.021 0.399 0.239 0.271 0.031 0.04 0 0 0 \n#R| 15 2016 0 0.594 0.238 0.082 0.053 0.033 0 0 0 \n#R| 16 2017 0.02 0.518 0.197 0.197 0.027 0.035 0 0.007 0 \n#R| 17 2018 0.053 0.137 0.505 0.148 0.101 0.013 0.031 0.013 0 \n#R| 18 2019 0.013 0.765 0.127 0.037 0.027 0.014 0.004 0.013 0 \n#R| 19 2020 0.005 0.206 0.677 0.096 0.003 0.005 0.005 0.002 0 \n#R| # … with 2 more variables: `Age 10` , `Age 11` \n\n\nThe data were provided in a wide format that needs to be “tidied” to a long format with the proportions at age in the Age X columns stacked on top of each other with a corresponding variable that indicates the age. Note that the columns to pivot in cols= were selected by ignoring year and, thus, leaving all of the Age X columns.11 The columns also could have been selected with starts_with(\"Age\"), among other possibilities.\n\ndat <- dat |>\n pivot_longer(cols=-Year,names_to=\"Age\",values_to=\"Proportion\")\nFSA::headtail(dat)\n\n#R| Year Age Proportion\n#R| 1 2002 Age 1 0.113\n#R| 2 2002 Age 2 0.460\n#R| 3 2002 Age 3 0.394\n#R| 207 2020 Age 9 0.000\n#R| 208 2020 Age 10 0.001\n#R| 209 2020 Age 11 0.000\n\n\nThe Age variable should be converted to a factor so that the levels can be controlled, otherwise “Age 10” will follow “Age 1”.\n\ndat <- dat |>\n mutate(Age=factor(Age,levels=c(\"Age 1\",\"Age 2\",\"Age 3\",\"Age 4\",\"Age 5\",\"Age 6\",\n \"Age 7\",\"Age 8\",\"Age 9\",\"Age 10\",\"Age 11\")))\n\nThis data frame is ready for recreating Figure 5.\n \n\n\nRecreating Figure 5\nFigure 5 is an “area plot” which is easily constructed in ggplot2 with geom_area(), with the variable that defines the colored areas (i.e., Age) mapped to fill=.22 I plotted every other on the x-axis as the font needed to be so small to show every year at in McCarrick et al. (2022).\n\nggplot(data=dat,mapping=aes(x=Year,y=Proportion,fill=Age)) +\n geom_area() +\n scale_y_continuous(expand=expansion(mult=0),\n breaks=scales::breaks_width(0.1)) +\n scale_x_continuous(expand=expansion(mult=0),\n limits=c(2002,2020),breaks=scales::breaks_width(2)) +\n theme_bw() +\n theme(panel.grid=element_blank())\n\n\n\n\n\n\n\n\nI won’t address color here (but see further below) as these colors are no uglier than what is shown in the published Figure 5. However, there are other adjustments that need to be made to match Figure 5.\nFirst, the ages above are stacked opposite of what is in Figure 5; i.e., age-1 is at the top, age-2 below that, etc. rather than age-1 at the bottom, age-2 on top of that, etc. The order of stacking is reversed with position= in geom_area() as shown below. Second, the authors included two digits for the values on the y-axis for some reason. Assuming this behavior is desired it can be obtained with scales::label_number() in scale_y_continuous() as shown below.33 This was demonstrated in this post.\n\nggplot(data=dat,mapping=aes(x=Year,y=Proportion,fill=Age)) +\n geom_area(position=position_stack(reverse=TRUE)) +\n scale_y_continuous(expand=expansion(mult=0),\n breaks=scales::breaks_width(0.1),\n label=scales::label_number(0.01)) +\n scale_x_continuous(expand=expansion(mult=0),\n limits=c(2002,2020),breaks=scales::breaks_width(2)) +\n theme_bw() +\n theme(panel.grid=element_blank())\n\n\n\n\n\n\n\n\nThird, the legend needs to be moved to below the x-axis. This is easily accomplished with legend.position=\"bottom\" in theme(). However, doing this alone shows the legend in three rows. One row was used for the legend as shown below with guides(). Finally, other theme options were altered to remove the legend title and make the legend symbols and text smaller.\n\nggplot(data=dat,mapping=aes(x=Year,y=Proportion,fill=Age)) +\n geom_area(position=position_stack(reverse=TRUE)) +\n scale_y_continuous(expand=expansion(mult=0),\n breaks=scales::breaks_width(0.1),\n label=scales::label_number(0.01)) +\n scale_x_continuous(expand=expansion(mult=0),\n limits=c(2002,2020),breaks=scales::breaks_width(2)) +\n guides(fill=guide_legend(nrow=1)) +\n theme_bw() +\n theme(panel.grid=element_blank(),\n legend.position=\"bottom\",\n legend.title=element_blank(),\n legend.key.size=unit(2,\"mm\"),\n legend.text=element_text(size=7))\n\n\n\n\n\n\n\n\nThis largely recreates Figure 5 in McCarrick et al. (2022).\n \n\n\nPossible Modifications\nArea plots are notorious for being difficult for readers to interpret.4 Below I offer some modifications that may(?) aid interpretation.4 See this for example.\n\nLump Ages\nMany potential ages are shown in Figure 5 though ages greater than age-5 are rarely visible (or noticeable) as they never represent more than 10% in total or 4% individually of the fish in any given year.\n\n# Find maximum proportion by age, is that more than 5%\ndat |> group_by(Age) |> summarize(maxP=max(Proportion))\n\n#R| # A tibble: 11 × 2\n#R| Age maxP\n#R| \n#R| 1 Age 1 0.39 \n#R| 2 Age 2 0.774\n#R| 3 Age 3 0.677\n#R| 4 Age 4 0.289\n#R| 5 Age 5 0.101\n#R| 6 Age 6 0.04 \n#R| 7 Age 7 0.031\n#R| 8 Age 8 0.013\n#R| 9 Age 9 0.019\n#R| 10 Age 10 0.002\n#R| 11 Age 11 0.001\n\n\nThe number of colors used in the plot, and the number of areas that the reader looks for, can be reduced by lumping together ages that are not well-represented in the data. Below fct_collapse() from forcats is used to collapse the “Age 6” to “Age 11” levels in Age to one level called “Age 6+”. To preserve the original data this data frame was called dat2.\n\ndat2 <- dat |>\n mutate(Age=forcats::fct_collapse(Age,`Age 6+`=c(\"Age 6\",\"Age 7\",\"Age 7\",\"Age 8\",\n \"Age 9\",\"Age 10\",\"Age 11\")))\nFSA::headtail(dat2)\n\n#R| Year Age Proportion\n#R| 1 2002 Age 1 0.113\n#R| 2 2002 Age 2 0.460\n#R| 3 2002 Age 3 0.394\n#R| 207 2020 Age 6+ 0.000\n#R| 208 2020 Age 6+ 0.001\n#R| 209 2020 Age 6+ 0.000\n\n\nHowever, “Age 6+” was simply repeated for the original “Age 6”, “Age 7”, etc. The proportions for these ages should be summed, within each year, to get a proper proportion of “Age 6+” fish.55 Summing the proportions for the ages that were lumped will just return the proportion for those ages.\n\ndat2 <- dat2 |>\n group_by(Year,Age) |>\n summarize(Proportion=sum(Proportion)) |>\n ungroup()\nFSA::headtail(dat2)\n\n#R| Year Age Proportion\n#R| 1 2002 Age 1 0.113\n#R| 2 2002 Age 2 0.460\n#R| 3 2002 Age 3 0.394\n#R| 112 2020 Age 4 0.096\n#R| 113 2020 Age 5 0.003\n#R| 114 2020 Age 6+ 0.013\n\n\nTo save some typing below, I set the theme to the theme items above with the exception that I moved the legend back to the right where I think it is more appropriate.\n\ntheme_set(\n theme_bw() +\n theme(panel.grid=element_blank(),\n legend.title=element_blank(),\n legend.key.size=unit(3,\"mm\"),\n legend.text=element_text(size=8))\n)\n\nThe code for Figure 5 is largely repeated below with these data. However, I reversed the order of the labels in the legend with guides() so that the labels more naturally followed how the areas were plotted and I removed the unnecessary extra digit in the y-axis labels.\n\nggplot(data=dat2,mapping=aes(x=Year,y=Proportion,fill=Age)) +\n geom_area(position=position_stack(reverse=TRUE)) +\n scale_y_continuous(expand=expansion(mult=0),\n breaks=scales::breaks_width(0.1)) +\n scale_x_continuous(expand=expansion(mult=0),\n limits=c(2002,2020),breaks=scales::breaks_width(2)) +\n guides(fill=guide_legend(reverse=TRUE))\n\n\n\n\n\n\n\n\n\n\nColor\nChanging the color is not necessarily going to make the figure easier to interpret. However, a gradient of color can be used to more clearly represent the gradient of age. Here, I form a gradient of grays with scale_fill_grey().\n\nggplot(data=dat2,mapping=aes(x=Year,y=Proportion,fill=Age)) +\n geom_area(position=position_stack(reverse=TRUE)) +\n scale_y_continuous(expand=expansion(mult=0),\n breaks=scales::breaks_width(0.1)) +\n scale_x_continuous(expand=expansion(mult=0),\n limits=c(2002,2020),breaks=scales::breaks_width(2)) +\n scale_fill_grey(start=0.2,end=0.8) +\n guides(fill=guide_legend(reverse=TRUE))\n\n\n\n\n\n\n\n\nA sequential palette that ranges from dark green to light blue is used below with scale_fill_brewer(). A variety of palettes may be chosen in this function as described in its documentation. Note that direction=-1 was used here to reverse the palette order as I preferred the darker colors for age-1 and the lighter colors for age-6+.\n\nggplot(data=dat2,mapping=aes(x=Year,y=Proportion,fill=Age)) +\n geom_area(position=position_stack(reverse=TRUE)) +\n scale_y_continuous(expand=expansion(mult=0),\n breaks=scales::breaks_width(0.1)) +\n scale_x_continuous(expand=expansion(mult=0),\n limits=c(2002,2020),breaks=scales::breaks_width(2)) +\n scale_fill_brewer(palette=\"BuGn\",direction=-1) +\n guides(fill=guide_legend(reverse=TRUE))\n\n\n\n\n\n\n\n\nOther palette algorithms can also be used. Below, scale_fill_viridis_d() is used as an example.\n\nggplot(data=dat2,mapping=aes(x=Year,y=Proportion,fill=Age)) +\n geom_area(position=position_stack(reverse=TRUE)) +\n scale_y_continuous(expand=expansion(mult=0),\n breaks=scales::breaks_width(0.1)) +\n scale_x_continuous(expand=expansion(mult=0),\n limits=c(2002,2020),breaks=scales::breaks_width(2)) +\n scale_fill_viridis_d(begin=0.25,end=0.9) +\n guides(fill=guide_legend(reverse=TRUE))\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nTip\n\n\n\nThere is both an art and a science behind choosing colors for plots. Unfortunately, I am not strong nor fully knowledgeable in either. Thus, I show how to alter colors here, but I don’t claim that these choices are ideal.\n\n\n\n\nAdd Lines\nI sometimes feel that the colors in area plots “run together” in my eyes. One way to make more clear “breaks” is to highlight the color changes. Below I also map Age to color=, use scale_color_viridis_d() with the same options as scale_fill_viridis_d(), except that for the fill I set a slight transparency with alpha=. Here color= is used for the boundaries of the areas and since the fill was made transparent these boundaries are a bit darker and, thus, appear as lines between the areas. Further note that both fill= and color= had to be “reversed” in guides().\n\nggplot(data=dat2,mapping=aes(x=Year,y=Proportion,fill=Age,color=Age)) +\n geom_area(position=position_stack(reverse=TRUE),linewidth=0.75) +\n scale_y_continuous(expand=expansion(mult=0),\n breaks=scales::breaks_width(0.1)) +\n scale_x_continuous(expand=expansion(mult=0),\n limits=c(2002,2020),breaks=scales::breaks_width(2)) +\n scale_color_viridis_d(begin=0.25,end=0.9) +\n scale_fill_viridis_d(begin=0.25,end=0.9,alpha=0.75) +\n guides(fill=guide_legend(reverse=TRUE),\n color=guide_legend(reverse=TRUE))\n\n\n\n\n\n\n\n\n\n\nBar Chart\nMost people that eschew the use of area plots suggests using bar charts instead. This is easily accomplished here by replacing geom_area() with geom_col(). However, the limits of the x-axis will need to be extended by one year on both sides so that the first and last year will be shown correctly.\n\nggplot(data=dat2,mapping=aes(x=Year,y=Proportion,fill=Age)) +\n geom_col(position=position_stack(reverse=TRUE)) +\n scale_y_continuous(expand=expansion(mult=0),\n breaks=scales::breaks_width(0.1)) +\n scale_x_continuous(expand=expansion(mult=0),\n limits=c(2001,2021),breaks=scales::breaks_width(2)) +\n scale_fill_viridis_d(begin=0.25,end=0.9) +\n guides(fill=guide_legend(reverse=TRUE))\n\n\n\n\n\n\n\n\n\n\nFacets\nFinally, I think that if the goal is to show annular trends for the specific ages, that they should be plotted as lines for each age. Here lines are used with geom_line() and faceting was used on Age. The use of color is superfluous here, but I kept it for comparing with the previous options.\n\nggplot(data=dat2,mapping=aes(x=Year,y=Proportion,color=Age)) +\n geom_line(linewidth=0.75) +\n scale_y_continuous(expand=expansion(mult=c(0,0.025)),\n breaks=scales::breaks_width(0.1)) +\n scale_x_continuous(expand=expansion(mult=0),\n limits=c(2002,2020),breaks=scales::breaks_width(2)) +\n scale_color_viridis_d(begin=0.25,end=0.9) +\n lemon::facet_rep_wrap(vars(Age),ncol=1,strip.position=\"right\") +\n theme(legend.position=\"none\")\n\n\n\n\n\n\n\n\nIn my view, it is much easier to decipher what is going on with age-2 to age-4 fish from this plot.\n \n\n\n\n\n\n\n\n\n\n\nReferences\n\nMcCarrick, D. K., J. C. Dillon, B. High, and M. C. Quist. 2022. Population dynamics of Yellowstone Cutthroat Trout in Henrys Lake, Idaho. Journal of Fish and Wildlife Management 13(1):169–181.\n\nReusehttps://creativecommons.org/licenses/by/4.0/CitationBibTeX citation:@online{h.ogle2023,\n author = {Derek H. Ogle},\n title = {McCarrick Et Al. (2022) {Age} {Composition} {Plot}},\n date = {2023-03-27},\n url = {https://fishr-core-team.github.io/fishR//blog/posts/2023-3-27_McCarricketal2022_Fig5},\n langid = {en}\n}\nFor attribution, please cite this work as:\nDerek H. Ogle. 2023, March 27. McCarrick et al. (2022) Age Composition\nPlot. https://fishr-core-team.github.io/fishR//blog/posts/2023-3-27_McCarricketal2022_Fig5." - }, - { - "objectID": "blog/posts/2023-3-27_McCarricketal2022_Fig5/index.html#take-note", - "href": "blog/posts/2023-3-27_McCarricketal2022_Fig5/index.html#take-note", - "title": "McCarrick et al. (2022) Age Composition Plot", - "section": "Take Note", - "text": "Take Note\nThere is both an art and a science behind choosing colors for plots. Unfortunately, I am not strong nor fully knowledgeable in either. Thus, I show how to alter colors here, but I don’t claim that these choices are ideal." } ] \ No newline at end of file diff --git a/docs/sitemap.xml b/docs/sitemap.xml index 00feff7..b414bf2 100644 --- a/docs/sitemap.xml +++ b/docs/sitemap.xml @@ -2,350 +2,350 @@ https://fishr-core-team.github.io/fishR/blog/index.html - 2023-03-25T16:19:37.383Z + 2023-03-26T14:30:34.188Z https://fishr-core-team.github.io/fishR/blog/posts/2015-9-5_Age_Comparison_Results/index.html - 2023-03-19T22:44:51.091Z + 2023-03-26T14:30:42.268Z https://fishr-core-team.github.io/fishR/blog/posts/2015-9-6_Cumulative_Sums/index.html - 2023-03-19T22:44:56.868Z + 2023-03-26T14:30:47.555Z https://fishr-core-team.github.io/fishR/blog/posts/2016-11-11_Pauly-VBModel/index.html - 2023-03-19T22:45:02.440Z + 2023-03-26T14:30:52.580Z https://fishr-core-team.github.io/fishR/blog/posts/2016-12-9_PSD_SE/index.html - 2023-03-19T22:45:08.238Z + 2023-03-26T14:30:57.701Z https://fishr-core-team.github.io/fishR/blog/posts/2017-11-7_BackCalculationPlot/index.html - 2023-03-19T22:45:13.666Z + 2023-03-26T14:31:03.028Z https://fishr-core-team.github.io/fishR/blog/posts/2017-12-12_StockRecruit_Graph_Questions/index.html - 2023-03-19T22:45:19.169Z + 2023-03-26T14:31:08.465Z https://fishr-core-team.github.io/fishR/blog/posts/2017-4-20_BlandAltman/index.html - 2023-03-19T22:45:24.781Z + 2023-03-26T14:31:14.323Z https://fishr-core-team.github.io/fishR/blog/posts/2017-7-28_LF_Ridgeline_Plot/index.html - 2023-03-19T22:45:29.987Z + 2023-03-26T14:31:19.776Z https://fishr-core-team.github.io/fishR/blog/posts/2017-8-9_Mean_Weights/index.html - 2023-03-19T22:45:36.524Z + 2023-03-26T14:31:25.865Z https://fishr-core-team.github.io/fishR/blog/posts/2018-3-30_Collapsing_Categories_or_Values/index.html - 2023-03-19T22:45:41.962Z + 2023-03-26T14:31:31.843Z https://fishr-core-team.github.io/fishR/blog/posts/2019-12-28_Length_Frequency_Histograms/index.html - 2023-03-19T22:45:47.339Z + 2023-03-26T14:31:37.320Z https://fishr-core-team.github.io/fishR/blog/posts/2019-12-31_vonB_plots_1/index.html - 2023-03-19T22:45:53.057Z + 2023-03-26T14:31:42.975Z https://fishr-core-team.github.io/fishR/blog/posts/2020-1-2_vonB_plots_2/index.html - 2023-03-19T22:45:59.108Z + 2023-03-26T14:31:49.007Z https://fishr-core-team.github.io/fishR/blog/posts/2021-3-15-AgeBiasPlots/index.html - 2023-03-19T22:46:04.621Z + 2023-03-26T14:31:54.981Z https://fishr-core-team.github.io/fishR/blog/posts/2021-5-11_compSlopes-replacement/index.html - 2023-03-19T22:46:13.204Z + 2023-03-26T14:32:00.644Z https://fishr-core-team.github.io/fishR/blog/posts/2021-5-12_compIntercepts-replacement/index.html - 2023-03-19T22:46:19.493Z + 2023-03-26T14:32:06.158Z https://fishr-core-team.github.io/fishR/blog/posts/2021-5-25_fitPlot-replacement/index.html - 2023-03-19T22:46:25.893Z + 2023-03-26T14:32:12.473Z https://fishr-core-team.github.io/fishR/blog/posts/2021-5-26_filterD-replacement/index.html - 2023-03-19T22:46:31.115Z + 2023-03-26T14:32:17.533Z https://fishr-core-team.github.io/fishR/blog/posts/2021-6-1_residPlot-replacement/index.html - 2023-03-19T22:46:37.000Z + 2023-03-26T14:32:23.109Z https://fishr-core-team.github.io/fishR/blog/posts/2022-12-22_AFS_Style_Figures/index.html - 2023-03-19T22:46:43.128Z + 2023-03-26T14:32:28.627Z https://fishr-core-team.github.io/fishR/blog/posts/2023-2-15_Vaisviletal2022_ROC/index.html - 2023-03-19T22:46:48.761Z + 2023-03-26T14:32:34.063Z https://fishr-core-team.github.io/fishR/blog/posts/2023-2-16_Ulaskietal_GrowthMortFig/index.html - 2023-03-19T22:46:54.563Z + 2023-03-26T14:32:39.611Z https://fishr-core-team.github.io/fishR/blog/posts/2023-3-10-Text_Annotation_Position/index.html - 2023-03-19T22:47:00.340Z + 2023-03-26T14:32:45.091Z https://fishr-core-team.github.io/fishR/blog/posts/2023-3-15-Axis_Magic/index.html - 2023-03-21T20:19:16.989Z + 2023-03-26T14:32:52.443Z https://fishr-core-team.github.io/fishR/blog/posts/2023-3-18-Rooketal2022_CiscoHarvest/index.html - 2023-03-21T20:19:30.421Z + 2023-03-26T14:32:58.654Z https://fishr-core-team.github.io/fishR/blog/posts/2023-3-20-Rooketal2022_Fig4/index.html - 2023-03-19T22:47:19.171Z + 2023-03-26T14:33:04.111Z + + + https://fishr-core-team.github.io/fishR/blog/posts/2023-3-22_McCarricketal2022_Fig2/index.html + 2023-03-26T14:33:09.809Z + + + https://fishr-core-team.github.io/fishR/blog/posts/2023-3-25_McCarricketal2022_Fig3/index.html + 2023-03-26T14:33:15.552Z + + + https://fishr-core-team.github.io/fishR/blog/posts/2023-3-26_McCarricketal2022_Fig4/index.html + 2023-03-26T14:33:21.517Z + + + https://fishr-core-team.github.io/fishR/blog/posts/2023-3-27_McCarricketal2022_Fig5/index.html + 2023-03-26T14:33:27.103Z https://fishr-core-team.github.io/fishR/blog/posts/2023-3-6_Landryetal2022_LogRegress/index.html - 2023-03-19T22:47:25.156Z + 2023-03-26T14:33:32.790Z https://fishr-core-team.github.io/fishR/blog/posts/2023-3-8_MackCheatwood2022_CumSums/index.html - 2023-03-19T22:47:30.588Z + 2023-03-26T14:33:38.149Z https://fishr-core-team.github.io/fishR/blog/posts/2023-3-9-Clemens2022/index.html - 2023-03-19T22:47:36.185Z + 2023-03-26T14:33:43.524Z https://fishr-core-team.github.io/fishR/blog/posts/2023_2_13_Quistetal2022_AgeData/index.html - 2023-03-19T22:47:41.628Z + 2023-03-26T14:33:48.899Z https://fishr-core-team.github.io/fishR/blog/posts/2023_2_14_Quistetal2022_BCData/index.html - 2023-03-19T22:47:47.196Z + 2023-03-26T14:33:54.117Z https://fishr-core-team.github.io/fishR/index.html - 2023-03-19T22:47:50.669Z + 2023-03-26T14:33:57.475Z https://fishr-core-team.github.io/fishR/pages/books.html - 2023-03-19T22:47:52.131Z + 2023-03-26T14:33:58.993Z https://fishr-core-team.github.io/fishR/pages/contribute.html - 2023-03-19T22:47:53.619Z + 2023-03-26T14:34:00.380Z https://fishr-core-team.github.io/fishR/pages/data_Comp_byPackage.html - 2023-03-19T22:47:55.692Z + 2023-03-26T14:34:02.427Z https://fishr-core-team.github.io/fishR/pages/data_Comp_byTopic.html - 2023-03-19T22:47:57.937Z + 2023-03-26T14:34:04.646Z https://fishr-core-team.github.io/fishR/pages/data_fishR_alpha.html - 2023-03-19T22:47:59.926Z + 2023-03-26T14:34:06.510Z https://fishr-core-team.github.io/fishR/pages/data_fishR_byTopic.html - 2023-03-19T22:48:02.170Z + 2023-03-26T14:34:08.553Z https://fishr-core-team.github.io/fishR/pages/packages.html - 2023-03-22T18:41:20.893Z + 2023-03-26T14:34:10.113Z https://fishr-core-team.github.io/fishR/teaching/index.html - 2023-03-19T22:48:06.726Z + 2023-03-26T14:34:12.864Z https://fishr-core-team.github.io/fishR/teaching/posts/2016-6-12_Halflife_of_K/index.html - 2023-03-19T22:48:12.114Z + 2023-03-26T14:34:18.245Z https://fishr-core-team.github.io/fishR/teaching/posts/2018-4-19_Adding_Zero_Catches/index.html - 2023-03-19T22:48:15.926Z + 2023-03-26T14:34:21.690Z https://fishr-core-team.github.io/fishR/teaching/posts/2019-3-8_AgeComparisons_LCWhitefish/index.html - 2023-03-19T22:48:19.120Z + 2023-03-26T14:34:24.753Z https://fishr-core-team.github.io/fishR/teaching/posts/2019-3-8_ALK_FWDrumLE/index.html - 2023-03-19T22:48:22.648Z + 2023-03-26T14:34:27.877Z https://fishr-core-team.github.io/fishR/teaching/posts/2019-3-8_ALK_RockBassLO/index.html - 2023-03-19T22:48:25.977Z + 2023-03-26T14:34:31.174Z https://fishr-core-team.github.io/fishR/teaching/posts/2019-3-8_ALK_StripedBass/index.html - 2023-03-19T22:48:29.085Z + 2023-03-26T14:34:34.263Z https://fishr-core-team.github.io/fishR/teaching/posts/2019-3-8_Condition_BGInch/index.html - 2023-03-19T22:48:32.177Z + 2023-03-26T14:34:37.235Z https://fishr-core-team.github.io/fishR/teaching/posts/2019-3-8_Depletion_LGLargemouth/index.html - 2023-03-19T22:48:35.562Z + 2023-03-26T14:34:40.298Z https://fishr-core-team.github.io/fishR/teaching/posts/2019-3-8_Graphing_Inch/index.html - 2023-03-19T22:48:38.658Z + 2023-03-26T14:34:43.611Z https://fishr-core-team.github.io/fishR/teaching/posts/2019-3-8_Graphing_YPerchTL/index.html - 2023-03-19T22:48:41.763Z + 2023-03-26T14:34:46.657Z https://fishr-core-team.github.io/fishR/teaching/posts/2019-3-8_Growth_EuroPerch/index.html - 2023-03-19T22:48:45.008Z + 2023-03-26T14:34:49.672Z https://fishr-core-team.github.io/fishR/teaching/posts/2019-3-8_Growth_RockBassLO/index.html - 2023-03-19T22:48:48.154Z + 2023-03-26T14:34:52.859Z https://fishr-core-team.github.io/fishR/teaching/posts/2019-3-8_Growth_Sculpin/index.html - 2023-03-19T22:48:51.281Z + 2023-03-26T14:34:55.921Z https://fishr-core-team.github.io/fishR/teaching/posts/2019-3-8_Mortality_LSKBLakeTrout/index.html - 2023-03-19T22:48:54.347Z + 2023-03-26T14:34:58.890Z https://fishr-core-team.github.io/fishR/teaching/posts/2019-3-8_Mortality_LSSRLakeTrout/index.html - 2023-03-19T22:48:57.588Z + 2023-03-26T14:35:01.936Z https://fishr-core-team.github.io/fishR/teaching/posts/2019-3-8_MR_TanRiffleshell/index.html - 2023-03-19T22:49:00.654Z + 2023-03-26T14:35:05.081Z https://fishr-core-team.github.io/fishR/teaching/posts/2019-3-8_MR_UNSPRainbowTrout/index.html - 2023-03-19T22:49:03.759Z + 2023-03-26T14:35:08.188Z https://fishr-core-team.github.io/fishR/teaching/posts/2019-3-8_MR_URBrownTrout/index.html - 2023-03-19T22:49:06.850Z + 2023-03-26T14:35:11.169Z https://fishr-core-team.github.io/fishR/teaching/posts/2019-3-8_MR_WIYOYWalleye/index.html - 2023-03-19T22:49:10.399Z + 2023-03-26T14:35:14.232Z https://fishr-core-team.github.io/fishR/teaching/posts/2019-3-8_Recruitment_WalleyeEL/index.html - 2023-03-19T22:49:13.816Z + 2023-03-26T14:35:17.233Z https://fishr-core-team.github.io/fishR/teaching/posts/2019-3-8_SizeStrux_YPerchTL/index.html - 2023-03-19T22:49:16.890Z + 2023-03-26T14:35:20.265Z https://fishr-core-team.github.io/fishR/teaching/posts/2019-3-8_WLBluegill_Inch/index.html - 2023-03-19T22:49:20.217Z + 2023-03-26T14:35:23.340Z https://fishr-core-team.github.io/fishR/teaching/posts/2019-3-8_WLLMB_Inch/index.html - 2023-03-19T22:49:23.375Z + 2023-03-26T14:35:26.355Z https://fishr-core-team.github.io/fishR/teaching/posts/2019-3-8_WL_YPerchTL/index.html - 2023-03-19T22:49:26.744Z + 2023-03-26T14:35:29.448Z https://fishr-core-team.github.io/fishR/teaching/posts/2019-3-8_Wrangling_Inch/index.html - 2023-03-19T22:49:30.082Z + 2023-03-26T14:35:32.478Z https://fishr-core-team.github.io/fishR/teaching/posts/2019-3-8_Wrangling_YPerchTL/index.html - 2023-03-19T22:49:33.238Z + 2023-03-26T14:35:35.510Z https://fishr-core-team.github.io/fishR/teaching/posts/2022-12-19_AgeComp_WalleyePS/index.html - 2023-03-19T22:49:36.384Z + 2023-03-26T14:35:38.547Z https://fishr-core-team.github.io/fishR/teaching/posts/2022-12-19_SizeStrux_YPerchSB1/index.html - 2023-03-19T22:49:39.446Z + 2023-03-26T14:35:41.634Z https://fishr-core-team.github.io/fishR/teaching/posts/2022-12-19_Using_fishR_Data/index.html - 2023-03-19T22:49:42.765Z + 2023-03-26T14:35:44.945Z https://fishr-core-team.github.io/fishR/teaching/posts/2022-12-20_SizeStrux_Whittlesey/index.html - 2023-03-19T22:49:45.862Z + 2023-03-26T14:35:47.995Z https://fishr-core-team.github.io/fishR/teaching/posts/2022-12-21_SizeStrux_BGLouise/index.html - 2023-03-19T22:49:48.865Z + 2023-03-26T14:35:51.008Z https://fishr-core-team.github.io/fishR/teaching/posts/2022-12-22_BagLimits_MN/index.html - 2023-03-19T22:49:52.404Z + 2023-03-26T14:35:54.664Z https://fishr-core-team.github.io/fishR/teaching/posts/2022-12-23_Depletion_Ruffe/index.html - 2023-03-19T22:49:55.350Z + 2023-03-26T14:35:57.742Z https://fishr-core-team.github.io/fishR/teaching/posts/2022-12-23_MR_SeaLamprey/index.html - 2023-03-19T22:49:58.285Z + 2023-03-26T14:36:01.693Z https://fishr-core-team.github.io/fishR/teaching/posts/2022-12-23_Removal_Crayfish/index.html - 2023-03-19T22:50:01.269Z + 2023-03-26T14:36:04.828Z https://fishr-core-team.github.io/fishR/teaching/posts/2022-12-23_Removal_EBullhead/index.html - 2023-03-19T22:50:04.361Z + 2023-03-26T14:36:08.171Z https://fishr-core-team.github.io/fishR/teaching/resources/Crappiesum.html - 2023-03-19T22:50:07.801Z + 2023-03-26T14:36:11.854Z https://fishr-core-team.github.io/fishR/teaching/resources/LMBsum.html - 2023-03-19T22:50:09.339Z + 2023-03-26T14:36:13.552Z https://fishr-core-team.github.io/fishR/teaching/resources/NOPsum.html - 2023-03-19T22:50:10.974Z + 2023-03-26T14:36:15.361Z https://fishr-core-team.github.io/fishR/teaching/resources/Sunfishsum.html - 2023-03-19T22:50:12.624Z + 2023-03-26T14:36:17.300Z https://fishr-core-team.github.io/fishR/teaching/resources/WAEsum.html - 2023-03-19T22:50:14.231Z + 2023-03-26T14:36:19.091Z https://fishr-core-team.github.io/fishR/teaching/resources/YEPsum.html - 2023-03-19T22:50:15.739Z - - - https://fishr-core-team.github.io/fishR/blog/posts/2023-3-22_McCarricketal2022_Fig2/index.html - 2023-03-22T21:39:44.221Z - - - https://fishr-core-team.github.io/fishR/blog/posts/2023-3-25_McCarricketal2022_Fig3/index.html - 2023-03-23T13:02:12.518Z - - - https://fishr-core-team.github.io/fishR/blog/posts/2023-3-26_McCarricketal2022_Fig4/index.html - 2023-03-24T13:33:18.832Z - - - https://fishr-core-team.github.io/fishR/blog/posts/2023-3-27_McCarricketal2022_Fig5/index.html - 2023-03-25T16:19:32.857Z + 2023-03-26T14:36:20.645Z diff --git a/docs/teaching/posts/2016-6-12_Halflife_of_K/index.html b/docs/teaching/posts/2016-6-12_Halflife_of_K/index.html index c3f0118..995a1aa 100644 --- a/docs/teaching/posts/2016-6-12_Halflife_of_K/index.html +++ b/docs/teaching/posts/2016-6-12_Halflife_of_K/index.html @@ -146,6 +146,7 @@ + @@ -168,6 +169,7 @@ + diff --git a/docs/teaching/posts/2018-4-19_Adding_Zero_Catches/index.html b/docs/teaching/posts/2018-4-19_Adding_Zero_Catches/index.html index 1ea21fc..451f9be 100644 --- a/docs/teaching/posts/2018-4-19_Adding_Zero_Catches/index.html +++ b/docs/teaching/posts/2018-4-19_Adding_Zero_Catches/index.html @@ -145,6 +145,7 @@ + @@ -167,6 +168,7 @@ + diff --git a/docs/teaching/posts/2019-3-8_ALK_FWDrumLE/index.html b/docs/teaching/posts/2019-3-8_ALK_FWDrumLE/index.html index f48080d..515369c 100644 --- a/docs/teaching/posts/2019-3-8_ALK_FWDrumLE/index.html +++ b/docs/teaching/posts/2019-3-8_ALK_FWDrumLE/index.html @@ -101,6 +101,7 @@ + @@ -123,6 +124,7 @@ + diff --git a/docs/teaching/posts/2019-3-8_ALK_RockBassLO/index.html b/docs/teaching/posts/2019-3-8_ALK_RockBassLO/index.html index 2ee24af..5efd434 100644 --- a/docs/teaching/posts/2019-3-8_ALK_RockBassLO/index.html +++ b/docs/teaching/posts/2019-3-8_ALK_RockBassLO/index.html @@ -101,6 +101,7 @@ + @@ -123,6 +124,7 @@ + diff --git a/docs/teaching/posts/2019-3-8_ALK_StripedBass/index.html b/docs/teaching/posts/2019-3-8_ALK_StripedBass/index.html index 876c166..ad367d4 100644 --- a/docs/teaching/posts/2019-3-8_ALK_StripedBass/index.html +++ b/docs/teaching/posts/2019-3-8_ALK_StripedBass/index.html @@ -101,6 +101,7 @@ + @@ -123,6 +124,7 @@ + diff --git a/docs/teaching/posts/2019-3-8_AgeComparisons_LCWhitefish/index.html b/docs/teaching/posts/2019-3-8_AgeComparisons_LCWhitefish/index.html index 9d63617..d2b3bb5 100644 --- a/docs/teaching/posts/2019-3-8_AgeComparisons_LCWhitefish/index.html +++ b/docs/teaching/posts/2019-3-8_AgeComparisons_LCWhitefish/index.html @@ -101,6 +101,7 @@ + @@ -123,6 +124,7 @@ + diff --git a/docs/teaching/posts/2019-3-8_Condition_BGInch/index.html b/docs/teaching/posts/2019-3-8_Condition_BGInch/index.html index 49ad8da..6684262 100644 --- a/docs/teaching/posts/2019-3-8_Condition_BGInch/index.html +++ b/docs/teaching/posts/2019-3-8_Condition_BGInch/index.html @@ -82,6 +82,7 @@ + @@ -104,6 +105,7 @@ + diff --git a/docs/teaching/posts/2019-3-8_Depletion_LGLargemouth/index.html b/docs/teaching/posts/2019-3-8_Depletion_LGLargemouth/index.html index 27d432a..4a27d22 100644 --- a/docs/teaching/posts/2019-3-8_Depletion_LGLargemouth/index.html +++ b/docs/teaching/posts/2019-3-8_Depletion_LGLargemouth/index.html @@ -102,6 +102,7 @@ + @@ -124,6 +125,7 @@ + diff --git a/docs/teaching/posts/2019-3-8_Graphing_Inch/index.html b/docs/teaching/posts/2019-3-8_Graphing_Inch/index.html index 24ea9e2..9e296bd 100644 --- a/docs/teaching/posts/2019-3-8_Graphing_Inch/index.html +++ b/docs/teaching/posts/2019-3-8_Graphing_Inch/index.html @@ -82,6 +82,7 @@ + @@ -104,6 +105,7 @@ + diff --git a/docs/teaching/posts/2019-3-8_Graphing_YPerchTL/index.html b/docs/teaching/posts/2019-3-8_Graphing_YPerchTL/index.html index f780c74..87647f6 100644 --- a/docs/teaching/posts/2019-3-8_Graphing_YPerchTL/index.html +++ b/docs/teaching/posts/2019-3-8_Graphing_YPerchTL/index.html @@ -82,6 +82,7 @@ + @@ -104,6 +105,7 @@ + diff --git a/docs/teaching/posts/2019-3-8_Growth_EuroPerch/index.html b/docs/teaching/posts/2019-3-8_Growth_EuroPerch/index.html index 1a5bb77..8f318e7 100644 --- a/docs/teaching/posts/2019-3-8_Growth_EuroPerch/index.html +++ b/docs/teaching/posts/2019-3-8_Growth_EuroPerch/index.html @@ -102,6 +102,7 @@ + @@ -124,6 +125,7 @@ + diff --git a/docs/teaching/posts/2019-3-8_Growth_RockBassLO/index.html b/docs/teaching/posts/2019-3-8_Growth_RockBassLO/index.html index b8cd199..d12e380 100644 --- a/docs/teaching/posts/2019-3-8_Growth_RockBassLO/index.html +++ b/docs/teaching/posts/2019-3-8_Growth_RockBassLO/index.html @@ -102,6 +102,7 @@ + @@ -124,6 +125,7 @@ + diff --git a/docs/teaching/posts/2019-3-8_Growth_Sculpin/index.html b/docs/teaching/posts/2019-3-8_Growth_Sculpin/index.html index 49fd927..8a6f701 100644 --- a/docs/teaching/posts/2019-3-8_Growth_Sculpin/index.html +++ b/docs/teaching/posts/2019-3-8_Growth_Sculpin/index.html @@ -83,6 +83,7 @@ + @@ -105,6 +106,7 @@ + diff --git a/docs/teaching/posts/2019-3-8_MR_TanRiffleshell/index.html b/docs/teaching/posts/2019-3-8_MR_TanRiffleshell/index.html index 597b211..1d7b8f8 100644 --- a/docs/teaching/posts/2019-3-8_MR_TanRiffleshell/index.html +++ b/docs/teaching/posts/2019-3-8_MR_TanRiffleshell/index.html @@ -101,6 +101,7 @@ + @@ -123,6 +124,7 @@ + diff --git a/docs/teaching/posts/2019-3-8_MR_UNSPRainbowTrout/index.html b/docs/teaching/posts/2019-3-8_MR_UNSPRainbowTrout/index.html index a793143..3215f6a 100644 --- a/docs/teaching/posts/2019-3-8_MR_UNSPRainbowTrout/index.html +++ b/docs/teaching/posts/2019-3-8_MR_UNSPRainbowTrout/index.html @@ -102,6 +102,7 @@ + @@ -124,6 +125,7 @@ + diff --git a/docs/teaching/posts/2019-3-8_MR_URBrownTrout/index.html b/docs/teaching/posts/2019-3-8_MR_URBrownTrout/index.html index 07274f9..12cb792 100644 --- a/docs/teaching/posts/2019-3-8_MR_URBrownTrout/index.html +++ b/docs/teaching/posts/2019-3-8_MR_URBrownTrout/index.html @@ -102,6 +102,7 @@ + @@ -124,6 +125,7 @@ + diff --git a/docs/teaching/posts/2019-3-8_MR_WIYOYWalleye/index.html b/docs/teaching/posts/2019-3-8_MR_WIYOYWalleye/index.html index 47cf963..0b74953 100644 --- a/docs/teaching/posts/2019-3-8_MR_WIYOYWalleye/index.html +++ b/docs/teaching/posts/2019-3-8_MR_WIYOYWalleye/index.html @@ -104,6 +104,7 @@ + @@ -126,6 +127,7 @@ + diff --git a/docs/teaching/posts/2019-3-8_Mortality_LSKBLakeTrout/index.html b/docs/teaching/posts/2019-3-8_Mortality_LSKBLakeTrout/index.html index 11dfda9..ce05fa0 100644 --- a/docs/teaching/posts/2019-3-8_Mortality_LSKBLakeTrout/index.html +++ b/docs/teaching/posts/2019-3-8_Mortality_LSKBLakeTrout/index.html @@ -101,6 +101,7 @@ + @@ -123,6 +124,7 @@ + diff --git a/docs/teaching/posts/2019-3-8_Mortality_LSSRLakeTrout/index.html b/docs/teaching/posts/2019-3-8_Mortality_LSSRLakeTrout/index.html index 4288552..d384747 100644 --- a/docs/teaching/posts/2019-3-8_Mortality_LSSRLakeTrout/index.html +++ b/docs/teaching/posts/2019-3-8_Mortality_LSSRLakeTrout/index.html @@ -101,6 +101,7 @@ + @@ -123,6 +124,7 @@ + diff --git a/docs/teaching/posts/2019-3-8_Recruitment_WalleyeEL/index.html b/docs/teaching/posts/2019-3-8_Recruitment_WalleyeEL/index.html index 8ad9fed..c1e5294 100644 --- a/docs/teaching/posts/2019-3-8_Recruitment_WalleyeEL/index.html +++ b/docs/teaching/posts/2019-3-8_Recruitment_WalleyeEL/index.html @@ -101,6 +101,7 @@ + @@ -123,6 +124,7 @@ + diff --git a/docs/teaching/posts/2019-3-8_SizeStrux_YPerchTL/index.html b/docs/teaching/posts/2019-3-8_SizeStrux_YPerchTL/index.html index 1460b89..9315b5c 100644 --- a/docs/teaching/posts/2019-3-8_SizeStrux_YPerchTL/index.html +++ b/docs/teaching/posts/2019-3-8_SizeStrux_YPerchTL/index.html @@ -82,6 +82,7 @@ + @@ -104,6 +105,7 @@ + diff --git a/docs/teaching/posts/2019-3-8_WLBluegill_Inch/index.html b/docs/teaching/posts/2019-3-8_WLBluegill_Inch/index.html index 1b67e9a..a969baf 100644 --- a/docs/teaching/posts/2019-3-8_WLBluegill_Inch/index.html +++ b/docs/teaching/posts/2019-3-8_WLBluegill_Inch/index.html @@ -82,6 +82,7 @@ + @@ -104,6 +105,7 @@ + diff --git a/docs/teaching/posts/2019-3-8_WLLMB_Inch/index.html b/docs/teaching/posts/2019-3-8_WLLMB_Inch/index.html index 2ddf675..e09491b 100644 --- a/docs/teaching/posts/2019-3-8_WLLMB_Inch/index.html +++ b/docs/teaching/posts/2019-3-8_WLLMB_Inch/index.html @@ -82,6 +82,7 @@ + @@ -104,6 +105,7 @@ + diff --git a/docs/teaching/posts/2019-3-8_WL_YPerchTL/index.html b/docs/teaching/posts/2019-3-8_WL_YPerchTL/index.html index 2aab7cd..c2f1249 100644 --- a/docs/teaching/posts/2019-3-8_WL_YPerchTL/index.html +++ b/docs/teaching/posts/2019-3-8_WL_YPerchTL/index.html @@ -82,6 +82,7 @@ + @@ -104,6 +105,7 @@ + diff --git a/docs/teaching/posts/2019-3-8_Wrangling_Inch/index.html b/docs/teaching/posts/2019-3-8_Wrangling_Inch/index.html index 2ea75cf..0ea1d8c 100644 --- a/docs/teaching/posts/2019-3-8_Wrangling_Inch/index.html +++ b/docs/teaching/posts/2019-3-8_Wrangling_Inch/index.html @@ -82,6 +82,7 @@ + @@ -104,6 +105,7 @@ + diff --git a/docs/teaching/posts/2019-3-8_Wrangling_YPerchTL/index.html b/docs/teaching/posts/2019-3-8_Wrangling_YPerchTL/index.html index 90faf52..24f18ca 100644 --- a/docs/teaching/posts/2019-3-8_Wrangling_YPerchTL/index.html +++ b/docs/teaching/posts/2019-3-8_Wrangling_YPerchTL/index.html @@ -82,6 +82,7 @@ + @@ -104,6 +105,7 @@ + diff --git a/docs/teaching/posts/2022-12-19_AgeComp_WalleyePS/index.html b/docs/teaching/posts/2022-12-19_AgeComp_WalleyePS/index.html index 59e7ea0..03233f2 100644 --- a/docs/teaching/posts/2022-12-19_AgeComp_WalleyePS/index.html +++ b/docs/teaching/posts/2022-12-19_AgeComp_WalleyePS/index.html @@ -101,6 +101,7 @@ + @@ -123,6 +124,7 @@ + diff --git a/docs/teaching/posts/2022-12-19_SizeStrux_YPerchSB1/index.html b/docs/teaching/posts/2022-12-19_SizeStrux_YPerchSB1/index.html index 3532366..d0c67d5 100644 --- a/docs/teaching/posts/2022-12-19_SizeStrux_YPerchSB1/index.html +++ b/docs/teaching/posts/2022-12-19_SizeStrux_YPerchSB1/index.html @@ -101,6 +101,7 @@ + @@ -123,6 +124,7 @@ + diff --git a/docs/teaching/posts/2022-12-19_Using_fishR_Data/index.html b/docs/teaching/posts/2022-12-19_Using_fishR_Data/index.html index 768ec90..6b5e020 100644 --- a/docs/teaching/posts/2022-12-19_Using_fishR_Data/index.html +++ b/docs/teaching/posts/2022-12-19_Using_fishR_Data/index.html @@ -145,6 +145,7 @@ + @@ -167,6 +168,7 @@ + diff --git a/docs/teaching/posts/2022-12-20_SizeStrux_Whittlesey/index.html b/docs/teaching/posts/2022-12-20_SizeStrux_Whittlesey/index.html index 4ed7dc0..ec430ca 100644 --- a/docs/teaching/posts/2022-12-20_SizeStrux_Whittlesey/index.html +++ b/docs/teaching/posts/2022-12-20_SizeStrux_Whittlesey/index.html @@ -82,6 +82,7 @@ + @@ -104,6 +105,7 @@ + diff --git a/docs/teaching/posts/2022-12-21_SizeStrux_BGLouise/index.html b/docs/teaching/posts/2022-12-21_SizeStrux_BGLouise/index.html index a90e76f..deb4e27 100644 --- a/docs/teaching/posts/2022-12-21_SizeStrux_BGLouise/index.html +++ b/docs/teaching/posts/2022-12-21_SizeStrux_BGLouise/index.html @@ -82,6 +82,7 @@ + @@ -104,6 +105,7 @@ + diff --git a/docs/teaching/posts/2022-12-22_BagLimits_MN/index.html b/docs/teaching/posts/2022-12-22_BagLimits_MN/index.html index bd661ee..f191fc5 100644 --- a/docs/teaching/posts/2022-12-22_BagLimits_MN/index.html +++ b/docs/teaching/posts/2022-12-22_BagLimits_MN/index.html @@ -104,6 +104,7 @@ + @@ -126,6 +127,7 @@ + diff --git a/docs/teaching/posts/2022-12-23_Depletion_Ruffe/index.html b/docs/teaching/posts/2022-12-23_Depletion_Ruffe/index.html index 43dcf95..dcda0d6 100644 --- a/docs/teaching/posts/2022-12-23_Depletion_Ruffe/index.html +++ b/docs/teaching/posts/2022-12-23_Depletion_Ruffe/index.html @@ -101,6 +101,7 @@ + @@ -123,6 +124,7 @@ + diff --git a/docs/teaching/posts/2022-12-23_MR_SeaLamprey/index.html b/docs/teaching/posts/2022-12-23_MR_SeaLamprey/index.html index 5943513..9026d0a 100644 --- a/docs/teaching/posts/2022-12-23_MR_SeaLamprey/index.html +++ b/docs/teaching/posts/2022-12-23_MR_SeaLamprey/index.html @@ -101,6 +101,7 @@ + @@ -123,6 +124,7 @@ + diff --git a/docs/teaching/posts/2022-12-23_Removal_Crayfish/index.html b/docs/teaching/posts/2022-12-23_Removal_Crayfish/index.html index d6e69e5..b9565e8 100644 --- a/docs/teaching/posts/2022-12-23_Removal_Crayfish/index.html +++ b/docs/teaching/posts/2022-12-23_Removal_Crayfish/index.html @@ -101,6 +101,7 @@ + @@ -123,6 +124,7 @@ + diff --git a/docs/teaching/posts/2022-12-23_Removal_EBullhead/index.html b/docs/teaching/posts/2022-12-23_Removal_EBullhead/index.html index 8fa33ac..f94e0ef 100644 --- a/docs/teaching/posts/2022-12-23_Removal_EBullhead/index.html +++ b/docs/teaching/posts/2022-12-23_Removal_EBullhead/index.html @@ -101,6 +101,7 @@ + @@ -123,6 +124,7 @@ +