Skip to content

Commit

Permalink
Merge pull request #65 from SciViews/lessdependencies
Browse files Browse the repository at this point in the history
Dependency-less version
  • Loading branch information
stefano-meschiari authored Aug 16, 2024
2 parents 0efe78e + 393bccd commit 733d5d2
Show file tree
Hide file tree
Showing 14 changed files with 419 additions and 400 deletions.
10 changes: 4 additions & 6 deletions DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
Package: latex2exp
Type: Package
Title: Use LaTeX Expressions in Plots
Version: 0.9.7
Date: 2022-12-28
Version: 0.9.8
Date: 2024-07-05
Authors@R: person("Stefano", "Meschiari", email="[email protected]", role=c("aut", "cre"))
Description: Parses and converts LaTeX math formulas to R's plotmath
expressions, used to enter mathematical formulas and symbols to be rendered as
text, axis labels, etc. throughout R's plotting system.
License: MIT + file LICENSE
URL: https://www.stefanom.io/latex2exp/, https://github.com/stefano-meschiari/latex2exp
BugReports: https://github.com/stefano-meschiari/latex2exp/issues
Imports:
stringr,
magrittr
Encoding: UTF-8
Suggests:
tools,
testthat,
waldo,
knitr,
Expand All @@ -28,5 +26,5 @@ Suggests:
rlang,
dplyr
VignetteBuilder: knitr
RoxygenNote: 7.2.2
RoxygenNote: 7.2.3
Language: en-US
13 changes: 0 additions & 13 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,4 @@ importFrom(graphics,par)
importFrom(graphics,plot.new)
importFrom(graphics,plot.window)
importFrom(graphics,text)
importFrom(magrittr,"%>%")
importFrom(stringr,fixed)
importFrom(stringr,str_c)
importFrom(stringr,str_detect)
importFrom(stringr,str_length)
importFrom(stringr,str_match)
importFrom(stringr,str_match_all)
importFrom(stringr,str_replace)
importFrom(stringr,str_replace_all)
importFrom(stringr,str_split)
importFrom(stringr,str_starts)
importFrom(stringr,str_sub)
importFrom(stringr,str_trim)
importFrom(utils,vignette)
4 changes: 4 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# 0.9.8 (07/05/2024)

* The code is reworked to eliminate dependencies to stringr and magrittr.

# 0.9.7 (12/28/2022)
## Bug fixes
* In math mode, numbers that started with 0 would be displayed without it (e.g.
Expand Down
11 changes: 5 additions & 6 deletions R/demos.R
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#'
#' @param cex Multiplier for font size
#' @export
latex2exp_examples <- function(cex=1) {
latex2exp_examples <- function(cex = 1) {
oldpar <- par(no.readonly = TRUE)
on.exit(suppressWarnings(par(oldpar)))

Expand All @@ -31,9 +31,8 @@ latex2exp_examples <- function(cex=1) {
x <- 0
y <- seq(0.95, 0.05, length.out = length(examples))

text(
0.5, y, str_c("TeX(r\"(", examples, ")\")"), pos = 2, cex = 0.5 * cex, family = 'mono'
)
text(0.5, y, TeX(examples), pos = 4, cex=cex)
text(0.5, y, paste0("TeX(r\"(", examples, ")\")"), pos = 2, cex = 0.5 * cex,
family = 'mono')
text(0.5, y, TeX(examples), pos = 4, cex = cex)
return(invisible(TRUE))
}
}
208 changes: 102 additions & 106 deletions R/latex2exp.R
Original file line number Diff line number Diff line change
@@ -1,31 +1,20 @@
#' @importFrom magrittr %>%
#' @importFrom stringr str_c
#' @importFrom stringr str_detect
#' @importFrom stringr str_replace_all
#' @importFrom stringr str_replace
#' @importFrom stringr str_split
#' @importFrom stringr str_sub
#' @importFrom stringr str_match
#' @importFrom stringr str_trim
#' @importFrom stringr str_starts
#' @importFrom stringr str_match
#' @importFrom stringr str_match_all
#' @importFrom stringr fixed
#' @importFrom stringr str_length
NULL

#' Deprecated; use \code{\link{TeX}} instead.
#'
#' @param string A character vector containing LaTeX expressions. Note that any backslashes must be escaped (e.g. "$\\alpha").
#' @param output The returned object, one of "expression" (default, returns a plotmath expression ready for plotting), "character" (returns the expression as a string), and "ast" (returns the tree used to generate the expression).
#' @param string A character vector containing LaTeX expressions. Note that any
#' backslashes must be escaped (e.g. "$\\alpha").
#' @param output The returned object, one of "expression" (default, returns a
#' plotmath expression ready for plotting), "character" (returns the
#' expression as a string), and "ast" (returns the tree used to generate the
#' expression).
#'
#' @return Returns an expression (see the \code{output} parameter).
#' @export
latex2exp <-
function(string, output = c('expression', 'character', 'ast')) {
.Deprecated('TeX', 'latex2exp')
return(TeX(string, output=output))
}
latex2exp <- function(string, output = c('expression', 'character', 'ast')) {
.Deprecated('TeX', 'latex2exp')
return(TeX(string, output = output))
}

#' Converts LaTeX to a \code{\link{plotmath}} expression.
#'
Expand All @@ -44,117 +33,124 @@ latex2exp <-
#' "character" (returns the expression as a string),
#' and "ast" (returns the tree used to generate the expression).
#'
#' @return Returns a plotmath expression by default. The \code{output} parameter can
#' modify the type of the returned value.
#' @return Returns a plotmath expression by default. The \code{output} parameter
#' can modify the type of the returned value.
#'
#' If more than one string is specified in the \code{input} parameter, returns a list
#' of expressions.
#' If more than one string is specified in the \code{input} parameter, returns a
#' list of expressions.
#'
#' @section Adding new commands:
#' New LaTeX commands can be defined by supplying the \code{user_defined} parameter.
#' The \code{user_defined} parameter is a list that contains LaTeX commands
#' as names, and template strings as values. A LaTeX command that matches
#' one of the names is translated into the corresponding string and included in
#' the final plotmath expression. The file \code{symbols.R} in the source code
#' of this package contains one such table that can be used as a reference.
#' New LaTeX commands can be defined by supplying the \code{user_defined}
#' parameter. The \code{user_defined} parameter is a list that contains LaTeX
#' commands as names, and template strings as values. A LaTeX command that
#' matches one of the names is translated into the corresponding string and
#' included in the final plotmath expression. The file \code{symbols.R} in the
#' source code of this package contains one such table that can be used as a
#' reference.
#'
#' The template string can include one of the following special template
#' parameters:
#'
#' \itemize{
#' \item \code{$arg1, $arg2, ...} represent the first, second, ... brace argument.
#' E.g. for \code{\\frac{x}{y}}, \code{$arg1} is \code{x} and \code{$arg2} is \code{y}.
#' \item \code{$arg1, $arg2, ...} represent the first, second, ... brace
#' argument. E.g. for \code{\\frac{x}{y}}, \code{$arg1} is \code{x} and
#' \code{$arg2} is \code{y}.
#' \item \code{$opt} is an optional argument in square brackets. E.g. for
#' \code{\\sqrt[2]{x}}, \code{$opt} is \code{2}.
#' \item \code{$sub} and \code{$sup} are arguments in the exponent (\code{^}) or subscript (\code{_})
#' following the current expression. E.g. for \code{\\sum^{x}}, \code{$sup} is \code{x}.
#' \item \code{$LEFT} and \code{$RIGHT} are substituted the previous and following LaTeX expression
#' relative to the current token.
#' \item \code{$sub} and \code{$sup} are arguments in the exponent (\code{^}) or
#' subscript (\code{_}) following the current expression. E.g. for
#' \code{\\sum^{x}}, \code{$sup} is \code{x}.
#' \item \code{$LEFT} and \code{$RIGHT} are substituted the previous and
#' following LaTeX expression relative to the current token.
#' }
#' See the Examples section for an example of using the \code{user_defined} option.
#' See the Examples section for an example of using the \code{user_defined}
#' option.
#'
#' @examples
#' TeX("$\\alpha$") # plots the greek alpha character
#' TeX("The ratio of 1 and 2 is $\\frac{1}{2}$")
#'
#' a <- 1:100
#' plot(a, a^2, xlab=TeX("$\\alpha$"), ylab=TeX("$\\alpha^2$"))
#' plot(a, a^2, xlab = TeX("$\\alpha$"), ylab = TeX("$\\alpha^2$"))
#'
#' # create a \\variance command that takes a single argument
#' TeX("$\\variance{X} = 10$", user_defined=list("\\variance"="sigma[$arg1]^2"))
#' TeX("$\\variance{X} = 10$",
#' user_defined = list("\\variance" = "sigma[$arg1]^2"))
#' @export
TeX <-
function(input, bold=FALSE, italic=FALSE, user_defined=list(), output = c('expression', 'character', 'ast')) {
if (length(input) > 1) {
return(sapply(input, TeX, bold=bold, italic=italic, user_defined=user_defined, output = output))
}
stopifnot(is.character(input))
TeX <- function(input, bold = FALSE, italic = FALSE, user_defined = list(),
output = c('expression', 'character', 'ast')) {
if (length(input) > 1) {
return(sapply(input, TeX, bold = bold, italic = italic,
user_defined = user_defined, output = output))
}
stopifnot(is.character(input))

output <- match.arg(output)
parsed <- parse_latex(input)

output <- match.arg(output)
parsed <- parse_latex(input)
# Try all combinations of "hacks" in this grid, until one succeeds.
# As more hacks are introduced, the resulting expression will be less and
# less tidy, although it should still be visually equivalent to the
# desired output given the latex string.
grid <- expand.grid(hack_parentheses = c(FALSE, TRUE))
successful <- FALSE
for (row in seq_len(nrow(grid))) {
# Make a deep clone of the LaTeX token tree
parsed_clone <- clone_token(parsed)
rendered <- render_latex(parsed_clone, user_defined,
hack_parentheses = grid$hack_parentheses[[row]])

# Try all combinations of "hacks" in this grid, until one succeeds.
# As more hacks are introduced, the resulting expression will be less and
# less tidy, although it should still be visually equivalent to the
# desired output given the latex string.
grid <- expand.grid(hack_parentheses = c(FALSE, TRUE))
successful <- FALSE
for (row in seq_len(nrow(grid))) {
# Make a deep clone of the LaTeX token tree
parsed_clone <- clone_token(parsed)
rendered <- render_latex(parsed_clone, user_defined,
hack_parentheses=grid$hack_parentheses[[row]])

if (bold && italic) {
rendered <- str_c("bolditalic(", rendered, ")")
} else if (bold) {
rendered <- str_c("bold(", rendered, ")")
} else if (italic) {
rendered <- str_c("italic(", rendered, ")")
}

cat_trace("Rendered as ", rendered, " with parameters ", toString(grid[row,]))

if (output == "ast") {
return(parsed)
}

rendered_expression <- try({
str2expression(rendered)
}, silent=TRUE)

if (inherits(rendered_expression, "try-error")) {
error <- rendered_expression
cat_trace("Failed, trying next combination of hacks, error:", error,
" parsed as: ", rendered)

if (row == 1) {
original_error <- error
}
} else {
successful <- TRUE
break
}
if (bold && italic) {
rendered <- paste0("bolditalic(", rendered, ")")
} else if (bold) {
rendered <- paste0("bold(", rendered, ")")
} else if (italic) {
rendered <- paste0("italic(", rendered, ")")
}

if (!successful) {
stop("Error while converting LaTeX into valid plotmath.\n",
"Original string: ", input, "\n",
"Parsed expression: ", rendered, "\n",
original_error)
}
if (output == "character") {
return(rendered)
}
cat_trace("Rendered as ", rendered, " with parameters ",
toString(grid[row, ]))

# if the rendered expression is empty, return expression('') instead.
if (length(rendered_expression) == 0) {
rendered_expression <- expression('')
if (output == "ast") {
return(parsed)
}

class(rendered_expression) <- c("latexexpression", "expression")
attr(rendered_expression, "latex") <- input
attr(rendered_expression, "plotmath") <- rendered
rendered_expression <- try({
str2expression(rendered)
}, silent = TRUE)

rendered_expression
if (inherits(rendered_expression, "try-error")) {
error <- rendered_expression
cat_trace("Failed, trying next combination of hacks, error:", error,
" parsed as: ", rendered)

if (row == 1) {
original_error <- error
}
} else {
successful <- TRUE
break
}
}

if (!successful) {
stop("Error while converting LaTeX into valid plotmath.\n",
"Original string: ", input, "\n",
"Parsed expression: ", rendered, "\n",
original_error)
}
if (output == "character") {
return(rendered)
}

# if the rendered expression is empty, return expression('') instead.
if (length(rendered_expression) == 0) {
rendered_expression <- expression('')
}

class(rendered_expression) <- c("latexexpression", "expression")
attr(rendered_expression, "latex") <- input
attr(rendered_expression, "plotmath") <- rendered

rendered_expression
}
Loading

0 comments on commit 733d5d2

Please sign in to comment.