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.”

funcmath is a set of inconvenience functions to expand the compact plotmath syntax into a set of functions.

For example, instead of a nice compact plotmath expression such as:

m <- bquote(frac(alpha/beta, (1 + 2)))

… why not use defined symbols in funcmath (such as alpha) and infix functions like %/%?

m <- frac(alpha %/% beta, b(1 %+% 2)) 

Installation

devtools::install_github('coolbutuseless/funcmath')

Actual rationale

This work arose out of my attempts at creating fractals with plotmath expressions, and was not really meant as a way of creating actual math expressions.

Example #1

A plotmath expression created using bquote():

# http://lukemiller.org/index.php/2017/05/r-plotmath-functions-combined-with-variable-values/
mymean  <- 1.2345678
mySE    <- 0.55555
mylabel <- bquote(Delta*italic(T)[max]~.(format(mymean,digits=3))*''%+-%''*
                .(format(mySE,digits=2))*degree*C)
# plot(mylabel, cex=2)

The same plotmath expression created via funcmath:

Delta %*% 
  italic('T') %_% 'max' %space% format(mymean,digits=3) %+-% 
  (format(mySE,digits=2) %*% degree) %*% 'C' %>% 
  plot(cex=2)

Example #2 - Sierpinski Fractal

s <- function(x) { x %_% x %^% x }

plot(s(s(s(mu))))

Example #3 - Beta distribution

An issue with the normal way of building plotmaths expressions is that it is usually all done in one statement, which makes debugging complex math problematic. e.g. beta distribution

# https://blog.snap.uaf.edu/2013/03/25/mathematical-notation-in-r-plots/
expr.beta <- expression(italic(paste(displaystyle(f(x)~"="~frac(Gamma(alpha+beta),Gamma(alpha)*Gamma(beta))*x^{alpha-1}*(1-x)^{beta-1})
                    ~~~~displaystyle(list(paste(0<=x) <=1, paste(0<alpha) <infinity, paste(0<beta) <infinity))
                    )))

plot(expr.beta, cex=1.25)

By exploding plotmath into a set of functions, funcmath allows you to compose individual parts of an math expression and then combine them later. Individual parts can be tested separately and finally merged into the total required expression.

The result is more verbose, uglier and requires learning a whole new set of functions - this is called a win-win-win situation!

lhs          <- 'f' %*% b('x')
numerator    <- Gamma %*% b(alpha %+% beta)
denominator  <- (Gamma %*% b(alpha)) %*% (Gamma %*% b(beta))
right        <- 'x' %^% (alpha %-% 1) %*% b(1 %-% 'x') %^% (beta %-% 1)
limitx       <- 0 %<=%  'x'  %<=% 1
limitalpha   <- 0 %<<% alpha %<<% infinity
limitbeta    <- 0 %<<% beta  %<<% infinity

limits       <- list_(limitx, limitalpha, limitbeta)

total        <- lhs %eq% (numerator %frac% denominator) %*% right %space4% limits 

styled_total <- italic(displaystyle(total))


plot(styled_total, cex=1.25)

Turn the expression back into a parseable string

It is possible to turn the created plotmath back into a parseable character string.

pstring <- as_parseable_string(styled_total) 
cat(pstring)
italic({displaystyle({{{{{f}*{({x})}}=={frac({{Gamma}*{({{alpha}+{beta}})}},{{{Gamma}*{({alpha})}}*{{Gamma}*{({beta})}}})}}*{{{{x}^{{alpha}-{1}}}*{({{1}-{x}})}}^{{beta}-{1}}}}~{~{~{~{list({list({{{0}<={x}}<={1}},{{{0}<{alpha}}<{infinity}})},{{{0}<{beta}}<{infinity}})}}}}})})

Issues

  • There are a lot of namespace clashes e.g. list, paste, %*% etc.
  • Some names have an appended underscore to avoid clashing with a builtin/common function i.e. list_ instead of list.