## 'data.frame': 32 obs. of 11 variables:
## $ mpg : num 21 21 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 ...
## $ cyl : num 6 6 4 6 8 6 8 4 4 6 ...
## $ disp: num 160 160 108 258 360 ...
## $ hp : num 110 110 93 110 175 105 245 62 95 123 ...
## $ drat: num 3.9 3.9 3.85 3.08 3.15 2.76 3.21 3.69 3.92 3.92 ...
## $ wt : num 2.62 2.88 2.32 3.21 3.44 ...
## $ qsec: num 16.5 17 18.6 19.4 17 ...
## $ vs : num 0 0 1 1 0 1 0 1 1 1 ...
## $ am : num 1 1 1 0 0 0 0 0 0 0 ...
## $ gear: num 4 4 4 3 3 3 3 4 4 4 ...
## $ carb: num 4 4 1 1 2 1 4 2 2 4 ...
This notebook walks through writing two functions end to end: a
hand-built median() and a parameterized ggplot2 function.
Run every chunk in order — nothing here depends on unseen setup.
## [1] 8
return() is optional — R returns the last evaluated
expression regardless:
## [1] 12
Keep return() for early exits or readability; it costs
nothing and documents intent.
median()## [1] 19.2
## [1] 19.2
identical(get_median(mtcars$mpg), median(mtcars$mpg))
returns TRUE for this vector. mtcars$mpg has
32 values (even), so the function sorts and averages positions 16 and 17
— both 19.2 here, which is why the manual and base results align exactly
rather than approximately.
Quick check on an odd-length vector to confirm the other branch:
## [1] 4
Sorted: 1, 2, 4, 7, 9 — middle value is 4,
matching median(c(4,1,7,2,9)).
Inspect the summary table the function builds before it plots anything:
## # A tibble: 3 × 3
## cyl mean_val se_val
## <dbl> <dbl> <dbl>
## 1 4 26.7 1.36
## 2 6 19.7 0.549
## 3 8 15.1 0.684
(bar chart: 3 bars — 4cyl ≈26.7, 6cyl ≈19.7, 8cyl ≈15.1 — with SE error bars, theme_minimal)
Swap datasets without touching the function body:
{{ }} is not optional hereWithout curly-curly, group_by({{ group_var }}) would
fail or silently misbehave when group_var is passed as a
bare column name, because group_by() expects an expression,
not the string/symbol ambiguity a plain function argument creates.
{{ }} tells dplyr to evaluate
group_var in the caller’s data context. Try removing it and
re-running — you’ll get object 'cyl' not found even though
cyl is a real column in mtcars, because R is
looking for a variable named cyl in the function’s own
environment, not in data.
## [1] "Hello, Guest"
## [1] FALSE
## [1] 2 4 6 8 10
## R version 4.5.1 (2025-06-13 ucrt)
## Platform: x86_64-w64-mingw32/x64
## Running under: Windows 10 x64 (build 19045)
##
## Matrix products: default
## LAPACK version 3.12.1
##
## locale:
## [1] LC_COLLATE=English_United States.utf8
## [2] LC_CTYPE=English_United States.utf8
## [3] LC_MONETARY=English_United States.utf8
## [4] LC_NUMERIC=C
## [5] LC_TIME=English_United States.utf8
##
## time zone: Asia/Karachi
## tzcode source: internal
##
## attached base packages:
## [1] stats graphics grDevices utils datasets methods base
##
## other attached packages:
## [1] ggplot2_4.0.1 dplyr_1.1.4
##
## loaded via a namespace (and not attached):
## [1] vctrs_0.6.5 cli_3.6.5 knitr_1.51 rlang_1.1.6
## [5] xfun_0.56 otel_0.2.0 generics_0.1.4 S7_0.2.1
## [9] jsonlite_2.0.0 labeling_0.4.3 glue_1.8.0 htmltools_0.5.9
## [13] sass_0.4.10 scales_1.4.0 rmarkdown_2.30 grid_4.5.1
## [17] evaluate_1.0.5 jquerylib_0.1.4 tibble_3.3.0 fastmap_1.2.0
## [21] yaml_2.3.12 lifecycle_1.0.5 compiler_4.5.1 RColorBrewer_1.1-3
## [25] pkgconfig_2.0.3 rstudioapi_0.18.0 farver_2.1.2 digest_0.6.39
## [29] R6_2.6.1 tidyselect_1.2.1 pillar_1.11.1 magrittr_2.0.4
## [33] bslib_0.10.0 withr_3.0.2 gtable_0.3.6 tools_4.5.1
## [37] cachem_1.1.0
Full narrative version with a mistakes checklist and FAQ: https://www.rstudiodatalab.com/2026/09/create-function-in-r-custom-examples.html