README.md

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)) 

plot of chunk unnamed-chunk-3

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)

plot of chunk unnamed-chunk-6

Example #2 - Sierpinski Fractal

s <- function(x) { sub_and_super(x, x, x) }

plot(s(s(s(mu))), cex=3)

plot of chunk unnamed-chunk-7

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)

plot of chunk unnamed-chunk-8

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)

plot of chunk unnamed-chunk-9

plot()

plot() has been extended to work with character and expression objects.

plot("alpha * beta", cex=5)

plot of chunk unnamed-chunk-10

plot(bquote(alpha ^ 2), cex=5)

plot of chunk unnamed-chunk-10

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}})}}}}})})

And then you can use that in ggplot geom_text (for example):

withr::with_package('ggplot2', {
  ggplot(mtcars) +
    geom_point(aes(mpg, wt), alpha=0.3) + 
    geom_text(x=20, y=3, label=pstring, parse = TRUE) + 
    theme_bw() 
})

plot of chunk unnamed-chunk-12

Full list of plotmath functions and infix operators

|plotmath |funcmath |infix | |:------------------------|:---------------------------------|:------------------| |x + y |plus(x, y) |%+% | |x - y |minus(x, y) |%-% | |x * y |juxtapose(x, y) |%% | |x / y |forwardslash(x, y) |%/% | |x %+-% y |plusminus(x, y) |%+-% | |x %/% y |divide(x, y) |%//% | |x %% y |times(x, y) |%x% | |x %.% y |cdot(x, y) |%.% | |-x |neg(x) | | |+x |pos(x) | | |x[y] |subscript(x, y) |%subscript%, %% | |x ^ y |superscript(x, y) |%superscript%, %^% | |x[l]^u |sub_and_super(x, l, u) | | |sqrt(x, y) |sqrt(x, y=NULL) | | |x == y |eq(x, y) |%eq% | |x != y |neq(x, y) |%neq% | |x < y |lt(x, y) |%<<% | |x <= y |le(x, y) |%<=% | |x > y |gt(x, y) |%>>% | |x >= y |ge(x, y) |%>=% | |x %~~% y |approximate(x, y) |%~~% | |x %=~% y |congruent(x, y) |%=~% | |x %==% y |defined(x, y) |%==% | |x %prop% y |proportional(x, y) |%prop% | |x %~% y |distributed(x, y) |%~% | |!x |not(x) | | |plain (x) |plain(x) | | |bold (x) |bold(x) | | |italic (x) |italic(x) | | |bolditalic(x) |bolditalic(x) | | |bolditalic(x) |underline(x) | | |symbol (x) |symbol(x) | | |x %subset% y |subset(x, y) |%subset% | |x %subseteq% y |subseteq(x, y) |%subseteq% | |x %notsubset% y |notsubset(x, y) |%notsubset% | |x %supset% y |supset(x, y) |%supset% | |x %supseteq% y |supseteq(x, y) |%supseteq% | |x %in% y |in_(x, y) |%in_% | |x %notin% y |notin(x, y) |%notin% | |hat (x) |hat(x) | | |tilde (x) |tilde(x) | | |ring (x) |ring(x) | | |bar (x) |bar(x) | | |widehat (x) |widehat(x) | | |widetilde(x) |widetilde(x) | | |x %=>% y |double_arrow(x, y) |%<->% | |x %->% y |right_arrow(x, y) |%->% | |x %<-% y |left_arrow(x, y) |%<-% | |x %up% y |up_arrow(x, y) |%up% | |x %down% y |down_arrow(x, y) |%down% | |x %<=>% y |dbldbl(x, y) |%<=>% | |x %=>% y |dblright(x, y) |%=>>% | |x %<=% y |dblleft(x, y) |%<<=% | |x %dblup% y |dblup(x, y) |%dblup% | |x %dbldown% y |dbldown(x, y) |%dbldown% | |displaystyle(x) |displaystyle(x) | | |textstyle(x) |textstyle(x) | | |scriptstyle(x) |scriptstyle(x) | | |scriptscriptstyle(x) |scriptscriptstyle(x) | | |phantom(x) |phantom(x=NULL) | | |frac(x, y) |frac(x, y) |%frac% | |over(x, y) |over(x, y) |%over% | |atop(x, y) |atop(x, y) |%atop% | |x ~ y |space(x, y) |%space% | |x ~~ y |space2(x, y) |%space2% | |x ~~~ y |space3(x, y) |%space3% | |x ~~~~ y |space4(x, y) |%space4% | |sum (x, from, to) |sum_(x, from=NULL, to=NULL) | | |prod (x, from, to) |prod_(x, from=NULL, to=NULL) | | |integral (x, from, to) |integral(x, from=NULL, to=NULL) | | |union (x, from, to) |union_(x, from=NULL, to=NULL) | | |intersect(x, from, to) |intersect_(x, from=NULL, to=NULL) | | |lim (x, from, to) |lim(x, from=NULL, to=NULL) | | |min (x, from, to) |min_(x, from=NULL, to=NULL) | | |max (x, from, to) |max_(x, from=NULL, to=NULL) | | |inf(x) |inf(x) | | |sup(x) |sup(x) | | |group(lceil , x, rceil ) |ceiling_(x) | | |group(lfloor, x, rfloor) |floor_(x) | | |list(...) |list_(...) | | |paste(...) |paste_(...) | | |bgroup(x) |B(x), bgroup(x) | | |group(x) |G(x), group(x) | | |(x) |b(x) | |

Issues



coolbutuseless/funcmath documentation built on May 28, 2019, 2:47 p.m.