coolbutuseless
https://coolbutuseless.github.io/
Recent content on coolbutuselessHugo -- gohugo.ioen-usSun, 01 Mar 2020 06:00:00 +1000Line Segment/Box Intersection Test
https://coolbutuseless.github.io/2020/03/01/line-segment/box-intersection-test/
Sun, 01 Mar 2020 06:00:00 +1000https://coolbutuseless.github.io/2020/03/01/line-segment/box-intersection-test/Line Segment/Box Intersection Test While working with {grid} graphics I needed a way to cull some generated geometry if it didn’t lie within a given rectangular bounding box.
The following code is based upon a stackoverflow response
This code will test 100 thousand line segments against a box in about 20ms, which is fast enough for my purposes.
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #' Determine if line segments intersect a rectangle #' #' @param x1,y1,x2,y2 coordinates of line segment endpoints #' @param xmin,ymin,xmax,ymax coordinates of lower-left and upper-right of #' rectangle.My mental model of how alpha works is wrong
https://coolbutuseless.github.io/2020/02/14/my-mental-model-of-how-alpha-works-is-wrong/
Fri, 14 Feb 2020 06:20:00 +1000https://coolbutuseless.github.io/2020/02/14/my-mental-model-of-how-alpha-works-is-wrong/My mental model of alpha when plotting When plotting overlapping elements with a defined alpha (opacity), I had always thought about it as an additive process with results clamped to not exceed 1.
Thus, without every bothering to check, my mental model was: three overlapping black rectangles, each with an opacity of 0.4, would result in a black rectangle since their combined opacity is 1.2, and this is clamped the maximum possible value of 1.Introducing the {ggblur} package
https://coolbutuseless.github.io/2020/02/11/introducing-the-ggblur-package/
Tue, 11 Feb 2020 19:40:00 +1000https://coolbutuseless.github.io/2020/02/11/introducing-the-ggblur-package/ggblur ggblur provides geom_point_blur() for use in ggplot - this geom allows you to control the blurriness of the drawn points, but is otherwise identical to the standard geom_point().
What’s in the box? geom_point_blur() same as geom_point() but now accepts blur_size as an aesthetic also allows for control of the smoothness of the blur (blur_steps) and the maximum opacity (blur_alpha) scale_blur_size_continuous(), scale_blur_size_discrete() and scale_blur_size_manual() for controlling blur_size when used as a mapped aesthetic/ Similar packages ggecho is an earlier experiment of mine from 2019 where I echo components using a custom stat stat_echo.Drawing with epicycles in R
https://coolbutuseless.github.io/2019/12/31/drawing-with-epicycles-in-r/
Tue, 31 Dec 2019 08:00:00 +1000https://coolbutuseless.github.io/2019/12/31/drawing-with-epicycles-in-r/Drawing with epicycles Create a set of points to define the path Take the discrete fourier transform of the points (as represented in the complex plane) The magnitude and phase of the fourier transform components are the radius and phase offset of the circles to draw library(ggplot2) library(gganimate) library(ggforce) # geom_circle library(dplyr) library(hershey) # vector font: https://github.com/coolbutuseless/hershey Extract a set of points for the letter R This uses the Hershey vector fonts.dplyr::ungroup() - forget me not. Part 4.
https://coolbutuseless.github.io/2019/12/06/dplyrungroup-forget-me-not.-part-4./
Fri, 06 Dec 2019 20:20:00 +1000https://coolbutuseless.github.io/2019/12/06/dplyrungroup-forget-me-not.-part-4./Forget me not - dplyr::ungroup() If you forget to ungroup() an operation after a group_by() it can lead to unwanted behaviour.
Question: What if we didn’t have to remember to ungroup after every chain?
My “just be annoying” non-solution - Part 2 Since I almost never want to leave grouped data in my workspace, just make a noisy version of the pipe operator (%>%) which
warns if you try and operate on a dataset which is already grouped.dplyr::ungroup() - forget me not. Part 3.
https://coolbutuseless.github.io/2019/11/22/dplyrungroup-forget-me-not.-part-3./
Fri, 22 Nov 2019 22:05:00 +1000https://coolbutuseless.github.io/2019/11/22/dplyrungroup-forget-me-not.-part-3./Forget me not - dplyr::ungroup() If you forget to ungroup() an operation after a group_by() it can lead to unwanted behaviour.
Question: What if we didn’t have to remember to ungroup after every chain?
My “just be annoying” non-solution. Since I almost never want to leave grouped data in my workspace, just make a noisy version of the pipe operator (%>%) which puts out a big red warning if you try and operate on a dataset which is already grouped.dplyr::ungroup() - forget me not. Part 2.
https://coolbutuseless.github.io/2019/11/20/dplyrungroup-forget-me-not.-part-2./
Wed, 20 Nov 2019 19:25:00 +1000https://coolbutuseless.github.io/2019/11/20/dplyrungroup-forget-me-not.-part-2./Forget me not - dplyr::ungroup() If you forget to ungroup() an operation after a group_by() it can lead to unwanted behaviour.
Question: What if we didn’t have to remember to ungroup after every chain?
My “Let’s break backwards compatibility with the universe” non-solution. Instead of having to use an explicit ungroup(), use this brand new %>% (pipe operator) which will automatically apply an ungroup() at the end of every chain.dplyr::ungroup() - forget me not
https://coolbutuseless.github.io/2019/11/19/dplyrungroup-forget-me-not/
Tue, 19 Nov 2019 20:25:00 +1000https://coolbutuseless.github.io/2019/11/19/dplyrungroup-forget-me-not/Forget me not - dplyr::ungroup() If you forget to ungroup() an operation after a group_by() it can lead to unwanted behaviour.
Question: What if we didn’t have to remember to ungroup after every chain?
My post-lunch, sugar-coma non-solution Instead of using group_by(), use with_group_by() which will automatically apply an ungroup().
This isn’t really a solution as the syntax is pretty darn horrible, but was a fun post-lunch idea to implement.Introducing {devoutsvg} - SVG graphics output device with pattern fills
https://coolbutuseless.github.io/2019/10/10/introducing-devoutsvg-svg-graphics-output-device-with-pattern-fills/
Thu, 10 Oct 2019 21:30:00 +1000https://coolbutuseless.github.io/2019/10/10/introducing-devoutsvg-svg-graphics-output-device-with-pattern-fills/devoutsvg devoutsvg provides a bespoke SVG graphics device written in plain R.
The key feature of this SVG graphics device is that it allowd for the use of patterns for filled regions in plots!
Installation You can install from GitHub with:
# install.packages("devtools") devtools::install_github("coolbutuseless/lofi") # Colour encoding devtools::install_github("coolbutuseless/minisvg") # SVG creation devtools::install_github("coolbutuseless/devout") # Device interface devtools::install_github("coolbutuseless/devoutsvg") # This package Basic usage of the svgout device Use this device in the same way you would use pdf(), png() any of the other graphics output devices in R.Introducing {svgpatternusgs} - a collection U.S. Geological Survey repeating SVG patterns
https://coolbutuseless.github.io/2019/10/10/introducing-svgpatternusgs-a-collection-u.s.-geological-survey-repeating-svg-patterns/
Thu, 10 Oct 2019 06:50:00 +1000https://coolbutuseless.github.io/2019/10/10/introducing-svgpatternusgs-a-collection-u.s.-geological-survey-repeating-svg-patterns/svgpatternusgs svgpatternusgs provides SVG patterns from the United States Geological Survey (USGS).
The USGS provides a large array of reference styles for geologic linework and map symbology.
USGS website for Geological Map Symbols The raw data for this package was sourced from davenquinn’s github version An example of the patterns provided This is a screenshot of the original documentation which comes with these patterns from the USGSIntroducing {svgpatternsimple} - a collection of simple repeating SVG patterns
https://coolbutuseless.github.io/2019/10/09/introducing-svgpatternsimple-a-collection-of-simple-repeating-svg-patterns/
Wed, 09 Oct 2019 19:20:00 +1000https://coolbutuseless.github.io/2019/10/09/introducing-svgpatternsimple-a-collection-of-simple-repeating-svg-patterns/svgpatternsimple svgpatternsimple provides a basic set of simple repeating SVG patterns.
Installation You can install from GitHub with:
# install.packages("devtools") install_github("coolbutuseless/lofi") # for encoding information as RGB colours install_github("coolbutuseless/poissoned") # Generate points via poisson disk sampling install_github("coolbutuseless/minnisvg") # Build SVG documents with R install_github("coolbutuseless/svgpatternsimple") # This package Example: What is a pattern? The patterns generated by this package are SVG <pattern> elements created with minisvg.The {miniverse} - a collection of document creation packages for RStats
https://coolbutuseless.github.io/2019/10/09/the-miniverse-a-collection-of-document-creation-packages-for-rstats/
Wed, 09 Oct 2019 06:25:00 +1000https://coolbutuseless.github.io/2019/10/09/the-miniverse-a-collection-of-document-creation-packages-for-rstats/miniverse The miniverse is a constellation of packages for creating documents within R.
The purpose of this miniverse package is to:
Highlight the common interface used across the packages Provide links to the various packages Installation You can install miniverse from GitHub with:
# install.packages("devtools") devtools::install_github("coolbutuseless/minipdf") devtools::install_github("coolbutuseless/minihtml") devtools::install_github("coolbutuseless/minicss") devtools::install_github("coolbutuseless/miniverse") Create PDF documentsGithub Online documentation Create CSSGithub Online documentation Create HTML documentsGithub Online documentation Create XML documentsGithub Online documentation Create SVG documentsGithub Online documentation High level document description A document is a tree of objects, with a a document node at the root, and element nodes branching from this.Introducing {minisvg} - create SVG documents with R
https://coolbutuseless.github.io/2019/10/08/introducing-minisvg-create-svg-documents-with-r/
Tue, 08 Oct 2019 20:35:00 +1000https://coolbutuseless.github.io/2019/10/08/introducing-minisvg-create-svg-documents-with-r/minisvg minisvg is a package for building SVG documents in R.
Overview Need to build R6 object alternate initialisation SVG elements stag SVG elements SVGElement$new() svg_elem() SVG document SVGDocument$new() svg_doc() Quick Examples SVG Entity code result SVG elements stag$circle(cx=0, cy=0, r=20) <circle cx="0" cy="0" r="20" /> SVG elements SVGElement$new('circle', cx=0, cy=0, r=20) <circle cx="The {devoutverse} - a collection of non-standard graphics output devices for RStats
https://coolbutuseless.github.io/2019/10/08/the-devoutverse-a-collection-of-non-standard-graphics-output-devices-for-rstats/
Tue, 08 Oct 2019 06:05:00 +1000https://coolbutuseless.github.io/2019/10/08/the-devoutverse-a-collection-of-non-standard-graphics-output-devices-for-rstats/devoutverse The devoutverse is a collection of packages offering non-standard devices for RStats. Most are based on devout.
The purpose of this devoutverse package is to:
Provide links to the various packages. Installation You can install devoutverse packages from GitHub with:
# install.packages("devtools") devtools::install_github("coolbutuseless/devout") devtools::install_github("coolbutuseless/devoutpdf") devtools::install_github("coolbutuseless/devoutaudio")
ASCII graphics deviceGithub Online documentation PDF deviceGithub Online documentation Audio outputGithub Online documentation Want to build your own device?Introducing {devoutpdf} - a hand-crafted PDF graphics device written in plain R
https://coolbutuseless.github.io/2019/10/07/introducing-devoutpdf-a-hand-crafted-pdf-graphics-device-written-in-plain-r/
Mon, 07 Oct 2019 20:27:00 +1000https://coolbutuseless.github.io/2019/10/07/introducing-devoutpdf-a-hand-crafted-pdf-graphics-device-written-in-plain-r/devoutpdf devoutpdf is a hand-crafted PDF graphics device written in plain R.
It achieves this by invoking the devout package to do all the interfacing between the C++ side and the R side.
Drawing commands which sent to the graphics device are used to construct a minipdf document.
Why would you want this? Given that pdf() and cairo_pdf() devices come with R, what’s the point of a third PDF output device?Introducing {devoutaudio} - an experimental package for rendering graphics as audio
https://coolbutuseless.github.io/2019/10/04/introducing-devoutaudio-an-experimental-package-for-rendering-graphics-as-audio/
Fri, 04 Oct 2019 22:27:00 +1000https://coolbutuseless.github.io/2019/10/04/introducing-devoutaudio-an-experimental-package-for-rendering-graphics-as-audio/devoutaudio devoutaudio is an audio output “graphics” device - instead of rendering pixels, each graphics primitive is rendered as an audio snippet.
This is a testing ground for some graphics-to-sound ideas and is very experimental.
devoutaudio is written in plain R, and uses the devout package to interface with the R internals
Point-to-sound mapping x position is mapped to audio channel position - points on the left of the plot are rendered mainly in the left channel of audio y position is mapped to frequency - the higher the point the higher the frequency size is mapped to duration - larger points have a longer sound Installation You can install devoutaudio from GitHub with:Re-introducing devout - a package for creating graphics output devices in plain R
https://coolbutuseless.github.io/2019/10/03/re-introducing-devout-a-package-for-creating-graphics-output-devices-in-plain-r/
Thu, 03 Oct 2019 22:27:00 +1000https://coolbutuseless.github.io/2019/10/03/re-introducing-devout-a-package-for-creating-graphics-output-devices-in-plain-r/devout devout is a package that enables R graphics devices to be written in plain R.
devout uses a pseudo-graphics-device which translates graphics calls into a call to an R function of your design.
This means we can create alternative output devices (like pdf() or png()) using only plain R.
How normal (C/C++) graphics devices work animation (click to close) How the devout device enables plain R graphics devices animation (click to close) What’s in the box rdevice() - a generic device wrapper which will call the given R function to handle the graphics drawing.Introducing the `minixml` package for creating XML documents in R
https://coolbutuseless.github.io/2019/09/30/introducing-the-minixml-package-for-creating-xml-documents-in-r/
Mon, 30 Sep 2019 21:57:00 +1000https://coolbutuseless.github.io/2019/09/30/introducing-the-minixml-package-for-creating-xml-documents-in-r/minixml minixml is a package for building xml documents in R.
minixml vs xml2 xml2 is a fantastic package for parsing a pre-existing XML file and navigating through it, slicing it etc.
minixml is focussed on creating XML documents by assembling nodes with attributes in a programmatic fashion.
Overview Need to build R6 object alternate initialisation XML elements XMLElement$new() xml_elem() XML document XMLDocument$new() xml_doc() Quick Examples XML Entity code result XML elements XMLElement$new('info', "Introducing the `hershey` package - raw data for the Hershey Vector Fonts
https://coolbutuseless.github.io/2019/09/24/introducing-the-hershey-package-raw-data-for-the-hershey-vector-fonts/
Tue, 24 Sep 2019 19:35:00 +1000https://coolbutuseless.github.io/2019/09/24/introducing-the-hershey-package-raw-data-for-the-hershey-vector-fonts/hershey The hershey package contains the Hershey vector fonts in a number of formats for more convenient use within Rstats.
The Hershey fonts were developed in the 1960s. Each glyph is defined as collections of staight line segments - hand calculated by Hershey by sketching them on grid paper!
This package makes available the coordinates of the stroke endpoints for every glyph.
You may need this package if:Introducing the `minihtml` package for creating HTML documents in R
https://coolbutuseless.github.io/2019/09/19/introducing-the-minihtml-package-for-creating-html-documents-in-r/
Thu, 19 Sep 2019 19:35:00 +1000https://coolbutuseless.github.io/2019/09/19/introducing-the-minihtml-package-for-creating-html-documents-in-r/minihtml minihtml is a package for building html documents in R.
minihtml objects are compatible with shiny - see the vignette
Overview Need to build R6 object alternate initialisation HTML elements htag HTML elements HTMLElement$new() html_elem() HTML document HTMLDocument$new() html_doc() Quick Examples HTML Entity code result HTML elements htag$a(href = 'http://example.Introducing the `minizdog` package for creating zdog 3d illustrations in R
https://coolbutuseless.github.io/2019/09/17/introducing-the-minizdog-package-for-creating-zdog-3d-illustrations-in-r/
Tue, 17 Sep 2019 21:05:00 +1000https://coolbutuseless.github.io/2019/09/17/introducing-the-minizdog-package-for-creating-zdog-3d-illustrations-in-r/minizdog minizdog is a package for building Zdog illustrations in R.
This package was inspired by OganM’s package called rdog. That package is much more feature complete, with better documentation and examples and other stuff.
This package is part of an ongoing exploration of writing document interfaces with R and R6 - every drawing feature is mapped to an R6 object, and these objects are nested within each other to create the document.Introducing the `minicss` package for creating CSS styles and stylesheets in R
https://coolbutuseless.github.io/2019/09/11/introducing-the-minicss-package-for-creating-css-styles-and-stylesheets-in-r/
Wed, 11 Sep 2019 22:45:00 +1000https://coolbutuseless.github.io/2019/09/11/introducing-the-minicss-package-for-creating-css-styles-and-stylesheets-in-r/minicss The goal of minicss is to be able to programatically create CSS styles and style sheets from within R.
minicss objects and output are compabile with Shiny (see the vignette)
Overview minicss is a collection of R6 objects a user creates and encapsulates within one other to build CSS style sheets
Need to build… R6 object alternate initialisation CSS Properties css_prop CSS Selectors Selector$new() css_sel() KeyFrames Keyframe$new() css_keyframe() Keyframes$new() css_keyframes() CSS Styles Style$new() css_style() CSS Style Sheets StyleSheet$new() css_stylesheet() Quick examples CSS Entity code result Properties css_prop$'font-family'$cursive font-family: cursive; css_prop$'animation-delay'$set(12) animation-delay: 12; Selectors css_sel('#cindy')$child_of('#carol') #carol > #cindy Inline Styles css_style(colour='red')$update(margin=0) color: red; margin: 0; CSS Styles css_style("Introducing the `minipdf` package for writing raw PDFs
https://coolbutuseless.github.io/2019/08/14/introducing-the-minipdf-package-for-writing-raw-pdfs/
Wed, 14 Aug 2019 14:45:00 +1000https://coolbutuseless.github.io/2019/08/14/introducing-the-minipdf-package-for-writing-raw-pdfs/minipdf minipdf is a package for creating simple, single-page PDF documents written in pure R.
This package is very, very far from supporting the full PDF spec (which is over 750 pages!), but it supports enough to draw simple figures - for example the package logo was created with the package itself.
Supported features Documents with a single page only Only one font per document (set during initialization) Objects: Text, lines, polylines, polygons, rectangles and circles Attributes: Fill colour (including alpha), stroke colour (including alpha), linewidth, linetype Clipping regions Currently there is no support for annotations or any sort of text layout.Introducing the `lofi` package for low-fidelity/low-bit data representations
https://coolbutuseless.github.io/2019/08/06/introducing-the-lofi-package-for-low-fidelity/low-bit-data-representations/
Tue, 06 Aug 2019 19:45:00 +1000https://coolbutuseless.github.io/2019/08/06/introducing-the-lofi-package-for-low-fidelity/low-bit-data-representations/lofi The goal of lofi is to squeeze multiple, low-fidelity representations of colours and numbers into the 32-bits of a single, standard integer in R.
This low-fidelity representation of values (a.k.a. lofi) is usually only an approximation of the original values, and reconstructed values will most likely be slightly different from the original.
Visit the webpage for more in-depth documentation.
What’s in the box pack() and unpack() are the key functions for packing/unpacking multiple values into the bits of an integer There is a suite of low-level functions for handling each particular supported type e.Using random bits to generate random numbers
https://coolbutuseless.github.io/2019/07/19/using-random-bits-to-generate-random-numbers/
Fri, 19 Jul 2019 05:40:00 +1000https://coolbutuseless.github.io/2019/07/19/using-random-bits-to-generate-random-numbers/Problem: How do you randomly generate any possible floating point number, including NAs and Infs?
Details:
I wanted everything from the super small 3.1e-15 to the super large 6.6e230 I wanted Inf and NA to be possible Thanks to Emil Hvitfeldt and Michael Chirico for their assistance, ideas and feedback!
Attempt 1 - runif() My first attempt using runif() to generate any possible number between 0 and the maximum double was never going to work:poissoned - a package for poisson disc sampling
https://coolbutuseless.github.io/2019/06/25/poissoned-a-package-for-poisson-disc-sampling/
Tue, 25 Jun 2019 05:40:00 +1000https://coolbutuseless.github.io/2019/06/25/poissoned-a-package-for-poisson-disc-sampling/poissoned poissoned is an Rstats implementation of the poisson disk sampling algorithm from Bridson’s paper - Fast Poisson Disk Sampling in Arbitrary Dimensions
Notes:
only implemented the 2d case adjusted the algorithm in order to ensure repeatable/tileable samples with minimal artifacts at the joins similar in purpose to Will Chase’s package {poissondisc}. However, poissoned has a a completely different implementation which ends up being much faster. Installation You can install from GitHub with:Drawing Fractals with grid graphics - part 2
https://coolbutuseless.github.io/2019/04/29/drawing-fractals-with-grid-graphics-part-2/
Mon, 29 Apr 2019 16:50:00 +1000https://coolbutuseless.github.io/2019/04/29/drawing-fractals-with-grid-graphics-part-2/L-system fractals with grid graphics in R This is a follow-up to the prior post - by changing the axiom and the L-system production rules you can change the type of fractal produced
Rather than simply calculating and drawing lines, I am interested in how viewports in the grid system work. So to draw L-systems, the movement and rotation of lines are carried out by pushing new viewports on the viewing stack.Drawing Fractals with grid graphics - part 1
https://coolbutuseless.github.io/2019/04/27/drawing-fractals-with-grid-graphics-part-1/
Sat, 27 Apr 2019 17:00:00 +1000https://coolbutuseless.github.io/2019/04/27/drawing-fractals-with-grid-graphics-part-1/grid graphics in R grid graphics is one of the graphics systems within R - ggplot and trellis are both built upon the grid system.
This is some exploratory code to figure out some of the capabilities of grid, by using it to draw fractals using L-systems.
Rather than simply calculating and drawing lines, I am interested in how viewports in the grid system work. So to draw L-systems, the movement and rotation of lines are carried out by pushing new viewports on the viewing stack.Introducing the ggreverse package for turning ggplots back in to code
https://coolbutuseless.github.io/2019/04/26/introducing-the-ggreverse-package-for-turning-ggplots-back-in-to-code/
Fri, 26 Apr 2019 21:00:00 +1000https://coolbutuseless.github.io/2019/04/26/introducing-the-ggreverse-package-for-turning-ggplots-back-in-to-code/ggreverse ggreverse takes a ggplot object and returns the code to create that plot.
This package was written as a learning exercise to help me figure out some of the internal structure of a ggplot object.
ToDo Reverse engineering of facetting and scales from a plot object. aes_string() is currently unsupported. Using tidyeval in aes() calls is currently unsupported. Lots of other stuff :) Installation You can install from GitHub with:Reverse engineer the ggplot call from a ggplot object
https://coolbutuseless.github.io/2019/04/26/reverse-engineer-the-ggplot-call-from-a-ggplot-object/
Fri, 26 Apr 2019 06:25:00 +1000https://coolbutuseless.github.io/2019/04/26/reverse-engineer-the-ggplot-call-from-a-ggplot-object/Idea tjmahr posted a neat hack to embed auto-embed the text used to create a ggplot as the title of the plot itself.
I wondered if you could somehow extract the ggplot call text from a ggplot object itself.
Proof-of-concept: Reverse engineering a ggplot call library(ggplot2) library(dplyr) #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # reverse_mapping -> "aes(x = ..., y = ...)" #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ reverse_mapping <- function(mapping) { aes_args <- paste(names(mapping), stringr::str_sub(as.character(mapping), start=2), sep = "=", collapse = ", ") aes_text <- glue::glue("aes({aes_args})") aes_text } #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # reverse aesthetic params -> "size = 3" #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ reverse_aes_params <- function(aes_params) { if (length(aes_params) == 0) { NULL } else { paste(names(aes_params), unname(aes_params), sep = "=", collapse = ", ") } } #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # reverse_layer -> "geom_point(aes(mpg, wt), size = 3)" #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ reverse_layer <- function(layer) { geom_name <- ggplot2:::snakeize(class(layer$geom)[1]) aes_text <- reverse_mapping(layer$mapping) aes_params_text <- reverse_aes_params(layer$aes_params) geom_args <- paste(c(aes_text, aes_params_text), collapse = ", ") glue::glue("{geom_name}({geom_args})") } #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Reverse plot #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ reverse_plot <- function(p) { layers <- p$layers %>% map_chr(reverse_layer) plot_text <- paste(c("ggplot(data)", layers), collapse = "+\n") styler::style_text(plot_text) } Example #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Create a plot object #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ (p <- ggplot(mtcars) + geom_point(aes(mpg, wt), size = 3) + geom_line(aes(mpg, wt))) #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Determine the ggplot call from the ggplot object #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ reverse_plot(p) Warning: Could not use colored = TRUE, as the package prettycode is not installed.Every possible scatterplot from a data.frame (32 thousand plots of `mtcars`)
https://coolbutuseless.github.io/2019/04/25/every-possible-scatterplot-from-a-data.frame-32-thousand-plots-of-mtcars/
Thu, 25 Apr 2019 18:00:00 +1000https://coolbutuseless.github.io/2019/04/25/every-possible-scatterplot-from-a-data.frame-32-thousand-plots-of-mtcars/Question: Is it possible to generate every possible scatterplot from a data.frame? Is it?
Answer: Yes Yes, is is possible to generate every possible scatterplot from a data.frame. Even on limited subset of aesthetics, there are still 32 thousand possible scatterplots. Code included below Constraints: Not mapping alpha, fill, stroke or group Each variable could be used in only one aesthetic mapping on a single plot e.GIF image writing in pure R
https://coolbutuseless.github.io/2019/04/23/gif-image-writing-in-pure-r/
Tue, 23 Apr 2019 07:00:00 +1000https://coolbutuseless.github.io/2019/04/23/gif-image-writing-in-pure-r/Introduction While working on fast output of images for the foist package, I realised the GIF format was simple enough to write quickly, so I worked on an R implementation of a GIF image writer, before translating to C++ for speed.
Update
Thanks to BrodieG for some optimization of the code!
What’s in an uncompressed GIF? Header “GIF89a” to indicate this is a GIF file width + height.Twitter #rstats activity
https://coolbutuseless.github.io/2019/04/09/twitter-#rstats-activity/
Tue, 09 Apr 2019 19:45:00 +1000https://coolbutuseless.github.io/2019/04/09/twitter-#rstats-activity/When is Twitter #rstats active? Living in Australia, I sometimes feel I’m not on twitter when all the #rstats action is happening.
rtweet is a package I’ve been meaning to look at for a while, so this seemed like a good introductory exercise.
The rtweet authorisation process is totally painless, and spawns a browser session to get you started with the twitter API without even having to think.Outputting data to images
https://coolbutuseless.github.io/2019/04/08/outputting-data-to-images/
Mon, 08 Apr 2019 20:00:00 +1000https://coolbutuseless.github.io/2019/04/08/outputting-data-to-images/Problem: Saving lots of R matrices and arrays to image files A current project generates 100s (even 1000s) of matrices which I’d like to view outside of R i.e. I’d like to save all these matrices as image files and then process them with other tools.
This post benchmarks some ways of saving a matrix or an array as an image file.
Notes:
My machine has an SSD.Red/Blue Analglyphs with ggplot2 and ggthreed
https://coolbutuseless.github.io/2019/04/02/red/blue-analglyphs-with-ggplot2-and-ggthreed/
Tue, 02 Apr 2019 20:30:00 +1000https://coolbutuseless.github.io/2019/04/02/red/blue-analglyphs-with-ggplot2-and-ggthreed/ggthreed v0.1.2 ggthreed now includes a stat_anaglyph() for creating red/blue anaglyph plots.
Installation You can install from github
# install.packages("devtools") devtools::install_github("coolbutuseless/threed") devtools::install_github("coolbutuseless/ggthreed") Red/blue anaglyphs with stat_anaglyph() Grab your glasses and lower your expectations!!
Usage Works with point, line and polygon geoms. Although “works” may be a strong term - the 3d effect is very weak even if you tweak all the parameters It might work with other geoms, but no guarantees that it produces anything worth looking at.ggdebug - v0.1.1
https://coolbutuseless.github.io/2019/04/01/ggdebug-v0.1.1/
Mon, 01 Apr 2019 20:50:00 +1000https://coolbutuseless.github.io/2019/04/01/ggdebug-v0.1.1/ggdebug v0.1.1 ggdebug is a package for debugging ggplot2 stats.
I created this package to help in developing new ggplot2 stats, and trying to decipher and understand how existing ones work.
ggdebug v0.1.1 now includes a function for determining the name of the Geom which is being used with the current Stat - ggdebug::get_geom()
You can install from GitHub with:
# install.packages("remotes") remotes::install_github("coolbutuseless/ggdebug") Determine the Geom from within a Stat For good reasons(?ggdebug - a package for debugging ggplot stats
https://coolbutuseless.github.io/2019/03/26/ggdebug-a-package-for-debugging-ggplot-stats/
Tue, 26 Mar 2019 20:50:00 +1000https://coolbutuseless.github.io/2019/03/26/ggdebug-a-package-for-debugging-ggplot-stats/ggdebug ggdebug is a package for debugging ggplot2 stats.
I created this package to help in developing new ggplot2 stats, and trying to decipher and understand how existing ones work.
What’s in the box:
create_stat_with_caching() Capture arguments and the return values internal to Stat methods inject_data_into_stat_function() Inject arguments and return values directly into Stat methods This package wouldn’t be possible without:ggecho - an experimental ggplot stat for blurring elements
https://coolbutuseless.github.io/2019/03/22/ggecho-an-experimental-ggplot-stat-for-blurring-elements/
Fri, 22 Mar 2019 21:25:00 +1000https://coolbutuseless.github.io/2019/03/22/ggecho-an-experimental-ggplot-stat-for-blurring-elements/ggecho ggecho is a ggplot2 Stat which echoes the plotting data.
This can be used to create a blur effect for geom_point(), geom_line() and geom_text() (and probably some other geoms where the size parameter directly determines the area of the displayed element).
This ggplot2 stat works by duplicating/echoing the original data passed to ggplot, and adjusting each data echo by:
size (size_increment), alpha (alpha_factor), and position (x_offset & y_offset) This package wouldn’t be possible without:geom_blurry() - proof of concept
https://coolbutuseless.github.io/2019/03/19/geom_blurry-proof-of-concept/
Tue, 19 Mar 2019 20:35:00 +1000https://coolbutuseless.github.io/2019/03/19/geom_blurry-proof-of-concept/Emil Hvitfeldt wondered on twitter whether there was a convenient way to blur points in ggplot.
Is there a way to apply blur to #ggplot2 elements? I would like to be able to get something like the first image without having to modify the svg after creating 😅#rstats pic.twitter.com/vWACdGyl9g
— Emil Hvitfeldt (@Emil_Hvitfeldt) March 18, 2019 I created a proof-of-concept geom to plot blurry points. Not-at-all configurable at the moment, but it shows that it could be an interesting way of showing … something.Introducing the `analemmatic` Package for Creating Analemmatic Sundials
https://coolbutuseless.github.io/2019/03/19/introducing-the-analemmatic-package-for-creating-analemmatic-sundials/
Tue, 19 Mar 2019 19:48:00 +1000https://coolbutuseless.github.io/2019/03/19/introducing-the-analemmatic-package-for-creating-analemmatic-sundials/The analemmatic package creates analemmatic sundials.
Given a city, analemmatic will get its latitude and magnetic declination from an internal dataset and use this to construct an analemmatic sundial.
Analemmatic sundials are neat because they are a flat (horizontal) sundial with a vertical gnomon. They are often scaled up and uses as sculptures in parks such that the human standing in a specific location casts the shadow for the sundial.group_map() in dplyr 0.8.1 (still in development)
https://coolbutuseless.github.io/2019/03/17/group_map-in-dplyr-0.8.1-still-in-development/
Sun, 17 Mar 2019 17:30:00 +1000https://coolbutuseless.github.io/2019/03/17/group_map-in-dplyr-0.8.1-still-in-development/The release of dplyr v0.8.0 brought some new group functionality - described in the release notes.
Since then, romain francois has worked on some changes to the group operation in this pull request #4251, and things have changed a bit.
The group operations which have just been modified from 0.8.0 and ready for release whenever v0.8.1 comes out are
group_split() - split a data.frame by the grouping columns into a list group_data() - a data.group_split/map/modify() in dplyr 0.8.1 (still in development)
https://coolbutuseless.github.io/2019/03/15/group_split/map/modify-in-dplyr-0.8.1-still-in-development/
Fri, 15 Mar 2019 20:30:00 +1000https://coolbutuseless.github.io/2019/03/15/group_split/map/modify-in-dplyr-0.8.1-still-in-development/The release of dplyr v0.8.0 brought some new group functionality - described in the release notes.
Since then, romain francois has worked on some changes to the group operation in this pull request #4251, and things have changed a bit.
The group operations which have just been modified from 0.8.0 and ready for release whenever v0.8.1 comes out are
group_split() - split a data.frame by the grouping columns into a list group_data() - a data.Anonymous Functions in R - Part 3: Introducing the 'anon' package
https://coolbutuseless.github.io/2019/03/14/anonymous-functions-in-r-part-3-introducing-the-anon-package/
Thu, 14 Mar 2019 20:30:00 +1000https://coolbutuseless.github.io/2019/03/14/anonymous-functions-in-r-part-3-introducing-the-anon-package/An Anonymous Function (also known as a lambda expression) is a function definition that is not bound to an identifier. That is, it is a function that is created and used, but never assigned to a variable.
In a prior post I discussed how I am not completely ssatisfied with purrr/rlang’s anonymous function syntax as it has no capability for naming the function arguments anything other than .Anonymous Functions in R - Part 2
https://coolbutuseless.github.io/2019/03/13/anonymous-functions-in-r-part-2/
Wed, 13 Mar 2019 17:00:00 +1000https://coolbutuseless.github.io/2019/03/13/anonymous-functions-in-r-part-2/An Anonymous Function (also known as a lambda experssion) is a function definition that is not bound to an identifier. That is, it is a function that is created and used, but never assigned to a variable.
In a prior post I discussed how I am not completely satisfied with purrr/rlang’s anonymous function syntax as it has no capability for naming the function arguments anything other than .Anonymous Functions in R - Part 1
https://coolbutuseless.github.io/2019/03/13/anonymous-functions-in-r-part-1/
Wed, 13 Mar 2019 05:50:00 +1000https://coolbutuseless.github.io/2019/03/13/anonymous-functions-in-r-part-1/An Anonymous Function (also known as a lambda experssion) is a function definition that is not bound to an identifier. That is, it is a function that is created and used, but never assigned to a variable.
Base R anonymous function syntax An example in R where anonymous functions are used is in *apply() family of functions. In the following example a function is defined which takes one argument, adds one to it, and then returns it.image2xlsx package: Converting an image to an excel spreadsheet
https://coolbutuseless.github.io/2019/03/09/image2xlsx-package-converting-an-image-to-an-excel-spreadsheet/
Sat, 09 Mar 2019 06:30:00 +1000https://coolbutuseless.github.io/2019/03/09/image2xlsx-package-converting-an-image-to-an-excel-spreadsheet/image2xlsx image2xlsx provides a single function to turn an image into an excel (xlsx) spreadsheet.
It stands on the shoulders of the following giants:
openxlsx magick + imagemagick dplyr tidyr raster Installation You can install from GitHub with:
# install.packages("devtools") devtools::install_github("coolbutuseless/image2xlsx") Rlogo library(image2xlsx) image2xlsx("working/RStudio.png", "man/figures/rlogo.xlsx") A screenshot of rlogo.xlsx opened in LibreOffice
Bender Bending Rodríguez library(image2xlsx) image2xlsx("working/bender.jpg", "man/figures/bender.xlsx") A screenshot of bender.xlsx opened in LibreOfficeCustom axis breaks on facetted ggplot
https://coolbutuseless.github.io/2019/03/07/custom-axis-breaks-on-facetted-ggplot/
Thu, 07 Mar 2019 17:00:00 +1000https://coolbutuseless.github.io/2019/03/07/custom-axis-breaks-on-facetted-ggplot/I needed to create a facetted ggplot with custom x-axis breaks on every single plot.
The x-axis had units of hours and some plots spanned multiple days, and other spanned just a few hours. For the facets that spanned multiple days I wanted breaks at every 24 hours, but for the shorter times I needed breaks every hour.
ggplot2 allows you to use a function to set the breaks for the x-axis, so I could just check what the limits of the plot are and do two different things depending on the upper limit.Converting an image to an excel spreadsheet
https://coolbutuseless.github.io/2019/03/03/converting-an-image-to-an-excel-spreadsheet/
Sun, 03 Mar 2019 09:00:00 +1000https://coolbutuseless.github.io/2019/03/03/converting-an-image-to-an-excel-spreadsheet/Convert an image to an excel spreadsheet openxlsx is a pretty powerful package to read/write XLSX spreadsheet files. Attributes and styles can be set programmatically for each cell from within R.
So I’m going to use it to convert a JPG into a spreadsheet.
FAQ:
Why? Because. library(raster) library(openxlsx) #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Read the R logo from the jpeg package #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ jpeg_filename <- system.file("img", "Rlogo.object of type 'closure' is not(?) subsettable
https://coolbutuseless.github.io/2019/02/12/object-of-type-closure-is-not-subsettable/
Tue, 12 Feb 2019 20:00:00 +1000https://coolbutuseless.github.io/2019/02/12/object-of-type-closure-is-not-subsettable/R Error messages: A visual overview R Error message: object of type 'closure' is not subsettable A common error in R is object of type 'closure' is not subsettable. This message means that you have a variable which represents a function, and you’re mistakenly using square brackets to try and subset it, thinking that it represents a data.frame or vector or something e.g.
# `mean` here refers the built-in base R function mean[1:3] ## Error in mean[1:3]: object of type 'closure' is not subsettable In general if you get this error it means you’re trying to subset a function (or somehow access an item within a function using $) which (most of the time) doesn’t make much sense in normal R code.8 out of 10 cats does countdown - part 2
https://coolbutuseless.github.io/2019/02/11/8-out-of-10-cats-does-countdown-part-2/
Mon, 11 Feb 2019 21:00:00 +1000https://coolbutuseless.github.io/2019/02/11/8-out-of-10-cats-does-countdown-part-2/An error in the previous solution Claus Ekstrom pointed out to me that my previous solution won’t actually find all possible solutions to the Countdown numbers puzzle. i.e.
Just recoded your implementation in RCPP and it is blazingly fast. But ... the algorithm is not optimal since it works successively on the current value, and you could start in several places. Eg., the numbers 1 1 1 1 1 100, target 404.8 out of 10 cats does countdown
https://coolbutuseless.github.io/2019/02/04/8-out-of-10-cats-does-countdown/
Mon, 04 Feb 2019 21:00:00 +1000https://coolbutuseless.github.io/2019/02/04/8-out-of-10-cats-does-countdown/8 out of 10 cats does Countdown “8 out of 10 cats does Countdown” is a UK panel comedy show in which they play games with words and numbers while also telling rude jokes and generally mucking about. It’s an adults-only version of the much more sedate “Countdown” show.
The ‘Countdown’ number puzzle The number puzzle segment of the show goes something like this:Interleaving vectors and matrices - part 3
https://coolbutuseless.github.io/2019/01/31/interleaving-vectors-and-matrices-part-3/
Thu, 31 Jan 2019 17:00:00 +1000https://coolbutuseless.github.io/2019/01/31/interleaving-vectors-and-matrices-part-3/Yesterday’s request for help got some great replies on twitter. I’ve collected them in this post and benchmarked them.
No one (besides myself) had the sheer audacity to inflict a for loop upon the world.
Huge thanks to the following people for their ideas! (in order of appearance)
Stuart Lee Gabe Becker Kara Woo Michael Sumner Jake Westfall Brodie Gaslam Brendan Knapp Edward Visel David Mas-Ponte Interleaving a row-vector with a matrix of the same width I have a vector a row-vector and matrix of equal widthInterleaving vectors and matrices - part 2
https://coolbutuseless.github.io/2019/01/30/interleaving-vectors-and-matrices-part-2/
Wed, 30 Jan 2019 17:00:00 +1000https://coolbutuseless.github.io/2019/01/30/interleaving-vectors-and-matrices-part-2/I’m looking for a better, neater, more R-like solution to this - please hit me up on twitter.
At the moment, I can’t even include a benchmark screenshot as I only have just the one idea on how to do this!
Interleaving a vector with a matrix of the same width I have a vector a row-vector and matrix of equal width
vec <- c(101, 102, 103) mat <- matrix(c(1, 2, 3, 4, 5, 6, 7, 8, 9), nrow = 3, byrow = TRUE) Expected output after interleaving by columnInterleaving vectors and matrices (part 1)
https://coolbutuseless.github.io/2019/01/29/interleaving-vectors-and-matrices-part-1/
Tue, 29 Jan 2019 17:00:00 +1000https://coolbutuseless.github.io/2019/01/29/interleaving-vectors-and-matrices-part-1/Interleaving 2 vectors - simplest solution I have 2 vectors of equal length that I want to interleave
First input: 1, 2, 3 Second input: 4, 5, 6 Desired output: 1, 4, 2, 5, 3, 6 The simplest base R solution is to rbind() the 2 inputs and then unravel the matrix.
And when I say “simplest” solution, I mean “thing that is shortest but totally non-obvious”.Puzzle Solving: Dominosa
https://coolbutuseless.github.io/2019/01/28/puzzle-solving-dominosa/
Mon, 28 Jan 2019 17:00:00 +1000https://coolbutuseless.github.io/2019/01/28/puzzle-solving-dominosa/Puzzle solving - Dominosa Dominosa is a game/puzzle from Simon Tathams’ Portable Puzzle Collection.
In Dominosa there is a complete set of dominoes up to a certain number (A classic domino set goes from 0, 0 up to 6, 6). The initial board represents the dominoes laid out in a grid - we have the numbers, but not the outline of the dominos.
The aim of the puzzle is to determine the locations/orientations of all the dominos so that every possible domino appears exactly once.split-apply-combine with `group_map`
https://coolbutuseless.github.io/2018/12/31/split-apply-combine-with-group_map/
Mon, 31 Dec 2018 08:00:00 +1000https://coolbutuseless.github.io/2018/12/31/split-apply-combine-with-group_map/Split-Apply-Combine I tend to do quite a lot of coding where data is split into groups, operations performed independently on each group, and then the data re-assembled into a single entity.
This is the classic split-apply-combine as outlined in Hadley Wickham’s JStatSoft paper (pdf) and discussed in Jenny Bryan’s Stat545 notes
group_by + do is “basically deprecated” The original way I performed split-apply-combine in the tidyverse was with group_by and do,R packages - internal and external data
https://coolbutuseless.github.io/2018/12/10/r-packages-internal-and-external-data/
Mon, 10 Dec 2018 17:00:00 +1000https://coolbutuseless.github.io/2018/12/10/r-packages-internal-and-external-data/Packages in R can contain blobs of data - in fact some packages are only data without any code e.g. {nycflights13}.
Data in a package is classed as being internal or external to the package. In broad terms, internal data is data that the functions in the package use, and external data is the data you’d like the user to see.
A recent issue is that I wanted data in the {phon} package to be both external and internal.phon - a package for rhymes etc
https://coolbutuseless.github.io/2018/12/03/phon-a-package-for-rhymes-etc/
Mon, 03 Dec 2018 17:00:00 +1000https://coolbutuseless.github.io/2018/12/03/phon-a-package-for-rhymes-etc/phon The goal of phon is to make available the CMU Pronouncing Dictionary (cmudict) in an R friendly format, and to collect some tools which use the pronunciation information.
The CMU Pronouncing Dictionary includes pronunciations for 130,000 words. By matching the phonemes between words, phon provides
phonemes('threw') - Returns the phonemes for the pronunciation of “threw”. homophones('steak') - Returns words which are homophones of “steak”. rhymes('carry') - Returns words which rhyme with “carry”.grrr - a package for changing default function arguments
https://coolbutuseless.github.io/2018/11/20/grrr-a-package-for-changing-default-function-arguments/
Tue, 20 Nov 2018 21:00:00 +1000https://coolbutuseless.github.io/2018/11/20/grrr-a-package-for-changing-default-function-arguments/raison d’être - stringsAsFactors = TRUE sucks This package can change default arguments in pre-existing functions to be almost anything.
So you can change stringsAsFactors = FALSE whereever you please!
This is based on a blog post from earlier this year.
Installation install.packages("coolbutuseless/grrr") Example 1: Change mean to use na.rm = TRUE by default A call to mean will not remove NA values from the input i.ggthreed - 3d pie charts
https://coolbutuseless.github.io/2018/11/13/ggthreed-3d-pie-charts/
Tue, 13 Nov 2018 18:00:00 +1000https://coolbutuseless.github.io/2018/11/13/ggthreed-3d-pie-charts/Should I write a geom for 3d pie charts? Introducing the ggthreed package ggthreed is a collection of ggplot2 geoms which use the threed library.
At present it consists of just a single geom: geom_threedpie() which creates 3d pie charts.
I am fully aware of the crimes against visualisation I am committing here.
The code is available on github.
Installation You can install from githubthreed - drawing a cube in ggplot2
https://coolbutuseless.github.io/2018/11/12/threed-drawing-a-cube-in-ggplot2/
Mon, 12 Nov 2018 18:00:00 +1000https://coolbutuseless.github.io/2018/11/12/threed-drawing-a-cube-in-ggplot2/Introduction This post explores how to plot a cube in ggplot2 using the threed library.
ggplot2 doesn’t include any notion of a 3rd spatial axis, so instead, after manipulating a 3d object, we use perspective projection to “flatten” its faces and vertices onto a 2d plane. These projected faces/vertices are what ggplot2 will plot.
Prepare an object for plotting Create an object (here the standard 2x2x2 cube is being used) Define where camera is located, and where it is looking Transform the object into camera space Perspective transform the data #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # The `threed` package has some builtin objects in `threed::mesh3dobj` #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ obj <- threed::mesh3dobj$cube #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Define camera 'lookat' matrix i.Parsing a favicon with {minitypes}
https://coolbutuseless.github.io/2018/11/06/parsing-a-favicon-with-minitypes/
Tue, 06 Nov 2018 18:00:00 +1000https://coolbutuseless.github.io/2018/11/06/parsing-a-favicon-with-minitypes/minitypes minitypes is a package of type conversion tools for R atomic vectors.
This package is built upon R’s type conversion tools and aims to:
have a consistent interface for converting between types add handling for types not handled by R explicitly e.g. uint8 It’s available from github.
Worked Example - Parsing an ICO favicon Read in a favicon file (ICO) as raw bytes (ICO values are represented in little-endian byte order) Manually parse the ICO header (see e.Minitypes - vector type conversion
https://coolbutuseless.github.io/2018/11/06/minitypes-vector-type-conversion/
Tue, 06 Nov 2018 06:00:00 +1000https://coolbutuseless.github.io/2018/11/06/minitypes-vector-type-conversion/minitypes minitypes is a package of type conversion tools for R atomic vectors.
This package is built upon R’s type conversion tools and aims to:
have a consistent interface for converting between types add handling for types not handled by R explicitly e.g. uint8 It’s available from github.
Supported Types: raw byte This is R’s builtin raw byte format. chr Ascii/utf8 representation.facet_inception()
https://coolbutuseless.github.io/2018/10/31/facet_inception/
Wed, 31 Oct 2018 18:00:00 +1000https://coolbutuseless.github.io/2018/10/31/facet_inception/facetting a facetted facet ggplot In this post, I use patchwork to nest three levels of facetted ggplots.
The plots shown below are:
The diamonds data set: price vs carat The diamonds data set: price vs carat - facetted by cut. The diamonds data set: price vs carat - facetted by cut, then facetted within each cut by color The diamonds data set: price vs carat - facetted by cut, then facetted within each cut by color, then each of those facets are factted by clarity.Creating fractals with ggplot2 and patchwork
https://coolbutuseless.github.io/2018/10/30/creating-fractals-with-ggplot2-and-patchwork/
Tue, 30 Oct 2018 18:00:00 +1000https://coolbutuseless.github.io/2018/10/30/creating-fractals-with-ggplot2-and-patchwork/Creating fractals with ggplot2 and patchwork Today in my ongoing quest to generate fractals in Rstats using every available avenue: creating a Sierpinski Triangle and Sierpinski Carpet using patchwork to layout reptitions of 2 simple plots.
Methods for generating fractals so far:
Sierpinski Triangle in plotmath Another sierpinski triangle in plotmath Sierpinski triangle using character strings Using R matrices to create a sierpinski carpet Generating hilbert curves with an ad-hoc L-system Barnsley ferns generated by iterated affine transformations Ikeda map Today: Use patchwork to iteratively composite two basic plots into Sierpinski Triangle and Sierpinski Carpet Background patchwork is a great library written by Thomas Lin Pedersen for compositing multiple plots.engroupify: A function to transform other functions to be aware of dplyr groups
https://coolbutuseless.github.io/2018/10/11/engroupify-a-function-to-transform-other-functions-to-be-aware-of-dplyr-groups/
Thu, 11 Oct 2018 18:00:00 +1000https://coolbutuseless.github.io/2018/10/11/engroupify-a-function-to-transform-other-functions-to-be-aware-of-dplyr-groups/I needed to create a special mutate function that uses the dplyr groups if they’re defined, otherwise it should calculate over the entire data.
I couldn’t find anything online on how to do this, so I came with a solution.
It doesn’t seem there’s a blessed/sanctioned way of doing this.
I worked out the method to use in my previous post.
Then I realised I wanted to do this to a few other functions, so I thought I’d have a shot at making a function that converts other functions into ones which respect dplyr groups.Writing a function which respects `dplyr::group_by()`
https://coolbutuseless.github.io/2018/10/09/writing-a-function-which-respects-dplyrgroup_by/
Tue, 09 Oct 2018 21:00:00 +1000https://coolbutuseless.github.io/2018/10/09/writing-a-function-which-respects-dplyrgroup_by/I need to create a special mutate function that uses the dplyr groups if they’re defined, otherwise it should calculate over the entire data.
I couldn’t find anything online on how to do this, so I’ve come with a solution.
Does anyone know the correct/sanctioned way of handling this?
Thanks to:
romainfrancois for pointing out that the ‘indices’ attribute is undocumented, and I should use ‘group_indices()’ instead.Introducing the `memoisetools` package
https://coolbutuseless.github.io/2018/10/08/introducing-the-memoisetools-package/
Mon, 08 Oct 2018 17:00:00 +1000https://coolbutuseless.github.io/2018/10/08/introducing-the-memoisetools-package/memoisetools package memoisetools is a collection of additional caches and helper functions to work alongside the memoise package.
This package introduces new caches, new memoise() alternatives and functions for interrogating caches and expiring old objects from a cache.
New caches: cache_filesystem2() - with object timestamping, compression of objects by default, and expiration of results not accessed for a certain time. cache_memory2() - with object timestamping, faster xxhash64 used by default, and expiration of results not accessed for a certain time.Using LZ4 and Zstandard to compress files with `saveRDS()`
https://coolbutuseless.github.io/2018/10/02/using-lz4-and-zstandard-to-compress-files-with-saverds/
Tue, 02 Oct 2018 17:00:00 +1000https://coolbutuseless.github.io/2018/10/02/using-lz4-and-zstandard-to-compress-files-with-saverds/Serializing objects to file A standard way to serialize R objects to file is to use saveRDS() and readRDS().
A number of standard compression schemes are offered withni saveRDS() in order to save disk space, I’ve swiped some benchmarks from here and pulled out the numbers corresponding to the default options in R
gzip fast, but no very efficient Default compression level in gzfile(): 6 Compression/decompression speeds: 19 MB/s and 95 MB/s respecively bzip2 slower than gzip, but better compression Default compression level in bzfile(): 9 Compression/decompression speeds: 7 MB/s and 24 MB/s respecively xz very very slow.Memoisation
https://coolbutuseless.github.io/2018/10/01/memoisation/
Mon, 01 Oct 2018 17:00:00 +1000https://coolbutuseless.github.io/2018/10/01/memoisation/Memoisation Memoisation allows the caching of the output for a function for a given set of inputs.
That is, for a set of arguments the result is only ever calculated once and then stored in a cache. If those set of arguments ever happen again, then the result is pulled from the cache rather than the function being re-run.
This technique is really useful when a function takes a long time to execute.Writing a nonogram solver in R
https://coolbutuseless.github.io/2018/09/28/writing-a-nonogram-solver-in-r/
Fri, 28 Sep 2018 19:00:00 +1000https://coolbutuseless.github.io/2018/09/28/writing-a-nonogram-solver-in-r/Nonograms Nonograms are picture logic puzzles in which cells in a grid must be colored or left blank according to numbers at the side of the grid to reveal a hidden picture.
That is, the numbers on the side of the image (the clues) are the run-length encoding of the filled-in squares for each row and column.
By simultaneously satisfying the clues for the rows and columns, a picture is revealed!Creating nonograms with 'nonogram' and 'magick' packages
https://coolbutuseless.github.io/2018/09/27/creating-nonograms-with-nonogram-and-magick-packages/
Thu, 27 Sep 2018 19:00:00 +1000https://coolbutuseless.github.io/2018/09/27/creating-nonograms-with-nonogram-and-magick-packages/Nonograms Nonograms are picture logic puzzles in which cells in a grid must be colored or left blank according to numbers at the side of the grid to reveal a hidden picture.
That is, the numbers on the side of the image (the clues) are the run-length encoding of the filled-in squares for each row and column.
By simultaneously satisfying the clues for the rows and columns, a picture is revealed!Nonograms in R - 'nonogram' package
https://coolbutuseless.github.io/2018/09/26/nonograms-in-r-nonogram-package/
Wed, 26 Sep 2018 17:00:00 +1000https://coolbutuseless.github.io/2018/09/26/nonograms-in-r-nonogram-package/Nonograms - Make Run-Length Encoding Fun Again Nonograms are picture logic puzzles in which cells in a grid must be colored or left blank according to numbers at the side of the grid to reveal a hidden picture.
That is, the numbers on the side of the image (the clues) are the run-length encoding of the filled-in squares for each row and column.
By simultaneously satisfying the clues for the rows and columns, a picture is revealed!Memoise with object size limit
https://coolbutuseless.github.io/2018/09/24/memoise-with-object-size-limit/
Mon, 24 Sep 2018 17:00:00 +1000https://coolbutuseless.github.io/2018/09/24/memoise-with-object-size-limit/Problem I have a function which takes 2 arguments and returns a matrix. Returned values for the most common inputs are under 1MB but some input values result in returned matrices up to 5GB in size (thanks to a combinatorial explosion!) I would like to memoise the function using the memoise package, but there doesn’t seem to be a way to limit memory usage (someone please correct me on twitter if there is a way!The Zombie/Vampire Apocalypse - A use case for strict membership tests
https://coolbutuseless.github.io/2018/09/21/the-zombie/vampire-apocalypse-a-use-case-for-strict-membership-tests/
Fri, 21 Sep 2018 06:00:00 +1000https://coolbutuseless.github.io/2018/09/21/the-zombie/vampire-apocalypse-a-use-case-for-strict-membership-tests/Problem: %in% isn’t strict enough for some of my use cases This is a second attempt at creating a stricter version of %in% to test membership. (My first attempt is here)
My problems with %in% arise because:
It silently promotes arguments of different types. I’d actually like an error if doing membership tests of vectors of different types It is not robust to variations which might arise as the data evolves See Zombies/Vampires use case below In the following use-case, I show why %in% isn’t ideal with data sets which evolve and update.strict `case_when` - bugfix
https://coolbutuseless.github.io/2018/09/20/strict-case_when-bugfix/
Thu, 20 Sep 2018 17:00:00 +1000https://coolbutuseless.github.io/2018/09/20/strict-case_when-bugfix/Bugfix - actually handling NAs in input I previously talked about why I wanted a strict_case_when() a few week’s ago.
I’ve since found a major bug for inputs which contain NA and posting an update to fix this.
This code is available as a github gist
strict_case_when() strict_case_when() is a thin wrapper around dplyr::case_when() which: disallows a fall-through ‘TRUE’ value on the LHS. disallows input values which do not match any rules.Find all sequences of a given length with the given sum
https://coolbutuseless.github.io/2018/09/20/find-all-sequences-of-a-given-length-with-the-given-sum/
Thu, 20 Sep 2018 16:00:00 +1000https://coolbutuseless.github.io/2018/09/20/find-all-sequences-of-a-given-length-with-the-given-sum/Problem This problem popped up as a necessary step to solving a type of puzzle (which I’ll post about soon).
From the set of all positive (non-zero) integers, find all the sequences of the specified length which have the given sum. Need all orderings sums usually range from 10 to 30 lengths usually range from 2 to 10 Example: All the length=3 vectors which sum to 5 (one sequence per row) [,1] [,2] [,3] [1,] 1 1 3 [2,] 1 2 2 [3,] 1 3 1 [4,] 2 1 2 [5,] 2 2 1 [6,] 3 1 1 Naive solution - generate all sequences, then filter Use expand grid to expand all possible sequences.Intersection of multiple vectors
https://coolbutuseless.github.io/2018/09/17/intersection-of-multiple-vectors/
Mon, 17 Sep 2018 17:00:00 +1000https://coolbutuseless.github.io/2018/09/17/intersection-of-multiple-vectors/Problem - Finding the intersection of multiple integer vectors I want to find the intersection of multiple integer vectors Unbounded number of vectors, but usually 4-10 Unbounded size, but usually 10 to a million elements Duplicated elements allowed in output Order not important Submissions welcomed! (including alternate test sets that demonstrate a different dominant solution) Test set Benchmarking data: 10 vectors Varying lengths Elements sampled from range (1, 1e5) I realise that this benchmarking data ignores the following cases a few short vectors very long vectors vectors already sorted by size vectors with large overlap vectors with no overlap set.A stricter `%in%`
https://coolbutuseless.github.io/2018/09/07/a-stricter-in/
Fri, 07 Sep 2018 17:00:00 +1000https://coolbutuseless.github.io/2018/09/07/a-stricter-in/Problem: %in% isn’t strict enough for some of my use cases %in% will silently ignore
arguments of different types RHS arguments that don’t match any of the possible LHS inputs Empty RHS or LHS For example, the following is a non-sensical filter in which none of the elements we’re trying to match against are actually in the Species vector!
iris %>% filter(Species %in% c('leaf', 'tree', 'butterfly')) # A tibble: 0 x 5 # … with 5 variables: Sepal.strict `case_when`
https://coolbutuseless.github.io/2018/09/06/strict-case_when/
Thu, 06 Sep 2018 17:00:00 +1000https://coolbutuseless.github.io/2018/09/06/strict-case_when/Problem: case_when() isn’t strict enough case_when() is fantastic, but in some cases I’d like it to be a little bit stricter on what it allows.
I want to eliminate ways in which errors or oversights can creep in, so I’d like special handling for the following cases:
the fall-through/catch-all value of TRUE should be disallowed by default. all input values should match one rule no input value should match more than one rule Before starting, let me state clearly thatbits and bit reversal
https://coolbutuseless.github.io/2018/09/04/bits-and-bit-reversal/
Tue, 04 Sep 2018 17:00:00 +1000https://coolbutuseless.github.io/2018/09/04/bits-and-bit-reversal/library(tidyverse) library(bench) library(Rcpp) Problem I have a sequence of values in R and I want to reverse the bits in each value.
Problem dimensions:
Only considering raw values Up to ~10^5 raw values to reverse Bit reversal - overview For a vector of raw bytes I want:
the output of rawToBits() but with each byte bit-reversed i.e. most significant bit first with all raw-bits-representing bytes concatentated together into a single vector That is, each byte within a vector of values is unmoved, but each byte has its bits reversed.gganimate with sprites
https://coolbutuseless.github.io/2018/08/13/gganimate-with-sprites/
Mon, 13 Aug 2018 20:00:00 +1000https://coolbutuseless.github.io/2018/08/13/gganimate-with-sprites/library(tidyverse) library(raster) library(gganimate) Sprites A sprite is a 2d bitmap often used by games to represent objects. A number of sprites displayed in sequence creates an animation.
Puzzle bobble sprite extraction Grab a sprite sheet for your favourite game from spriters resource I will be using a Bubble Bobble dinosaur Work out how to cut out sprites by subsetting the sheet of sprites #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Not going to directly link in to script to avoid hitting server # https://www.gganimate with bitmap fonts
https://coolbutuseless.github.io/2018/08/12/gganimate-with-bitmap-fonts/
Sun, 12 Aug 2018 20:00:00 +1000https://coolbutuseless.github.io/2018/08/12/gganimate-with-bitmap-fonts/Introduction I finally got the time to play with the gganimate package by Thomas Lin Pederson.
The API is really well designed and Thomas has deconstructed the grammar of animation into a clean/orthogonal set of functions.
I put together the little animation shown below, and this is a short guide on how I got there.
Bitmap fonts In a bitmap font, a character is defined by a binary matrix - where the matrix is 1 the underlying pixel is turned on, otherwise it is turned off.ggplot2 stat_summary problem
https://coolbutuseless.github.io/2018/08/06/ggplot2-stat_summary-problem/
Mon, 06 Aug 2018 06:00:00 +1000https://coolbutuseless.github.io/2018/08/06/ggplot2-stat_summary-problem/Introduction When using stat_summary() it transforms all the values first and then calculates the summary.
However, I would like the stat_summary calculated on the original data and then transformed.
Below I’ll try and illustrate the problem, and propose a work-around.
Note: it appears my github issue has been closed.
ggplot2::stat_summary ggplot2 has the ability to summarise data with stat_summary. This particular Stat will calculate a summary of your data at each unique x value.Encoding and Rendering Grade 1 Braille
https://coolbutuseless.github.io/2018/07/31/encoding-and-rendering-grade-1-braille/
Tue, 31 Jul 2018 17:00:00 +1000https://coolbutuseless.github.io/2018/07/31/encoding-and-rendering-grade-1-braille/Introduction Braille is a tactile writing system used by people who are visually impaired.
A pattern of 2x3 dots is used to encode symbols, letters, words and language. The current(?) standard(?) for the English language is Unified English Braille, although Nemeth Braille seems to be a slightly different standard which still appears popular for encoding mathematical notion.
Disclaimer:
I’m only looking at simple Grade 1 encoding (i.pipe - rewriting nested function calls with pipes
https://coolbutuseless.github.io/2018/07/27/pipe-rewriting-nested-function-calls-with-pipes/
Fri, 27 Jul 2018 18:00:00 +1000https://coolbutuseless.github.io/2018/07/27/pipe-rewriting-nested-function-calls-with-pipes/pipe() - Replacing nested function calls with the pipe operator This is the inverse of yesterday’s code I’m trying to wrap my head around some parts of the rlang package so I set myself a task to focus my exploration: Auto-rewrite nested function calls into a chain of piped function calls pipe() #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # pipe - Auto-rewrite a nested function calls as a chain of piped function calls #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ pipe <- function(ee) { if (!Re-defining 'return()'
https://coolbutuseless.github.io/2018/07/27/re-defining-return/
Fri, 27 Jul 2018 18:00:00 +1000https://coolbutuseless.github.io/2018/07/27/re-defining-return/Introduction R has a number of reserved words which are core to the language and cannot be redefined.
According to R langauge definition these are:
if else repeat while function for in next break TRUE FALSE NULL Inf NaN NA NA_integer_ NA_real_ NA_complex_ NA_character_ … ..1 ..2 etc.
return() is not reserved which means we can redefine it. Note: This is a bad idea (tm)unpipe - rewriting an expression without the pipes
https://coolbutuseless.github.io/2018/07/26/unpipe-rewriting-an-expression-without-the-pipes/
Thu, 26 Jul 2018 20:00:00 +1000https://coolbutuseless.github.io/2018/07/26/unpipe-rewriting-an-expression-without-the-pipes/Playing with rlang package - Removing the pipe operator I’m trying to wrap my head around some parts of the rlang package so I set myself a task to focus my exploration: Auto-rewrite a chain of piped functions as a set of nested function calls unpipe #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # unpipe - rewrite a chain of piped functions as a set of nested function calls # # A recursive function that descends through the language tree and flips # arguments #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ unpipe <- function(ee) { if (!Shortest unique prefix - it's a builtin function
https://coolbutuseless.github.io/2018/07/24/shortest-unique-prefix-its-a-builtin-function/
Tue, 24 Jul 2018 20:00:00 +1000https://coolbutuseless.github.io/2018/07/24/shortest-unique-prefix-its-a-builtin-function/Shortest unique prefix - hack part #3 I want to find the shortest unique prefix for each string in a vector (N < 20) i.e. in a vector of strings, what’s the shortest a string can be and still match only itself This isn’t a computational bottleneck in the overall process, so there’s no need for heroic/drastic solutions. I wasn’t going to write a trie implementation just to solve this problem.Shortest unique prefix - second attempt
https://coolbutuseless.github.io/2018/07/24/shortest-unique-prefix-second-attempt/
Tue, 24 Jul 2018 16:00:00 +1000https://coolbutuseless.github.io/2018/07/24/shortest-unique-prefix-second-attempt/Shortest unique prefix - hack part #2 I want to find the shortest unique prefix for each string in a vector (N < 20) i.e. in a vector of strings, what’s the shortest a string can be and still match only itself This isn’t a computational bottleneck in the overall process, so there’s no need for heroic/drastic solutions. I wasn’t going to write a trie implementation just to solve this problem.Shortest unique prefix
https://coolbutuseless.github.io/2018/07/23/shortest-unique-prefix/
Mon, 23 Jul 2018 16:00:00 +1000https://coolbutuseless.github.io/2018/07/23/shortest-unique-prefix/Shortest unique prefix - hack I want to find the shortest unique prefix for each string in a vector (N < 20). This isn’t a computational bottleneck, so no need for heroic/drastic solutions. I wasn’t going to write a trie implementation just to solve this problem. Unfortunately, this got a bit ugly :( .Anyone got a more elegant solution?
library(tidyverse) #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Shortest Unique Prefix # # - Number of strings is always < 20 # - 'strings' input does not contain duplicates # - this isn't a computational bottleneck #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ find_shortest_unique_prefix <- function(strings) { # Determine uniqueness boolean vector of a set of arguments is_unique <- function(.Introducting the 'funcmath' package for creating plotmath expression
https://coolbutuseless.github.io/2018/07/18/introducting-the-funcmath-package-for-creating-plotmath-expression/
Wed, 18 Jul 2018 17:00:00 +1000https://coolbutuseless.github.io/2018/07/18/introducting-the-funcmath-package-for-creating-plotmath-expression/Rationale “That’s a compact and expressive DSL you have there for writing math equations given the constraints of the R language, it’d be a shame if someone were to expand it into an almost redundant and useless set of functions.” - #rstats mafia
Introduction funcmath is a small library for building plotmath expressions via functions.
Some programmers use the term convenience functions i.e. “A convenience function is a non-essential subroutine in a programming library or framework which is intended to ease commonly performed tasks.Ikeda map (fractal)
https://coolbutuseless.github.io/2018/07/09/ikeda-map-fractal/
Mon, 09 Jul 2018 19:00:00 +1000https://coolbutuseless.github.io/2018/07/09/ikeda-map-fractal/Generating an Ikeda Map Today in my ongoing quest to generate fractals in Rstats using every available avenue: generating an Ikeda map.
Methods for generating fractals so far:
Sierpinski Triangle in plotmath Another sierpinski triangle in plotmath Sierpinski triangle using character strings Using R matrices to create a sierpinski carpet Generating hilbert curves with an ad-hoc L-system Barnsley ferns generated by iterated affine transformations Today: Ikeda map Ikeda map An Ikeda map is a model of light going acound a nonlinear optical resonator.Barnsley Ferns (fractal)
https://coolbutuseless.github.io/2018/07/07/barnsley-ferns-fractal/
Sat, 07 Jul 2018 07:00:00 +1000https://coolbutuseless.github.io/2018/07/07/barnsley-ferns-fractal/Barnsley fern via iterated affine transformations (matrix ops) Today in my ongoing quest to generate fractals in Rstats using every available avenue: generating Barnsley ferns via iterated affine transformations (matrix ops)
Methods for generating fractals so far:
Sierpinski Triangle in plotmath Another sierpinski triangle in plotmath Sierpinski triangle using character strings Using R matrices to create a sierpinski carpet Generating hilbert curves with an ad-hoc L-system Today: Barnsley fern generated by iterated affine transformations Barnsley ferns Barnsley ferns are fractals generated by an iterated function system.Hilbert Curves
https://coolbutuseless.github.io/2018/07/06/hilbert-curves/
Fri, 06 Jul 2018 16:00:00 +1000https://coolbutuseless.github.io/2018/07/06/hilbert-curves/Hilbert curves with an ad-hoc L-system Today in my ongoing quest to generate fractals in Rstats using every available avenue: generating a hilbert curve using an ad-hoc L-system
Methods for generating fractals so far:
Sierpinski Triangle in plotmath Another sierpinski triangle in plotmath Sierpinski triangle using character strings Using R matrices to create a sierpinski carpet Today: Generating hilbert curves with an ad-hoc L-system Hilbert Curve A Hilbert Curve is a fractal space-filling curve that looks like a classic 70s wallpaper pattern.Fractals with matrices - sierpinski carpet
https://coolbutuseless.github.io/2018/07/05/fractals-with-matrices-sierpinski-carpet/
Thu, 05 Jul 2018 16:00:00 +1000https://coolbutuseless.github.io/2018/07/05/fractals-with-matrices-sierpinski-carpet/ Today in my ongoing quest to generate fractals in Rstart using every available avenue: generating a sierpinski carpet with matrices.
Methods so far:
Sierpinski Triangle in plotmath Another sierpinski triangle in plotmath Sierpinski triangle using characters Today: Using R matrices to create a sierpinski carpet #rstats #fractal library(raster) f <- function(x) { z <- x z[] <- ' ' rbind( cbind(x,x,x), cbind(x,z,x), cbind(x,x,x) ) } m=matrix('#') m=f(f(f(f(f(m))))) g=matrix(m=='#', nrow=nrow(m)) plot(raster(g), ann=F, axes=F, box=F, legend=F) Text fractals - sierpinski
https://coolbutuseless.github.io/2018/07/04/text-fractals-sierpinski/
Wed, 04 Jul 2018 16:00:00 +1000https://coolbutuseless.github.io/2018/07/04/text-fractals-sierpinski/ library(tidyverse) s <- function(x, y) {c(x + lag(x, d=0), 1) %% 2} r <- Reduce(s, 1:63, 1, acc=T) r <- r %>% map(~paste(ifelse(.x%%2, '#', ' '), collapse='')) cat(paste(r, sep='', collapse='\n')) # ## # # #### # # ## ## # # # # ######## # # ## ## # # # # #### #### # # # # ## ## ## ## # # # # # # # # ################ # # ## ## # # # # #### #### # # # # ## ## ## ## # # # # # # # # ######## ######## # # # # ## ## ## ## # # # # # # # # #### #### #### #### # # # # # # # # ## ## ## ## ## ## ## ## # # # # # # # # # # # # # # # # ################################ # # ## ## # # # # #### #### # # # # ## ## ## ## # # # # # # # # ######## ######## # # # # ## ## ## ## # # # # # # # # #### #### #### #### # # # # # # # # ## ## ## ## ## ## ## ## # # # # # # # # # # # # # # # # ################ ################ # # # # ## ## ## ## # # # # # # # # #### #### #### #### # # # # # # # # ## ## ## ## ## ## ## ## # # # # # # # # # # # # # # # # ######## ######## ######## ######## # # # # # # # # ## ## ## ## ## ## ## ## # # # # # # # # # # # # # # # # #### #### #### #### #### #### #### #### # # # # # # # # # # # # # # # # ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # ################################################################ Plotmath fractals 2
https://coolbutuseless.github.io/2018/07/03/plotmath-fractals-2/
Tue, 03 Jul 2018 16:00:00 +1000https://coolbutuseless.github.io/2018/07/03/plotmath-fractals-2/ Tweetable Fractal in Plotmath - Sierpinski triangle s <- function(x) bquote(.(x)[.(x)]^.(x)) x <- s(s(s(s(s(s(bquote(mu))))))) plot(0, type="n", xlim=c(0,1), ylim=c(0,1), axes=F, ann=F) text(0.5, 0.5, x, cex=1.5) And this is what the plotmath looks like for this sierpinski triangle
(((((mu[mu]^mu)[mu[mu]^mu]^mu[mu]^mu) [(mu[mu]^mu)[mu[mu]^mu]^mu[mu]^mu]^(mu[mu]^mu) [mu[mu]^mu]^mu[mu]^mu)[((mu[mu]^mu)[mu[mu]^mu]^mu[mu]^mu) [(mu[mu]^mu)[mu[mu]^mu]^mu[mu]^mu]^(mu[mu]^mu) [mu[mu]^mu]^mu[mu]^mu]^((mu[mu]^mu)[mu[mu]^mu]^mu[mu]^mu) [(mu[mu]^mu)[mu[mu]^mu]^mu[mu]^mu]^(mu[mu]^mu) [mu[mu]^mu]^mu[mu]^mu)[(((mu[mu]^mu)[mu[mu]^mu]^mu[mu]^mu) [(mu[mu]^mu)[mu[mu]^mu]^mu[mu]^mu]^(mu[mu]^mu) [mu[mu]^mu]^mu[mu]^mu)[((mu[mu]^mu)[mu[mu]^mu]^mu[mu]^mu) [(mu[mu]^mu)[mu[mu]^mu]^mu[mu]^mu]^(mu[mu]^mu) [mu[mu]^mu]^mu[mu]^mu]^((mu[mu]^mu)[mu[mu]^mu]^mu[mu]^mu) [(mu[mu]^mu)[mu[mu]^mu]^mu[mu]^mu]^(mu[mu]^mu) [mu[mu]^mu]^mu[mu]^mu]^(((mu[mu]^mu)[mu[mu]^mu]^mu[mu]^mu) [(mu[mu]^mu)[mu[mu]^mu]^mu[mu]^mu]^(mu[mu]^mu) [mu[mu]^mu]^mu[mu]^mu)[((mu[mu]^mu)[mu[mu]^mu]^mu[mu]^mu) [(mu[mu]^mu)[mu[mu]^mu]^mu[mu]^mu]^(mu[mu]^mu) [mu[mu]^mu]^mu[mu]^mu]^((mu[mu]^mu)[mu[mu]^mu]^mu[mu]^mu) [(mu[mu]^mu)[mu[mu]^mu]^mu[mu]^mu]^(mu[mu]^mu) [mu[mu]^mu]^mu[mu]^mu)[((((mu[mu]^mu)[mu[mu]^mu]^mu[mu]^mu) [(mu[mu]^mu)[mu[mu]^mu]^mu[mu]^mu]^(mu[mu]^mu) [mu[mu]^mu]^mu[mu]^mu)[((mu[mu]^mu)[mu[mu]^mu]^mu[mu]^mu) [(mu[mu]^mu)[mu[mu]^mu]^mu[mu]^mu]^(mu[mu]^mu) [mu[mu]^mu]^mu[mu]^mu]^((mu[mu]^mu)[mu[mu]^mu]^mu[mu]^mu) [(mu[mu]^mu)[mu[mu]^mu]^mu[mu]^mu]^(mu[mu]^mu) [mu[mu]^mu]^mu[mu]^mu)[(((mu[mu]^mu)[mu[mu]^mu]^mu[mu]^mu) [(mu[mu]^mu)[mu[mu]^mu]^mu[mu]^mu]^(mu[mu]^mu) [mu[mu]^mu]^mu[mu]^mu)[((mu[mu]^mu)[mu[mu]^mu]^mu[mu]^mu) [(mu[mu]^mu)[mu[mu]^mu]^mu[mu]^mu]^(mu[mu]^mu) [mu[mu]^mu]^mu[mu]^mu]^((mu[mu]^mu)[mu[mu]^mu]^mu[mu]^mu) [(mu[mu]^mu)[mu[mu]^mu]^mu[mu]^mu]^(mu[mu]^mu) [mu[mu]^mu]^mu[mu]^mu]^(((mu[mu]^mu)[mu[mu]^mu]^mu[mu]^mu) [(mu[mu]^mu)[mu[mu]^mu]^mu[mu]^mu]^(mu[mu]^mu) [mu[mu]^mu]^mu[mu]^mu)[((mu[mu]^mu)[mu[mu]^mu]^mu[mu]^mu) [(mu[mu]^mu)[mu[mu]^mu]^mu[mu]^mu]^(mu[mu]^mu) [mu[mu]^mu]^mu[mu]^mu]^((mu[mu]^mu)[mu[mu]^mu]^mu[mu]^mu) [(mu[mu]^mu)[mu[mu]^mu]^mu[mu]^mu]^(mu[mu]^mu) [mu[mu]^mu]^mu[mu]^mu]^((((mu[mu]^mu)[mu[mu]^mu]^mu[mu]^mu) [(mu[mu]^mu)[mu[mu]^mu]^mu[mu]^mu]^(mu[mu]^mu) [mu[mu]^mu]^mu[mu]^mu)[((mu[mu]^mu)[mu[mu]^mu]^mu[mu]^mu) [(mu[mu]^mu)[mu[mu]^mu]^mu[mu]^mu]^(mu[mu]^mu) [mu[mu]^mu]^mu[mu]^mu]^((mu[mu]^mu)[mu[mu]^mu]^mu[mu]^mu) [(mu[mu]^mu)[mu[mu]^mu]^mu[mu]^mu]^(mu[mu]^mu) [mu[mu]^mu]^mu[mu]^mu)[(((mu[mu]^mu)[mu[mu]^mu]^mu[mu]^mu) [(mu[mu]^mu)[mu[mu]^mu]^mu[mu]^mu]^(mu[mu]^mu) [mu[mu]^mu]^mu[mu]^mu)[((mu[mu]^mu)[mu[mu]^mu]^mu[mu]^mu) [(mu[mu]^mu)[mu[mu]^mu]^mu[mu]^mu]^(mu[mu]^mu) [mu[mu]^mu]^mu[mu]^mu]^((mu[mu]^mu)[mu[mu]^mu]^mu[mu]^mu) [(mu[mu]^mu)[mu[mu]^mu]^mu[mu]^mu]^(mu[mu]^mu) [mu[mu]^mu]^mu[mu]^mu]^(((mu[mu]^mu)[mu[mu]^mu]^mu[mu]^mu) [(mu[mu]^mu)[mu[mu]^mu]^mu[mu]^mu]^(mu[mu]^mu) [mu[mu]^mu]^mu[mu]^mu)[((mu[mu]^mu)[mu[mu]^mu]^mu[mu]^mu) [(mu[mu]^mu)[mu[mu]^mu]^mu[mu]^mu]^(mu[mu]^mu) [mu[mu]^mu]^mu[mu]^mu]^((mu[mu]^mu)[mu[mu]^mu]^mu[mu]^mu) [(mu[mu]^mu)[mu[mu]^mu]^mu[mu]^mu]^(mu[mu]^mu) [mu[mu]^mu]^mu[mu]^mu Plotmath fractals
https://coolbutuseless.github.io/2018/07/02/plotmath-fractals/
Mon, 02 Jul 2018 21:00:00 +1000https://coolbutuseless.github.io/2018/07/02/plotmath-fractals/Plotmath plotmath is a little domain specific language within R used to define and display mathematical formula.
It looks just like R code, but is interpreted in a different context in order to make a math equation.
Writing x ^ 2 in R usually tries to evaluate what x-squared is, but in a plotmath expression, the symbols are interpreted as their relative arrangement in a mathematical formula.Benchmark mutate - vector, matrix, data.frame
https://coolbutuseless.github.io/2018/05/12/benchmark-mutate-vector-matrix-data.frame/
Sat, 12 May 2018 17:30:00 +1000https://coolbutuseless.github.io/2018/05/12/benchmark-mutate-vector-matrix-data.frame/Introduction I’m looking at some numeric code that’s going to be in an inner loop and just wanted to get an idea of the relative speed differences of different approaches (Rcpp may be an option in the future, but not right now.)
Benchmark Context:
The vector lengths are in the range 1000-10000 This operation will be performed of the order of 1000 times. Key question: Is the speed gained by working with raw lists of vectors worth losing the convenience/safety of the data.Challenge: Simultaneous parallel min() and which.min()
https://coolbutuseless.github.io/2018/05/12/challenge-simultaneous-parallel-min-and-which.min/
Sat, 12 May 2018 12:00:00 +1000https://coolbutuseless.github.io/2018/05/12/challenge-simultaneous-parallel-min-and-which.min/Problem: p.which.min() Input: vs A list of N vectors of numeric values (each the same length, L) Output: For each index along the vectors (1..L) the minimum value out of the N vectors at this index the index of the vector that had the minimum (1..N) Conditions: If there are multiple vectors with the same minimum at the given index, it doesn’t matter which is returned.Hi-res c64 images with Rstats 'r64' package
https://coolbutuseless.github.io/2018/05/10/hi-res-c64-images-with-rstats-r64-package/
Thu, 10 May 2018 17:30:00 +1000https://coolbutuseless.github.io/2018/05/10/hi-res-c64-images-with-rstats-r64-package/Hires bitmap In this post, the r64 package will be used to:
generate a 320x200 hires Rstats logo in bitmap form suitable for the c64. incorporate those bytes into an R program using the r64 package and the R-specific .rbyte directive. compile the code and run it in an emulator (VICE). Converting an image into a monochrome bitmap matix Use imagemagick to convert an image into: 320x200 monochrome dithered keeping aspect ratio while padding to the correct size #----------------------------------------------------------------------------- #' Create a 320x200 binary matrix out of an image file #' #' @param image_filename full path to an image that can be read by imagemagick #' @param dither boolean.Introducing the `tapir` package: Text-based Arbitrary Precision Integers in R
https://coolbutuseless.github.io/2018/05/07/introducing-the-tapir-package-text-based-arbitrary-precision-integers-in-r/
Mon, 07 May 2018 17:30:00 +1000https://coolbutuseless.github.io/2018/05/07/introducing-the-tapir-package-text-based-arbitrary-precision-integers-in-r/Rationale This is a toy library written in order bootstrap another idea, without having to carry a dependency on a real arbitrary precision library like gmp or Rmpfr.
The algorithms are straight-forward implementations of naive algorithms and are orders of magnitute slower than gmp even for small/moderate sized integers.
Installation devtools::install_github('coolbutuseless/tapir') Supported data types The only supported datatype is an unsigned integer represented in a character string.Challenge: Adding Large Integers in R
https://coolbutuseless.github.io/2018/05/04/challenge-adding-large-integers-in-r/
Fri, 04 May 2018 16:00:00 +1000https://coolbutuseless.github.io/2018/05/04/challenge-adding-large-integers-in-r/Challenge Write R code to add 2 BigInts (arbitrarily large integers) Integer input is as a string containing just the digits 0-9 e.g. "28349823749234234238077632" Integer output should be the same. Contributions welcome! No calling out to C libraries or using Rcpp :) Prep work: Create random large integers Guarantee that there are no leading zeros (as gmp will interpret as octal) rbigint <- function(size) { paste(c( sample(1:9, size = 1), sample(0:9, size = size-1, replace = TRUE) ), collapse='') } rbigint(50) [1] "60736670197966208346760834361818514898029183539092" Naive: for loop Split each number into individual digits Pad out each list of digits with zeros so that they’re the same length Loop over the digits, adding them 1 pair at a time, and including any carry from the previous pair.Finding names in R packages which could be domain names (using rvest and the tidyverse)
https://coolbutuseless.github.io/2018/05/02/finding-names-in-r-packages-which-could-be-domain-names-using-rvest-and-the-tidyverse/
Wed, 02 May 2018 16:00:00 +1000https://coolbutuseless.github.io/2018/05/02/finding-names-in-r-packages-which-could-be-domain-names-using-rvest-and-the-tidyverse/Introduction Twitter likes to turn things which look like URLs into URLS.
I tweeted some rstats code last week and twitter decided that seq.int was actually http://seq.int.
According to wikipedia, the .int TLD has the “strictest application policies of all TLDs”, so there’s no chance of registering that particular domain.
Out of the other standard R packages in base in the tidyverse, which ones could be domain names?`uint8` package for an unsigned 8bit integer type in R
https://coolbutuseless.github.io/2018/04/29/uint8-package-for-an-unsigned-8bit-integer-type-in-r/
Sun, 29 Apr 2018 16:00:00 +1000https://coolbutuseless.github.io/2018/04/29/uint8-package-for-an-unsigned-8bit-integer-type-in-r/uint8 - An 8-bit unsigned integer type for R An 8-bit unsigned integer type for R based upon the raw type. Each value is stored in a single byte (whereas integer values in R are stored in 4 bytes), so there can be memory savings. Stores only values 0-255 No NA, NaN, or Inf allowed Basic arithmethic The aim is to have similar behaviour to the uint8_t type in C.r64 package - a c64/6502 assembler
https://coolbutuseless.github.io/2018/04/25/r64-package-a-c64/6502-assembler/
Wed, 25 Apr 2018 15:00:00 +1000https://coolbutuseless.github.io/2018/04/25/r64-package-a-c64/6502-assembler/r64 - a c64/6502 assembler in R Package home is on github Full documentation is available here: coolbutuseless.github.io/package/r64 Rationale Who doesn’t want a compiler for a 1 MHz 8-bit computer with 16 colours and a max resolution of 320x200? A 6502 assembler in R will allow for preparing/calculating data in R and then incorporating directly into the assembly code. e.g. creating character sets computing animation paths Features General featuresGenerating Executable ASCII art
https://coolbutuseless.github.io/2018/04/12/generating-executable-ascii-art/
Thu, 12 Apr 2018 17:00:00 +1000https://coolbutuseless.github.io/2018/04/12/generating-executable-ascii-art/Introduction Images can be converted to an ASCII representation - it’s a hack that’s as old as the hills This post’s contributions: Tweet-sized ascii image generator in R Executable art Notes/References Scarecrow’s ASCII reference ASCII art generation using the local exhaustive search on the GPU Tweet sized ascii image generator C=strsplit('851+-. ','')[[1]] i=jpeg::readJPEG(system.file('img/Rlogo.jpg',package='jpeg'))[c(T,F),,2] i[]=C[findInterval(i,quantile(i,p=seq(0,1,,length(C))))] cat(apply(i,1,paste,collapse=''),sep='\n') -- - -- - ++++++++++++++++++ -- -- - - - -+ - - + -- ++++155555555555555555555555555555551+++ -+- +-- + - +- - -++15555555555151111111111155555555555555555558851++ -- ++ - - + - ++15511111111111111111111111111111111111111155555555555885+++ - - - -- + +1511111111115555555511111111111111555555555555551111155555555888+ - - - - - - +1111111++15555555511+++++1155555555588888888888555555555555515555558881+ +- +111111+++58855551+++++++1155588888888888888888888888888888888885555515558888+ - -+11111++18855551+++++++11588888888885+++- - -- - -++15888888855555558881 + +--- -+1111+++5855551+++++++1588888885++ -+ -------------------- -+188888555558881 - -- -+ + +1111+++888551+++++++158888881+ - -+- - --- ----+--+--++ -+58855558888+ + - -+111+++885551+++++++5888888+ -+115555555555555555555555555555555555551++- +1885558885 + ++111++588551+++++++588888++ +-- - +51++11111111111111111111111111111++++155885+ +-- +55555888 - +111++88855+++++++588888+- - -- +51+885555555555555555555555555555588888515888+--- +1555888+ +111++88551+++++++58888+ +- + -- +51+88111111111++++++++++++++++11111111158855888-+- +555885 +111++58851+++++++88888+ +- + +-- +51+881111111++1888888888888855551111111111585888 - - -15588+ +111++88551++++++58888 +- + + +51+88111111+188888888888888888855551111111155888++ +--15581 +111+58851++++++18888+ - +51+8811111115888+ --+-+5851185111111155888 ++5588 +111+58851++++++18888+ - +51+8811111115888+---- - +51+88111111115888 --+188 +511158851++++++18888 - +51+88111111+5888+ - +- +51+88111111+15888 -+185 +5511188551++++++8888- +51+8811111115888+--------+-++ 11++88111111+18885- -- -158+ +511158551++++++58881 - +- + +51+8811111115888+ -++11++88111111++5888+-- +- +188- 5551558551++++++5888+ - +-- - +51+88111111155555555555555551++++8811111+++8888+--+ +158+ -+5555555551++++++5888+ -+-- +51+881111111588511++++++++++1888851+++++188888+ -+ +158+ - + +1555555555++++++15888+ - ++- +51+881111111111555555555555551+++11158888888+-+- -+ -+188+ - - +5555555551+++++115885+- - - - +51+88111111111+++++++++111111+18888888885+--+--+ -+1585+ -- ++-+555555555511+++1115888+ - - +51+881111111++155588555555111558881+-- - -+---+11188+ - - - +585555555111+++11155885+-+ ++51+88111111+188888888888855515855555585++ - -+111588+ + - ++58855555511111+1115555885+++51+88111111158881- ---+5885155588881+15885+1115888+- -- - + - +588555555511111111555555551+88111111158881- - -+555+5511155888588858881 - +- +888888555555111111155551+88111111+58881+++++++++5551581111115858881 - - - - -+ -+188888885555555511551+881111111588885555111111585158111111585888+ - - -+ -- - -+ -+5888888888855551+88111111158885111115555888551581111111858885- ++5888888851+88111111+588888888888888885851581111111555888+- - -- - -+ ++51+881111111588888551+++ - 1551181111111585888+ + --- + - +51+8811111115888+ -- -+- - +851181111111585888+ ---- +- +- - -+51+85+++++++5888+ -+- --- - - +85118++++++++55888+----+ - --+5118588585885888+ --- +8555888888888888881- -- + ++-+8888888888888888+ -- +8888888888888888885+ What’s executable in R?Changing the default arguments to a function
https://coolbutuseless.github.io/2018/04/11/changing-the-default-arguments-to-a-function/
Wed, 11 Apr 2018 17:00:00 +1000https://coolbutuseless.github.io/2018/04/11/changing-the-default-arguments-to-a-function/Problem: I don’t like the default arguments of a function Say I don’t like the default arguments of a particular function. What can I do about it?
For example, 99.999% of the time, I’d be happier with mean defaulting to na.rm=TRUE. Instead I get NAs when I don’t want, and I have to remember to call it and override the default na.rm value.
# I usually forget to set `na.Solving the 8 queens problem
https://coolbutuseless.github.io/2018/04/10/solving-the-8-queens-problem/
Tue, 10 Apr 2018 17:00:00 +1000https://coolbutuseless.github.io/2018/04/10/solving-the-8-queens-problem/Introduction to the 8 queens puzzle The eight queens puzzle is the problem of placing eight chess queens on an 8×8 chessboard so that no two queens threaten each other.
The wikipedia page is a good starting resource.
This post contains:
A neat version of a recursive function for finding all solutions: place_queen() A manually minified version that fits in a tweet (including generating a plot) Recursive solution in R library(tidyverse) #----------------------------------------------------------------------------- #' Try and place a queen given the queens we have on the board so far.Finding a length n needle in a haystack
https://coolbutuseless.github.io/2018/04/03/finding-a-length-n-needle-in-a-haystack/
Tue, 03 Apr 2018 17:30:00 +1000https://coolbutuseless.github.io/2018/04/03/finding-a-length-n-needle-in-a-haystack/Problem: Find index of a short vector (needle) inside a larger vector (haystack) What’s a good way to find the location of a needle in a haystack?
haystack <- sample(0:12, size = 2000, replace = TRUE) needle <- c(2L, 10L, 8L) The haystack may be large. The needle is definitely a vector Only the index for the first occurrence of needle within haystack is needed Assuming that there is always at least 1 occurrence Solution 1: for loop Naively test every position in a for loop Advantage of this method over a vectorised approach, is that it can terminate early i.Assert condition over a code block
https://coolbutuseless.github.io/2018/03/23/assert-condition-over-a-code-block/
Fri, 23 Mar 2018 05:30:00 +1000https://coolbutuseless.github.io/2018/03/23/assert-condition-over-a-code-block/Assert an expression is unchanged over a code block Most (all?) testing packages in R are built around the idea of testing a value at a particular moment in time e.g. “Check that a == 2 right now”.
The prior post detailed a function to test an expected changed in value of a particular expression before & after some particular code is run. E.g. I might not know how long a data.Assert condition over a code block
https://coolbutuseless.github.io/2018/03/22/assert-condition-over-a-code-block/
Thu, 22 Mar 2018 16:30:00 +1000https://coolbutuseless.github.io/2018/03/22/assert-condition-over-a-code-block/Assert a logical statement over a code block Most (all?) testing packages in R are built around the idea of testing a value at a particular moment in time e.g. “Check that a == 2 right now”.
This post proposes a way to test the expected change in value of a particular expression before & after some particular code is run. E.g. I might not know how long a data.Body modification part 5: Adding runtime check of function return value
https://coolbutuseless.github.io/2018/03/21/body-modification-part-5-adding-runtime-check-of-function-return-value/
Wed, 21 Mar 2018 17:30:00 +1000https://coolbutuseless.github.io/2018/03/21/body-modification-part-5-adding-runtime-check-of-function-return-value/Problem: Can I augment an existing function with checking code for its return value? I’m still experimenting with function body modification, and I’ve downscaled my ambitions and thought about what a type check helper should look like.
Yesterday’s post showed that a simple function could be used to add checks to an existing function.
This post is about writing a function to add a check for the return value of a function.Body modification part 4: Adding runtime checks to an existing function
https://coolbutuseless.github.io/2018/03/20/body-modification-part-4-adding-runtime-checks-to-an-existing-function/
Tue, 20 Mar 2018 17:30:00 +1000https://coolbutuseless.github.io/2018/03/20/body-modification-part-4-adding-runtime-checks-to-an-existing-function/Problem: Can I augment an existing function with checking code for a function? I’m still experimenting with function body modification, and I’ve downscaled my ambitions and thought about what a type check helper should look like.
My first attempt worked, but in a very roundabout fashion and had holes big enough to drive a truck through.
The previous post showed that the code to apply a function to another can get very obscure (and unreadable!Body modification part 3: Syntax for body modification/function wrapping
https://coolbutuseless.github.io/2018/03/19/body-modification-part-3-syntax-for-body-modification/function-wrapping/
Mon, 19 Mar 2018 17:30:00 +1000https://coolbutuseless.github.io/2018/03/19/body-modification-part-3-syntax-for-body-modification/function-wrapping/The prior experiment on generating automatic runtime tests and the ensurer package used different methods of trying to wrap the original function so that it could be augmented with tests. What other ways are possible/sensible?
Python has solved this problem with decorators - they’re pretty neat, and look great.
None of what follows is neat, and all of these are going to be a lot of work for no real benefit other than seeing how they operate!Body modification part 2: Automatically creating type checks for a function
https://coolbutuseless.github.io/2018/03/18/body-modification-part-2-automatically-creating-type-checks-for-a-function/
Sun, 18 Mar 2018 17:30:00 +1000https://coolbutuseless.github.io/2018/03/18/body-modification-part-2-automatically-creating-type-checks-for-a-function/Problem: Can I automatically create type checking code for a function? This post is mainly scratching an itch to learn about some function internals. I want to work out a way to have R generate all the type checks for a given function given some shorter definition.
Notes:
mypy - optional static typing for python recently popped up on twitter and got me thinking about types in R.Body modification: Injecting new content into a function
https://coolbutuseless.github.io/2018/03/16/body-modification-injecting-new-content-into-a-function/
Fri, 16 Mar 2018 06:30:00 +1000https://coolbutuseless.github.io/2018/03/16/body-modification-injecting-new-content-into-a-function/Problem: Can the contents of 2 functions be merged into a single function using R? A function consists of 3 things:
formal arguments body environment The body of a function can be
fetched using body() set using body<-() With these functions for manipulating bodies, can the contents of two functions be merged into a single function using R?
And can the resulting function’s body look neat?Base R split has issues - Part 3 more idiosyncrasies
https://coolbutuseless.github.io/2018/03/15/base-r-split-has-issues-part-3-more-idiosyncrasies/
Thu, 15 Mar 2018 06:30:00 +1000https://coolbutuseless.github.io/2018/03/15/base-r-split-has-issues-part-3-more-idiosyncrasies/Base R split() My prior post on tidyverse split-apply-combined ended with me favouring split + map_dfr as a replacement for group_by + do. In prior posts I saw:
Base R split() runtime is quadratic in number of splitting variables - (see post) Base R split() runtime is quadratic in number of groups within each variable - (see post) split() recycles splitting variables and silent dropping of all NA levels (see post) In the process of working on my pull request for chop() I found I had even more issues with split().geom_cat()
https://coolbutuseless.github.io/2018/03/08/geom_cat/
Thu, 08 Mar 2018 17:30:00 +1000https://coolbutuseless.github.io/2018/03/08/geom_cat/ Some test plots in order to get borders and font-sizes correct for large (A0) plan printing from ggplot.
This is printed on tyvek which is made of woven HDPE - it’s untearable, machine washable, and totally kicks arse.
geom_cat() + theme_bw() geom_cat() + scale_x_continuous(expand='carpet') `chop()`: A tidyverse-style `split()`
https://coolbutuseless.github.io/2018/03/07/chop-a-tidyverse-style-split/
Wed, 07 Mar 2018 17:30:00 +1000https://coolbutuseless.github.io/2018/03/07/chop-a-tidyverse-style-split/tidyverse split(): The journey to the pull request Last week I searched for a replacement for group_by + do, and this ended with split + map_dfr being my favourite alternative. Conceptually it was the most compact representation of the idea (just 2 commands) and avoided a the extra work that seemed necessary to nest a data.frame and operate on the nested data.
I then looked more closely at the split() function, in particular the runtime characteristics and its idioscrasies and noted that in the Base R split() function:`cleave_by()`: A tidyverse-style `split()`
https://coolbutuseless.github.io/2018/03/04/cleave_by-a-tidyverse-style-split/
Sun, 04 Mar 2018 17:30:00 +1000https://coolbutuseless.github.io/2018/03/04/cleave_by-a-tidyverse-style-split/My issues with split() in base R My prior post on tidyverse split-apply-combined ended with me favouring split + map_dfr as a replacement for group_by + do.
In subsequent posts I looked at the runtime of the split function and the idioscrasies of the split function and saw the following for the Base R split() function:
runtime is quadratic in number of splitting variables runtime is quadratic in number of groups within each variable the splitting variable gets recycled if it’s not as long as the data.Base R split has issues - Part 2 idiosyncrasies
https://coolbutuseless.github.io/2018/03/04/base-r-split-has-issues-part-2-idiosyncrasies/
Sun, 04 Mar 2018 14:30:00 +1000https://coolbutuseless.github.io/2018/03/04/base-r-split-has-issues-part-2-idiosyncrasies/Base R split() My prior post on tidyverse split-apply-combined ended with me favouring split + map_dfr as a replacement for group_by + do. In this post I look at some idioscrasies of the split function from Base R.
The main 2 gotchas with base R split():
the splitting variable gets recycled if it’s not as long as the data.frame being split NA levels are dropped from the data Idiosyncrasy 1: the splitting variable gets recycled if it’s not long enough If trying to split() a data.Base R split has issues - Part 1 runtime
https://coolbutuseless.github.io/2018/03/04/base-r-split-has-issues-part-1-runtime/
Sun, 04 Mar 2018 12:30:00 +1000https://coolbutuseless.github.io/2018/03/04/base-r-split-has-issues-part-1-runtime/Base R split() My prior post on tidyverse split-apply-combined ended with me favouring split + map_dfr as a replacement for group_by + do. In this post I benchmark the runtime of base R split().
Looking at the runtime graphs which follow, it seems:
Base R split() runtime is quadratic in number of splitting variables Base R split() runtime is quadratic in number of groups within each variable Neither of these is a good thing – a doubling in the number of splitting variables, or a doubling of levels within a splitting variable would increase runtimes by ~4x (modulo the baseline runtime)Split-Apply-Combine: My search for a replacement for 'group_by + do'
https://coolbutuseless.github.io/2018/03/03/split-apply-combine-my-search-for-a-replacement-for-group_by-do/
Sat, 03 Mar 2018 07:30:00 +1000https://coolbutuseless.github.io/2018/03/03/split-apply-combine-my-search-for-a-replacement-for-group_by-do/Introduction I currently process a lot of data a single entity at a time, but have a data.frame representing multiple entities as input.
I have specialist functions that do a lot of work on the data.frame for a single entity, so I want to split the original data.frame into multiple data.frames containing just one entity each and then process them one at a time.
This is a classic case of split-apply-combine, as outlined Hadley Wickham’s JStatSoft paper (pdf) and Jenny Bryan’s Stat545 notesThe 'ggplot2pipes' package
https://coolbutuseless.github.io/2018/02/27/the-ggplot2pipes-package/
Tue, 27 Feb 2018 15:45:00 +1000https://coolbutuseless.github.io/2018/02/27/the-ggplot2pipes-package/Sometimes it doesn’t feel like a project (no matter how small!) is completed until there’s a package for it.
I wrapped up my previous post on using pipes with ggplot2 into the ggplot2pipes package.
In summary:
ggplot2pipes is a package for creating pipe-enabled versions of ggplot2 functions. You can find it on github. Install: devtools::install_github("coolbutuseless/ggplot2pipes") This supercedes the pipify package from 2015. Basic Usage Call init_ggplot2_pipes() to create all the pipe-enabled functions.Using ggplot with pipes
https://coolbutuseless.github.io/2018/02/25/using-ggplot-with-pipes/
Sun, 25 Feb 2018 17:45:00 +1000https://coolbutuseless.github.io/2018/02/25/using-ggplot-with-pipes/Problem I want to add pipes to ALL THE THINGS. ggplot2 is a thing ggplot2 doesn’t use pipes Add pipe support to ggplot2 Write a blog post. ??? Profit Note: for keen followers, this is a rehash of my hack that was the pipify package.
ggplot without pipes. :( Using the + character is soooo early 2010’s.
ggplot(mtcars) + geom_point(aes(mpg, cyl)) Create add_geom_point as a pipe-able geom_point :) Let’s write a wrapper around geom_point so that I can use it in a pipeCustoming ggplots created within functions
https://coolbutuseless.github.io/2018/02/24/customing-ggplots-created-within-functions/
Sat, 24 Feb 2018 08:45:00 +1000https://coolbutuseless.github.io/2018/02/24/customing-ggplots-created-within-functions/Problem I often need to create complicated plots within a function.
A dataset is passed in to the function, then I do some data transformation and then create a multilayered/complicated plot.
I then set up the plot to have good default colours, aesthetics etc.
However sooner or later, I’ll want to override the defaults or add some extra styling.
This post details how these plotting functions start and how they end up.Overlapping lines
https://coolbutuseless.github.io/2018/02/20/overlapping-lines/
Tue, 20 Feb 2018 17:45:00 +1000https://coolbutuseless.github.io/2018/02/20/overlapping-lines/Overlapping lines for interesting image effect While convex hulls can produce some interesting results (See parts 1, 2, 3, 4 ) they’re expensive to compute relative to just drawing lines.
The same idea using lines is 1000x faster and the results are just as good:
Sample points from the image (with darker pixels having a higher probability of being sampled) Find the distance between successive points and filter out line segments which are too long Draw a single poly-line connecting all the remaining points Final image using lines rather than convex hulls Code #----------------------------------------------------------------------------- # Read a jpg file using image magick and scale it and convert to greyscale #----------------------------------------------------------------------------- filename <- 'data/mona.Convex Hulls part 4
https://coolbutuseless.github.io/2018/02/18/convex-hulls-part-4/
Sun, 18 Feb 2018 07:45:00 +1000https://coolbutuseless.github.io/2018/02/18/convex-hulls-part-4/Messing around with chull As mentioned previously ( 1, 2, 3 ) I’m attempting to use chull() to create some stuff.
I had though that using convex hulls would give me some nicer medium-scale circular artefacts in the image, but that didn’t occur.
Instead, just using the random points sampled from the image to draw a very long line was sufficient to produce an almost equivalent image (and about 1000x faster as well!Convex Hulls part 3
https://coolbutuseless.github.io/2018/02/18/convex-hulls-part-3/
Sun, 18 Feb 2018 07:30:00 +1000https://coolbutuseless.github.io/2018/02/18/convex-hulls-part-3/Messing around with chull As mentioned yesterday, I’m using chull() to create some stuff.
The basic scheme is:
Generate a large number of points somehow Repeat the following until done: Take a small subset of the points Draw the convex hull around them. Extra filtering was done to reject some of the generated convex hulls, i.e.
Reject those with a large area, as I wanted to use smaller, local hulls Reject those with “bad” circularity.convex hulls part 2
https://coolbutuseless.github.io/2018/02/16/convex-hulls-part-2/
Fri, 16 Feb 2018 05:30:00 +1000https://coolbutuseless.github.io/2018/02/16/convex-hulls-part-2/ Messing around with chull As mentioned yesterday, I’m using chull() to create some stuff.
The basic scheme is:
Generate a large number of points somehow Repeat until done: Take a small subset of the points Draw the convex hull around them. Instead of tweaked random point fields, here’s what happens when a recognizable image is used as a point source.
Mona Lisa Girl with a Pearl Earring chull()
https://coolbutuseless.github.io/2018/02/15/chull/
Thu, 15 Feb 2018 16:00:00 +1000https://coolbutuseless.github.io/2018/02/15/chull/ Messing around with chull Taking a break from whitelisting/sandboxing and malicous users.
Using chull() to create some stuff.
Generate a large number of points somehow Repeat until done: Take a small subset of the points Draw the convex hull around them. Evaluating R code from potentially malicious sources Part 4
https://coolbutuseless.github.io/2018/02/13/evaluating-r-code-from-potentially-malicious-sources-part-4/
Tue, 13 Feb 2018 08:00:00 +1000https://coolbutuseless.github.io/2018/02/13/evaluating-r-code-from-potentially-malicious-sources-part-4/Which of the functions from the base R package would you let a malicious user run? There are 1301 functions in the base package version 3.6.1.
What functions would you want to prevent a malicious user from running?
This post is going doing a (very rough) first pass over what’s in the base package and do some (lazy, half-arsed!) classification of some functions into safe(?) and unsafe(?). Note the presence of the (?Part 3: Evaluating R code from potentially malicious sources
https://coolbutuseless.github.io/2018/02/12/part-3-evaluating-r-code-from-potentially-malicious-sources/
Mon, 12 Feb 2018 08:00:00 +1000https://coolbutuseless.github.io/2018/02/12/part-3-evaluating-r-code-from-potentially-malicious-sources/TLDR: Shiny app Shiny app using safe(?) evalation of R code
Please try and tell me if you break it or make it do something unsafe …
Evaluating R code from potentially malicious sources - part 3 As mentioned in Part 1, and Part 2 I’m looking into the idea of running R code which may originate from potentially malicious sources e.g. code from a web interface, or a database or even a tweet!Evaluating R code from potentially malicious sources part 2
https://coolbutuseless.github.io/2018/02/11/evaluating-r-code-from-potentially-malicious-sources-part-2/
Sun, 11 Feb 2018 08:00:00 +1000https://coolbutuseless.github.io/2018/02/11/evaluating-r-code-from-potentially-malicious-sources-part-2/Evaluating R code from potentially malicious sources - part 2 As mentioned in Part 1, I’m looking into the idea of running R code which may originate from potentially malicious sources e.g. code from a web interface, or a database or even a tweet!
My idea after yesterday’s post was to evaluate the code one expression at a time and check the function signature of any calls to ensure nothing had been renamed.Evaluating R code from potentially malicious sources
https://coolbutuseless.github.io/2018/02/10/evaluating-r-code-from-potentially-malicious-sources/
Sat, 10 Feb 2018 16:00:00 +1000https://coolbutuseless.github.io/2018/02/10/evaluating-r-code-from-potentially-malicious-sources/Evaluating R code from potentially malicious sources I’m looking into the idea of running R code which may originate from potentially malicious sources e.g. code from a web interface, or a database or even a tweet!
If we allow user input of R code, eventually someone is going to try system("rm -rf /") or something equally dangerous, so I would like to forbid the use of system while still allowing the use of mean, +, c() etc.YAML vs jsonlite vs RJSONIO
https://coolbutuseless.github.io/2018/02/07/yaml-vs-jsonlite-vs-rjsonio/
Wed, 07 Feb 2018 16:00:00 +1000https://coolbutuseless.github.io/2018/02/07/yaml-vs-jsonlite-vs-rjsonio/Comparison of R object encoding with YAML, jsonlist and RJSONIO As described in a prior post I need to save some configuration objects from R into human-readable, human-editable format.
I’d previously decided that YAML was the best for my purposes, but I recently discovered that YAML and jsonlite won’t keep the names of a named vector, whereas RJSONIO will.
In response to this discovery, I’ve decided to check a large number of standard R object types output by the three packages (yaml, jsonlite and RJSONIO) to get a better picture of their strengths and weaknesses.`blogdown` rss feed of full articles
https://coolbutuseless.github.io/2018/02/07/blogdown-rss-feed-of-full-articles/
Wed, 07 Feb 2018 08:00:00 +1000https://coolbutuseless.github.io/2018/02/07/blogdown-rss-feed-of-full-articles/RSS Setup in Blogdown By default, blogdown in Rstats includes an RSS feed which is limited to just the first snippet from each article.
For some RSS aggregators, it’s probably nicer to have a full article showing up in the feed.
Ensure you have a full baseURL in your config.toml e.g. baseURL = "https://coolbutuseless.github.io/" Ensure you have an rss.xml file by default I think blogdown just uses the hugo’s internal rss.`dithr` package for error diffusion dithering in R
https://coolbutuseless.github.io/2018/02/05/dithr-package-for-error-diffusion-dithering-in-r/
Mon, 05 Feb 2018 16:00:00 +1000https://coolbutuseless.github.io/2018/02/05/dithr-package-for-error-diffusion-dithering-in-r/Introduction I made a simple package to encapsulate the dithering code from yesterday’s post.
The package is called dithr and is available on github
The code expects a numeric matrix (all values in the range [0, 1]) as input and provides a matrix as output with only 0 and 1 values. It includes 10 pre-defined diffusion matrices in dithr::diffusion_matrix.
At the moment it’s not really very user friendly, mostly because dealing with image data in R can be a bit of a pain.Error Diffusion Dithering in R
https://coolbutuseless.github.io/2018/02/04/error-diffusion-dithering-in-r/
Sun, 04 Feb 2018 08:00:00 +1000https://coolbutuseless.github.io/2018/02/04/error-diffusion-dithering-in-r/Introduction I wanted to experiment with some dithering algorithms within R, but I also wanted complete control of the error diffusion.
After reading Tanner Helland’s articale on dithering, I decided to implement some generic dithering code in order to experiment.
Packages
magick - for image preparation EBImage - easiest(?) way to get image data out of magick To Do
Serpentine error diffusion (i.e. alternating traversal direction every row) Original Image #----------------------------------------------------------------------------- # Using imagemagick to load and convert the image to grayscale #----------------------------------------------------------------------------- im <- magick::image_read(".YAML vs JSON for saving human-readable R objects (TLDR: Use YAML)
https://coolbutuseless.github.io/2018/02/03/yaml-vs-json-for-saving-human-readable-r-objects-tldr-use-yaml/
Sat, 03 Feb 2018 08:00:00 +1000https://coolbutuseless.github.io/2018/02/03/yaml-vs-json-for-saving-human-readable-r-objects-tldr-use-yaml/Problem: serialization of R list objects to a human readable/editable file I often use R list objects for storing configuration information within shiny apps. These are used to define multiple configuration sets and are usually saved to file. I then want to be able to edit the objects on the filesystem with a text editor.
What’s a good file format for saving R list objects to file such that they’re easily editable?About
https://coolbutuseless.github.io/about/
Mon, 01 Jan 2018 08:00:00 +0000https://coolbutuseless.github.io/about/Mostly blogging about the R programming language. Other topics which may arise: birds, urban design, cycling.
Thanks to the blogdown package for making this blog possible using R
All code appearing on this blog is licensed under MIT unless otherwise specified. See LicenseLicense
https://coolbutuseless.github.io/license/
Mon, 01 Jan 2018 08:00:00 +0000https://coolbutuseless.github.io/license/All code appearing on this blog is licensed under MIT unless otherwise specified.
MIT License
Copyright (c) 2018,2019,2020 mikefc@coolbutuseless.com
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: