Skip to content

Commit dd7a021

Browse files
committed
updated README, added contributing and Code of Conduct files
1 parent 39dcad0 commit dd7a021

15 files changed

Lines changed: 372 additions & 33 deletions

CONDUCT.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Contributor Code of Conduct
2+
3+
As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
4+
5+
We are committed to making participation in this project a harassment-free experience for everyone, regardless of regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socioeconomic status, nationality, personal appearance, race, caste, color, religion, or sexual identity and orientation.
6+
7+
Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
8+
9+
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.
10+
11+
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
12+
13+
This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org/), version 2.1, available at <https://www.contributor-covenant.org/version/2/1/code_of_conduct.html>

CONTRIBUTING.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# Contributing
2+
3+
We love pull requests from everyone. By participating in this project, you
4+
agree to abide by our [code of conduct](CONDUCT.md).
5+
6+
## Getting Started
7+
8+
* Make sure you have a [GitHub account](https://github.com/signup/free). If you are not familiar with git and GitHub, take a look at <http://happygitwithr.com/> to get started.
9+
* [Submit a post for your issue](https://github.com/rmk118/morphmat/issues), assuming one does not already exist.
10+
* Clearly describe your issue, including steps to reproduce when it is a bug, or some justification for a proposed improvement.
11+
* [Fork](https://github.com/rmk118/morphmat/fork) the repository on GitHub or in your shell terminal to make a copy of the repository on your account.
12+
13+
## Making changes
14+
15+
* Before you make a Pull Request, make sure you have discussed your proposed change in an issue post and that the team support your proposed change.
16+
* We recommend that you create a Git branch for each pull request (PR).
17+
* Edit the files, save often, and make commits of logical units, where each commit indicates one concept
18+
* Follow the Tidyverse [style guide](https://style.tidyverse.org/).
19+
* Make sure you write [good commit messages](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html).
20+
* We use testthat. Contributions with test cases included are easier to accept.
21+
* For user-facing changes, add a bullet to the top of NEWS.md below the current development version header describing the changes made followed by your GitHub username, and links to relevant issue(s)/PR(s).
22+
* Run _all_ the tests using `devtools::check()` to assure nothing else was accidentally broken.
23+
* If you need help or unsure about anything, post an update to [your issue](https://github.com/rmk118/morphmat/issues/).
24+
25+
## Submitting your changes
26+
27+
Push to your fork and [submit a pull request](https://github.com/rmk118/morphmat/compare/).
28+
29+
At this point you're waiting on us. We like to at least comment on pull requests within a few days (and, typically, one business day). We may suggest some changes or improvements or alternatives.
30+
31+
Some things you can do that will increase the chance that your pull request is accepted:
32+
33+
* Engage in discussion on [your issue](https://github.com/rmk118/morphmat/issues/).
34+
* Be familiar with the background literature cited in the [README](README.Rmd)
35+
* Write tests that pass `devtools::check()`.
36+
* Follow the [Tidyverse style guide](https://style.tidyverse.org/).
37+
38+
## Acknowledgements
39+
40+
This contributing guide was modified from the CONTRIBUTING.md file from the rrtools package (https://github.com/benmarwick/rrtools/blob/master/CONTRIBUTING.md), an excellent collection of tools for writing reproducible reports and articles in R.
41+

LICENSE

Lines changed: 0 additions & 2 deletions
This file was deleted.

R/density_int.R

Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
#' Distribution interval derived (DID) cutline method
2+
#'
3+
#' @description Implementation of the method described by Richar & Foy (2022) (DOI:
4+
#' 10.1139/facets-2021-0061).
5+
#'
6+
#' @param dat data frame or matrix containing the data
7+
#' @param xvar Name of column (or integer or double vector) containing
8+
#' measurements for the x-axis variable (e.g., carapace width).
9+
#' @param yvar Name of column (or integer or double vector) containing
10+
#' measurements for the y-axis variable (e.g., claw height).
11+
#' @param log Boolean; should both variables be log-transformed before
12+
#' performing the regression? Defaults to FALSE.
13+
#' @param upper Integer or double; the upper bound for possible SM50 values.
14+
#' Must be on the same scale as the data. Defaults to the 80th percentile of
15+
#' the x-variable.
16+
#' @param lower Integer or double; the lower bound for possible SM50 values.
17+
#' Must be on the same scale of the data. Defaults to the 20th percentile of
18+
#' the x-variable.
19+
#' @param int_num Integer; how many intervals between the lower and upper bound
20+
#' should be used? Defaults to 25. With fewer intervals, each interval will
21+
#' contain more points, increasing the accuracy of the estimated density
22+
#' minimum for a given interval. However, the linear regression of the minima
23+
#' distributions (the divisions between immature and mature individuals within
24+
#' an interval) against the midpoints of those intervals may be more reliable
25+
#' with more intervals.
26+
#' @param plot Boolean; should a plot of the data with the calculated minima and
27+
#' discriminating line be displayed?
28+
#' @param adjust the bandwidth used for the kernel density estimate is actually
29+
#' adjust*bw. This makes it easy to specify values like ‘half the default’
30+
#' bandwidth.
31+
#'
32+
#' @returns Something
33+
#'
34+
#' @examples
35+
#' set.seed(12)
36+
#' fc <- fake_crustaceans(n = 1000, L50 = 100, allo_params = c(1, 0.2, 1.1, 0.2))
37+
#' density_int(dat = fc, xvar = "x", yvar = "y", upper = 120)
38+
#' density_int(dat = fc, xvar = "x", yvar = "y", upper = log(120), log = TRUE)
39+
density_int <- density_int <- function(dat,
40+
xvar,
41+
yvar,
42+
lower = NULL,
43+
upper = NULL,
44+
int_num = 25,
45+
log = FALSE,
46+
plot = FALSE,
47+
adjust = 1) {
48+
if (isTRUE(log)) {
49+
dat$xvar <- log(dat[[xvar]])
50+
dat$yvar <- log(dat[[yvar]])
51+
}
52+
else {
53+
dat$xvar <- dat[[xvar]]
54+
dat$yvar <- dat[[yvar]]
55+
}
56+
57+
if (is.null(lower)) {
58+
lower <- stats::quantile(dat$xvar, 0.2, names = FALSE)
59+
}
60+
61+
if (is.null(upper)) {
62+
upper <- stats::quantile(dat$xvar, 0.8, names = FALSE)
63+
}
64+
65+
int_width <- (upper - lower) / int_num
66+
67+
i <- 1
68+
int_bottom <- lower
69+
df_ints <- data.frame(
70+
int_bottom = rep(NA, int_num),
71+
int_top = rep(NA, int_num),
72+
min = rep(NA, int_num),
73+
n_obs = rep(NA, int_num)
74+
)
75+
76+
##### BEGIN LOOP
77+
while (i < int_num + 1) {
78+
int_top_temp <- int_bottom + int_width
79+
temp_df <- dat %>% filter(xvar >= int_bottom, xvar <= int_top_temp)
80+
n_obs <- nrow(temp_df)
81+
82+
if (n_obs < 5) {
83+
abort(
84+
paste(
85+
"Each interval must contain at least 5 data points. The interval from",
86+
round(int_bottom, 3),
87+
"to",
88+
round(int_top_temp, 3),
89+
"only contains",
90+
n_obs,
91+
"points.",
92+
sep = " "
93+
)
94+
)
95+
}
96+
97+
df_ints$int_bottom[i] <- int_bottom
98+
df_ints$int_top[i] <- int_top_temp
99+
df_ints$n_obs[i] <- n_obs
100+
101+
# compute a kernel density estimate
102+
density_test <- stats::density(temp_df$yvar, adjust = adjust)
103+
104+
# convert into a data frame
105+
density_test <- data.frame(x = density_test$x, density = density_test$y)
106+
107+
span <- 5
108+
109+
# find the local maxima - should be two modes
110+
density_test$is_max <- splus2R::peaks(x = density_test$density,
111+
span = span,
112+
strict = TRUE)
113+
modes <- density_test %>%
114+
dplyr::filter(.data$is_max == TRUE) %>%
115+
dplyr::pull(x)
116+
117+
118+
while(length(modes) > 2) {
119+
span <- span + 2
120+
121+
density_test$is_max <- splus2R::peaks(x = density_test$density,
122+
span = span,
123+
strict = TRUE)
124+
modes <- density_test %>%
125+
dplyr::filter(.data$is_max == TRUE) %>%
126+
dplyr::pull(x)
127+
128+
}
129+
130+
if(length(modes) < 2) {
131+
# int_num <- int_num - 1
132+
# int_width <- (upper - lower) / int_num
133+
# i <- 1
134+
# int_bottom <- lower
135+
# df_ints <- data.frame(
136+
# int_bottom = rep(NA, int_num),
137+
# int_top = rep(NA, int_num),
138+
# min = rep(NA, int_num),
139+
# n_obs = rep(NA, int_num)
140+
# )
141+
abort(
142+
paste(
143+
"Each interval should contain two peaks in the density of points along the y-axis. The interval from",
144+
round(int_bottom, 3),
145+
"to",
146+
round(int_top_temp, 3),
147+
"only contains",
148+
length(modes),
149+
"peaks. Try decreasing the int_num argument or changing the adjust argument, which is a multiplier for the smoothing bandwidth.",
150+
sep = " "
151+
)
152+
)
153+
}
154+
# else {
155+
between_modes <- density_test %>% filter(x > modes[1], x < modes[2])
156+
157+
interval_min <- between_modes[which.min(between_modes$density), "x"]
158+
159+
df_ints$min[i] <- interval_min
160+
161+
int_bottom <- int_top_temp
162+
i <- i + 1
163+
# }
164+
} # end loop
165+
166+
df_ints$midpt <- (df_ints$int_bottom + df_ints$int_top) / 2
167+
168+
# optionally visualize the data with the discriminant line
169+
if (plot == TRUE) {
170+
if (log == TRUE) {
171+
xlab <- paste0("ln(", xvar, ")")
172+
ylab <- paste0("ln(", yvar, ")")
173+
}
174+
else {
175+
xlab <- xvar
176+
ylab <- yvar
177+
}
178+
179+
lm_density <- stats::lm(min ~ midpt, data = df_ints)
180+
pred_line <- data.frame(x = dat$xvar,
181+
y = stats::predict(lm_density, data.frame(midpt = dat$xvar)))
182+
print(
183+
ggplot2::ggplot() +
184+
ggplot2::geom_point(data = dat, aes(x = xvar, y = yvar)) +
185+
ggplot2::geom_point(
186+
data = na.omit(df_ints),
187+
aes(x = midpt, y = min),
188+
color = "red"
189+
) +
190+
ggplot2::geom_line(data = pred_line, aes(x, y)) +
191+
ggplot2::labs(x = xlab, y = ylab) +
192+
ggplot2::theme_light()
193+
)
194+
}
195+
196+
return(df_ints)
197+
}

R/infl_pt.R

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@
1414
#' y-var/x-var ratio for all points, then finding the local minimum separating
1515
#' the two peaks representing the maturity clusters.
1616
#'
17-
#' @param dat optional data frame or matrix containing the data
18-
#' @param x Name of column (or integer or double vector) containing measurements
17+
#' @param dat data frame or matrix containing the data
18+
#' @param xvar Name of column (or integer or double vector) containing measurements
1919
#' for the x-axis variable (e.g., carapace width).
20-
#' @param y Name of column (or integer or double vector) containing measurements
20+
#' @param yvar Name of column (or integer or double vector) containing measurements
2121
#' for the y-axis variable (e.g., claw height).
2222
#' @param log Boolean; should both variables be log-transformed before performing the
2323
#' regression? Defaults to FALSE.
@@ -42,13 +42,13 @@
4242
#' infl_pt(fc, "x", "y", plot = TRUE)
4343
#' infl_pt(fc, "x", "y", log = TRUE, plot = TRUE)
4444
#'
45-
infl_pt <- function(dat, x, y, log = FALSE, plot = FALSE) {
45+
infl_pt <- function(dat, xvar, yvar, log = FALSE, plot = FALSE) {
4646
# find the ratio between the two morphometric variables
4747
if (isTRUE(log)) {
48-
ratio <- log(dat[[y]])/log(dat[[x]])
48+
ratio <- log(dat[[yvar]])/log(dat[[xvar]])
4949
}
5050
else {
51-
ratio <- dat[[y]]/dat[[x]]
51+
ratio <- dat[[yvar]]/dat[[xvar]]
5252
}
5353

5454

@@ -60,7 +60,7 @@ infl_pt <- function(dat, x, y, log = FALSE, plot = FALSE) {
6060

6161
# find the local minimum between the two peaks
6262
density_test$is_min <- splus2R::peaks(
63-
x = -density_test$y, span = 3, strict = FALSE)
63+
x = -density_test$y, span = 3, strict = TRUE)
6464

6565
min <- density_test %>%
6666
dplyr::filter(.data$is_min == TRUE) %>%

R/piecewise.R

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@
1919
#' @param log Boolean; should both variables be log-transformed before performing the
2020
#' regression? Defaults to FALSE.
2121
#' @param upper Integer or double; the upper bound for possible SM50 values.
22-
#' Must be on the same trans of the data. Defaults to the 80th percentile of
22+
#' Must be on the same scale as the data. Defaults to the 80th percentile of
2323
#' the x-variable.
2424
#' @param lower Integer or double; the lower bound for possible SM50 values.
25-
#' Must be on the same trans of the data. Defaults to the 20th percentile of
25+
#' Must be on the same scale of the data. Defaults to the 20th percentile of
2626
#' the x-variable.
2727
#'
2828
#' @returns An estimate of SM50 from the specified method(s).

README.Rmd

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ knitr::opts_chunk$set(
2424

2525
<!-- badges: end -->
2626

27+
## Description
28+
2729
A compilation of methods used to estimate size at (sexual) maturity based on morphometric data, most commonly applied to crabs, lobsters, and other crustaceans. Approaches include modeling approaches based on piecewise/segmented linear regression as well as numerous clustering-based methods.
2830

2931
`morphmat` is intended to help fisheries scientists and managers to implement the multitude of computational methods that have been developed for estimating crustacean size at maturity. This package is being developed as part of my graduate work at the University of Maine. **This is still a work in progress and should not yet be used for research purposes.**
@@ -57,8 +59,9 @@ The following scripts do not use morphometric data and require individuals to al
5759
You can install the development version of morphmat from [GitHub](https://github.com/) with:
5860

5961
``` r
60-
# install.packages("devtools")
61-
devtools::install_github("rmk118/morphmat")
62+
remotes::install_github("rmk118/morphmat")
63+
# or
64+
pak::pak("rmk118/morphmat")
6265
```
6366

6467
## Articles/vignettes
@@ -110,4 +113,15 @@ mod <- glm(data = out_df, pred_mat_num ~ x, family = binomial(link = "logit"))
110113
unname(-coef(mod)[1] / coef(mod)[2])
111114
```
112115

116+
117+
## Contributing
118+
119+
If you would like to contribute to this project, please start by reading the [Guide to Contributing](CONTRIBUTING.md). Please note that this project is released with a [Contributor Code of Conduct](CONDUCT.md). By participating in this project you agree to abide by its terms.
120+
121+
## How to Cite
122+
123+
> Krasnow, R. (2025). morphmat:
124+
> An R package to estimate crustacean size at maturity using morphometric data.
125+
> <https://ruby.science/morphmat>.
126+
113127
## References

README.md

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ public.](https://www.repostatus.org/badges/latest/wip.svg)](https://www.repostat
1313

1414
<!-- badges: end -->
1515

16+
## Description
17+
1618
A compilation of methods used to estimate size at (sexual) maturity
1719
based on morphometric data, most commonly applied to crabs, lobsters,
1820
and other crustaceans. Approaches include modeling approaches based on
@@ -74,8 +76,9 @@ You can install the development version of morphmat from
7476
[GitHub](https://github.com/) with:
7577

7678
``` r
77-
# install.packages("devtools")
78-
devtools::install_github("rmk118/morphmat")
79+
remotes::install_github("rmk118/morphmat")
80+
# or
81+
pak::pak("rmk118/morphmat")
7982
```
8083

8184
## Articles/vignettes
@@ -140,6 +143,18 @@ unname(-coef(mod)[1] / coef(mod)[2])
140143
#> [1] 77.70282
141144
```
142145

146+
## Contributing
147+
148+
If you would like to contribute to this project, please start by reading
149+
the [Guide to Contributing](CONTRIBUTING.md). Please note that this
150+
project is released with a [Contributor Code of Conduct](CONDUCT.md). By
151+
participating in this project you agree to abide by its terms.
152+
153+
## How to Cite
154+
155+
> Krasnow, R. (2025). morphmat: An R package to estimate crustacean size
156+
> at maturity using morphometric data. <https://ruby.science/morphmat>.
157+
143158
## References
144159

145160
<div id="refs" class="references csl-bib-body hanging-indent"

0 commit comments

Comments
 (0)