diff --git a/content/blog/scales-1-4-0/figs/unnamed-chunk-2-1.png b/content/blog/scales-1-4-0/figs/unnamed-chunk-2-1.png new file mode 100644 index 00000000..3a00cb5a Binary files /dev/null and b/content/blog/scales-1-4-0/figs/unnamed-chunk-2-1.png differ diff --git a/content/blog/scales-1-4-0/figs/unnamed-chunk-5-1.png b/content/blog/scales-1-4-0/figs/unnamed-chunk-5-1.png new file mode 100644 index 00000000..682ee2d7 Binary files /dev/null and b/content/blog/scales-1-4-0/figs/unnamed-chunk-5-1.png differ diff --git a/content/blog/scales-1-4-0/figs/unnamed-chunk-6-1.png b/content/blog/scales-1-4-0/figs/unnamed-chunk-6-1.png new file mode 100644 index 00000000..38f8c2b3 Binary files /dev/null and b/content/blog/scales-1-4-0/figs/unnamed-chunk-6-1.png differ diff --git a/content/blog/scales-1-4-0/figs/unnamed-chunk-7-1.png b/content/blog/scales-1-4-0/figs/unnamed-chunk-7-1.png new file mode 100644 index 00000000..3204326b Binary files /dev/null and b/content/blog/scales-1-4-0/figs/unnamed-chunk-7-1.png differ diff --git a/content/blog/scales-1-4-0/index.Rmd b/content/blog/scales-1-4-0/index.Rmd new file mode 100644 index 00000000..a8d257db --- /dev/null +++ b/content/blog/scales-1-4-0/index.Rmd @@ -0,0 +1,184 @@ +--- +output: hugodown::hugo_document + +slug: scales-1-4-0 +title: scales 1.4.0 +date: 2024-10-30 +author: Teun van den Brand +description: > + The new 1.4.0 release of the scales package adds some colourful updates. + Read about colour manipulation, palettes and new label functions. + +photo: + url: https://unsplash.com/photos/a-close-up-of-a-person-holding-a-paintbrush-Xrelr7cTYm4 + author: Jennie Razumnaya + +# one of: "deep-dive", "learn", "package", "programming", "roundup", or "other" +categories: [package] +tags: [scales] +--- + + + +We're stoked to announce the release of [scales]({https://scales.r-lib.org/}) 1.4.0. +scales is a package that provides much of the scaling logic that is used in ggplot2 to a general framework, along with utility functions for e.g. formatting labels or creating colour palettes. + +You can install it from CRAN with: + +```{r, eval = FALSE} +install.packages("scales") +``` + +This blog post will give an overview of the 1.4.0 release, which has some nifty upgrades for working with colours and labels. + +You can see a full list of changes in the [release notes](https://scales.r-lib.org/news/index.html) + +```{r setup} +library(scales) +``` + +```{r ragg, include=FALSE} +knitr::opts_chunk$set(dev = "ragg_png") +``` + +## Colour manipulation + +The `alpha()` and `muted()` functions have been part of scales for a long time. +Back in the 1.1.0 release we swapped to [farver](https://farver.data-imaginist.com/) to power these functions. +We felt it was appropriate to use this package for other common colour tasks, and so `col_shift()`, `col_lighter()`, `col_darker()`, `col_saturate()` and `col_mix()` were born. + +```{r} +my_colours <- c("red", "green", "blue") + +m <- rbind( + original = my_colours, + shift = col_shift(my_colours, 90), + lighter = col_lighter(my_colours, 20), + darker = col_darker(my_colours, 20), + duller = col_saturate(my_colours, -50), + mixed = col_mix(my_colours, "orchid") +) + +show_col(t(m), ncol = ncol(m)) +text(x = ncol(m) + 0.25, y = -(1:nrow(m)) + 0.5, rownames(m), adj = 0) +``` + +## Palettes + +Palettes have also been reworked in this release to include some useful properties. +Palettes now come in one of two classes: 'pal_discrete' or 'pal_continuous'. + +```{r} +my_palette <- manual_pal(c("palegreen", "deepskyblue", "magenta")) +class(my_palette) +``` + +Having palettes as a class rather than as plain functions, allows us to store useful metadata about the palette which can be used downstream. +In addition, most colour palette functions also allow the aforementioned colour manipulation functions to work on the palette output. + +```{r} +palette_type(my_palette) + +palette_nlevels(my_palette) + +col_shift(my_palette, 180)(3) +``` + +With the new setup it is now possible to expand discrete palettes to continuous palettes with `as_continuous_pal()` or vise versa to chop up continuous palettes into discrete palettes with `as_discrete_pal()`. + +```{r} +plot(as_continuous_pal(my_palette)) +``` + +Another quality of life improvement for palettes, is that the 'scales' package now keeps track of named palettes. +By default, the collection of 'known' palettes is pre-populated with colour palettes from the grDevices, RColorBrewer and viridisLite packages. + + +```{r} +head(palette_names()) + +get_palette("Okabe-Ito")(8) +``` + +If you're a developer of a palette package, you can use `set_palette()` to register your palette. +This has the advantage that your palette is now available to users by name, which at times might be more convenient than having to call the palette generator function. +In the future, we plan to make it easier to work with named palettes in ggplot2. +Hopefully this will mean that mirroring every palette in a `scale_*()` function becomes obsolete. + +```{r, error=TRUE} +get_palette("aurora") + +set_palette("aurora", my_palette) +plot(get_palette("aurora")) +``` + +## Labels + +This release also provides improvements to labelling in the form of two new labelling functions and two new convenience functions for labels. +In contrast to most of scales' label functions, these label functions are great for discrete input. +First up is `label_glue()`, which uses the string interpolation from the glue package to format your labels. + +```{r} +label_glue("The {x} penguin")(c("Gentoo", "Chinstrap", "Adelie")) +``` + +The other labelling function, `label_dictionary()`, is convenient when some variable you use consists of short-codes or abbreviations. +You can provide `label_dictionary()` with a named vector that translates the values to prettier labels. +If one or more of your values doesn't exist in the dictionary, they stay as-is by default. + +```{r} +dict <- c( + diy = "Do it yourself", eta = "Estimated time of arrival", + asap = "As soon as possible", tldr = "Too long; didn't read" +) +label_dictionary(dict)(c("diy", "tldr", "bff")) +``` + +`compose_label()` is a useful convenience function we've added which will help you to create custom labelling behaviour without needing to write a labelling function from scratch. +Similar to `compose_trans()`, it allows you to chain together different labelling functions. + +```{r} +screaming_flowers <- compose_label(label_glue("The {x} flower"), toupper) +screaming_flowers(c("daffodil", "orchid", "tulip")) +``` +Lastly, we haven't completely forgotton about numeric labels either. +We have introduced the `number_options()` functions to globally populate defaults for functions such as `label_number()` and `label_currency()`. +This can be convenient if you produce statistical reports in non-English languages. + +```{r} +number_options( + decimal.mark = ",", + big.mark = ".", + style_negative = "minus", + currency.prefix = "", + currency.suffix = "€", + currency.decimal.mark = ",", + currency.big.mark = " ", + ordinal.rules = ordinal_french() +) + +label_currency(accuracy = 0.01)(c(0.1, 10, 1000000, -1000)) + +label_ordinal()(1:4) +``` + + + +## Acknowledgements + +We'd like to thank all people who have contributed in some way, whether it was filing issues, participating in discussion or contributing to code and documentation: + +[@Aariq](https://github.com/Aariq), [@Aehmlo](https://github.com/Aehmlo), [@Ali-Hudson](https://github.com/Ali-Hudson), [@cb12991](https://github.com/cb12991), [@colindouglas](https://github.com/colindouglas), [@d-morrison](https://github.com/d-morrison), [@davidhodge931](https://github.com/davidhodge931), [@EricMarcon](https://github.com/EricMarcon), [@kellijohnson-NOAA](https://github.com/kellijohnson-NOAA), [@kmcd39](https://github.com/kmcd39), [@lz1nwm](https://github.com/lz1nwm), [@mine-cetinkaya-rundel](https://github.com/mine-cetinkaya-rundel), [@mjskay](https://github.com/mjskay), [@Moohan](https://github.com/Moohan), [@muschellij2](https://github.com/muschellij2), [@ppreshant](https://github.com/ppreshant), [@rawktheuniversemon](https://github.com/rawktheuniversemon), [@rogiersbart](https://github.com/rogiersbart), [@SchmidtPaul](https://github.com/SchmidtPaul), [@teunbrand](https://github.com/teunbrand), and [@thomasp85](https://github.com/thomasp85). + + diff --git a/content/blog/scales-1-4-0/index.md b/content/blog/scales-1-4-0/index.md new file mode 100644 index 00000000..ac202454 --- /dev/null +++ b/content/blog/scales-1-4-0/index.md @@ -0,0 +1,219 @@ +--- +output: hugodown::hugo_document + +slug: scales-1-4-0 +title: scales 1.4.0 +date: 2024-10-30 +author: Teun van den Brand +description: > + The new 1.4.0 release of the scales package adds some colourful updates. + Read about colour manipulation, palettes and new label functions. + +photo: + url: https://unsplash.com/photos/a-close-up-of-a-person-holding-a-paintbrush-Xrelr7cTYm4 + author: Jennie Razumnaya + +# one of: "deep-dive", "learn", "package", "programming", "roundup", or "other" +categories: [package] +tags: [scales] +rmd_hash: 31a31e8ee7f5311f + +--- + + + +We're stoked to announce the release of [scales](%7Bhttps://scales.r-lib.org/%7D) 1.4.0. scales is a package that provides much of the scaling logic that is used in ggplot2 to a general framework, along with utility functions for e.g. formatting labels or creating colour palettes. + +You can install it from CRAN with: + +
+ +
install.packages("scales")
+ +
+ +This blog post will give an overview of the 1.4.0 release, which has some nifty upgrades for working with colours. + +You can see a full list of changes in the [release notes](https://scales.r-lib.org/news/index.html) + +
+ +
library(scales)
+ +
+ +## Colour manipulation + +The [`alpha()`](https://scales.r-lib.org/reference/alpha.html) and [`muted()`](https://scales.r-lib.org/reference/muted.html) functions have been part of scales for a long time. Back in the 1.1.0 release we swapped to [farver](https://farver.data-imaginist.com/) to power these functions. We felt it was appropriate to use this package for other common colour tasks, and so [`col_shift()`](https://scales.r-lib.org/reference/colour_manip.html), [`col_lighter()`](https://scales.r-lib.org/reference/colour_manip.html), [`col_darker()`](https://scales.r-lib.org/reference/colour_manip.html), [`col_saturate()`](https://scales.r-lib.org/reference/colour_manip.html) and [`col_mix()`](https://scales.r-lib.org/reference/col_mix.html) were born. + +
+ +
my_colours <- c("red", "green", "blue")
+
+m <- rbind(
+  original = my_colours,
+  shift    = col_shift(my_colours, 90),
+  lighter  = col_lighter(my_colours, 20),
+  darker   = col_darker(my_colours, 20),
+  duller   = col_saturate(my_colours, -50),
+  mixed    = col_mix(my_colours, "orchid")
+)
+
+show_col(t(m), ncol = ncol(m))
+text(x = ncol(m) + 0.25, y = -(1:nrow(m)) + 0.5, rownames(m), adj = 0)
+
+ + +
+ +## Palettes + +Also palettes have been reworked this release to reflect more useful properties. Palettes now come in one of two classes: 'pal_discrete' or 'pal_continuous'. + +
+ +
my_palette <- manual_pal(c("palegreen", "deepskyblue", "magenta"))
+class(my_palette)
+#> [1] "pal_discrete" "scales_pal"   "function"
+
+ +
+ +Having palettes as a class rather than plain functions, allows us to store useful metadata about the palette. In addition, most colour palette functions also allow the aforementioned colour manipulation functions to work on the palette output. + +
+ +
palette_type(my_palette)
+#> [1] "colour"
+
+palette_nlevels(my_palette)
+#> [1] 3
+
+col_shift(my_palette, 180)(3)
+#> [1] "#FFC3FF" "#E4A735" "#00B100"
+
+ +
+ +This metadata can then be used to expand discrete palettes to continuous palettes with [`as_continuous_pal()`](https://scales.r-lib.org/reference/new_continuous_palette.html) or vise versa to chop up a continuous palette into discrete palettes with [`as_discrete_pal()`](https://scales.r-lib.org/reference/new_continuous_palette.html). + +
+ +
plot(as_continuous_pal(my_palette))
+
+ + +
+ +Another thing to make working with palettes easier, is that the 'scales' package now keeps track of named palettes. By default, the collection of 'known' palettes is pre-populated with colour palettes from the grDevices, RColorBrewer and viridisLite packages. + +
+ +
head(palette_names())
+#> [1] "greens 2"   "r4"         "greens 3"   "blues"      "terrain"   
+#> [6] "tableau 10"
+
+get_palette("Okabe-Ito")(8)
+#> [1] "#000000" "#E69F00" "#56B4E9" "#009E73" "#F0E442" "#0072B2" "#D55E00"
+#> [8] "#CC79A7"
+
+ +
+ +If you're a developer of a palette package, you can use [`set_palette()`](https://scales.r-lib.org/reference/get_palette.html) to register your palette. This has the advantage that your palette is now available to users by name, which at times might be more convenient than having to call the palette generator function. + +
+ +
get_palette("aurora")
+#> Error in `get_palette()`:
+#> ! Unknown palette: aurora
+
+set_palette("aurora", my_palette)
+plot(get_palette("aurora"))
+
+ + +
+ +## Labels + +Lastly, please let us introduce you to our two new labelling functions and two new convenience functions for labels. In contrast to most of scales' label functions, these label functions are great for discrete input. First up is [`label_glue()`](https://scales.r-lib.org/reference/label_glue.html), which uses the string interpolation from the glue package to format your labels. + +
+ +
label_glue("The {x} penguin")(c("Gentoo", "Chinstrap", "Adelie"))
+#> The Gentoo penguin
+#> The Chinstrap penguin
+#> The Adelie penguin
+
+ +
+ +The next labeling function is convenient when some variable you use consists of shortcodes or abbreviations. You can provide [`label_dictionary()`](https://scales.r-lib.org/reference/label_dictionary.html) with a named vector that translates the values to prettier labels. If you value didn't exist in the dictionary, these stay as-is by default. + +
+ +
dict <- c(
+  diy = "Do it yourself", eta = "Estimated time of arrival",
+  asap = "As soon as possible", tldr = "Too long; didn't read"
+)
+label_dictionary(dict)(c("diy", "tldr", "bff"))
+#> [1] "Do it yourself"        "Too long; didn't read" "bff"
+
+ +
+ +The first label convenience function we'd like to tell you about is the [`compose_label()`](https://scales.r-lib.org/reference/compose_label.html) function. Similar to [`compose_trans()`](https://scales.r-lib.org/reference/transform_compose.html), it allows you to chain together different labelling functions. + +
+ +
screaming_flowers <- compose_label(label_glue("The {x} flower"), toupper)
+screaming_flowers(c("daffodil", "orchid", "tulip"))
+#> THE DAFFODIL FLOWER
+#> THE ORCHID FLOWER
+#> THE TULIP FLOWER
+
+ +
+ +Lastly, we haven't completely forgotton about numeric labels either. We have introduced the [`number_options()`](https://scales.r-lib.org/reference/number_options.html) functions to globally populate defaults for functions such as [`label_number()`](https://scales.r-lib.org/reference/label_number.html) and [`label_currency()`](https://scales.r-lib.org/reference/label_currency.html). This can be convenient if you produce statistical reports in non-English languages. + +
+ +
number_options(
+  decimal.mark = ",",
+  big.mark = ".",
+  style_negative = "minus",
+  currency.prefix = "",
+  currency.suffix = "€",
+  currency.decimal.mark = ",",
+  currency.big.mark = " ",
+  ordinal.rules = ordinal_french()
+)
+
+label_currency(accuracy = 0.01)(c(0.1, 10, 1000000, -1000))
+#> [1] "0,10€"         "10,00€"        "1 000 000,00€" "-1 000,00€"
+
+label_ordinal()(1:4)
+#> [1] "1er" "2e"  "3e"  "4e"
+
+ +
+ +## Acknowledgements + +We'd like to thank all people who have contributed in some way, whether it was filing issues, participating in discussion or contributing to code and documentation: + +[@Aariq](https://github.com/Aariq), [@Aehmlo](https://github.com/Aehmlo), [@Ali-Hudson](https://github.com/Ali-Hudson), [@cb12991](https://github.com/cb12991), [@colindouglas](https://github.com/colindouglas), [@d-morrison](https://github.com/d-morrison), [@davidhodge931](https://github.com/davidhodge931), [@EricMarcon](https://github.com/EricMarcon), [@kellijohnson-NOAA](https://github.com/kellijohnson-NOAA), [@kmcd39](https://github.com/kmcd39), [@lz1nwm](https://github.com/lz1nwm), [@mine-cetinkaya-rundel](https://github.com/mine-cetinkaya-rundel), [@mjskay](https://github.com/mjskay), [@Moohan](https://github.com/Moohan), [@muschellij2](https://github.com/muschellij2), [@ppreshant](https://github.com/ppreshant), [@rawktheuniversemon](https://github.com/rawktheuniversemon), [@rogiersbart](https://github.com/rogiersbart), [@SchmidtPaul](https://github.com/SchmidtPaul), [@teunbrand](https://github.com/teunbrand), and [@thomasp85](https://github.com/thomasp85). + diff --git a/content/blog/scales-1-4-0/thumbnail-sq.jpg b/content/blog/scales-1-4-0/thumbnail-sq.jpg new file mode 100644 index 00000000..8c070906 Binary files /dev/null and b/content/blog/scales-1-4-0/thumbnail-sq.jpg differ diff --git a/content/blog/scales-1-4-0/thumbnail-wd.jpg b/content/blog/scales-1-4-0/thumbnail-wd.jpg new file mode 100644 index 00000000..b6b9645e Binary files /dev/null and b/content/blog/scales-1-4-0/thumbnail-wd.jpg differ