Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Align symbolic and numeric matrices #66

Open
friendly opened this issue Oct 12, 2024 · 10 comments
Open

Align symbolic and numeric matrices #66

friendly opened this issue Oct 12, 2024 · 10 comments

Comments

@friendly
Copy link
Owner

friendly commented Oct 12, 2024

Starting to use latexMatrix() and friends in my book. I ran into a little problem with aligning two equations, one symbolic and the other numeric. My test file is dev/eigen-ex.R

Goal: show the eigen decomposition of a cov matrix, with a numeric example, ie,
S = V Lambda V^T

data(workers, package = "matlib")   
head(workers)

vars <- c("Experience", "Income")
# covariance matrix & mean
mu <- colMeans(workers[, vars]) |> print()
S <- cov(workers[, vars]) |> print()

# eigenvalues and eigenvectors
S.eig <- eigen(S)
Lambda <- S.eig$values |> print()
V <- S.eig$vectors |> print()

where,

S <- cov(workers[, vars]) |> print()
           Experience   Income
Experience   135.8333 151.9444
Income       151.9444 233.6111

I tried using \phantom{} to give the symbolic part look like "S = V Lambda V^T"
(fiddling with the size of the phantom)

# align V Lambda V' using \phantom{}
options(digits = 4)
rownames(S) <- colnames(S) <- c("Exp", "Inc")
spacer <- "\\phantom{00000000000000}"
Eqn("\\mathbf{S} & = \\mathbf{V}", spacer,
    "\\mathbf{\\Lambda}", spacer,  
    "\\mathbf{V}^\\top", Eqn_newline(),
    latexMatrix(S), "& =", 
    latexMatrix(V), "  ", diag(Lambda), "  ", latexMatrix(V, transpose=TRUE),
    align = TRUE)

which gives:

image

Note too bad, but very fiddly. Is there a better LaTeX way? I tried other alignment (&) tabs, but there's
something I don't understand.

# What's wrong here?
spacer <- " & "
Eqn("\\mathbf{S} & = \\mathbf{V}", spacer,
    "\\mathbf{\\Lambda}", spacer,  
    "\\mathbf{V}^\\top", Eqn_newline(),
    latexMatrix(S), "& =", 
    latexMatrix(V), "  ", diag(Lambda), "  ", latexMatrix(V, transpose=TRUE),
    align = TRUE)

Gives:

image

I think this is more of a LaTeX issue, than a problem in the package.

I looked at Eqn_hspace(), but couldn't figure out how to make it work in this context, because the function and docs related to alignment around =.

@friendly
Copy link
Owner Author

Some related notes on this:

  • I was surprised that row/col labels for S now appear by default. They get this from cov(). I'm not sure I want bordered matrices all the time, and didn't see where to turn this off. This is different, I think, than how this is controlled by rownames, colnames.
  • Abbreviating the names helped, but I was surprised that they are in math font rather than \text{}
  • One idea for improving bordered matrices alignment might be to use \small{} or other reduced size

Also, the default for digits = getOption("digits") - 2 was too large, so I set that option globally,
rather than in each call to latexMatrix()

@philchalmers
Copy link
Collaborator

Hi Michael,

From my experience aligning symbols above matrices is awkward, at least if you want them centered. If you're okay with right aligning adding a few more '&' can work.

Eqn("\\mathbf{S} & = & \\mathbf{V} & &\\mathbf{\\Lambda} & &\\mathbf{V}^\\top", Eqn_newline(),
    latexMatrix(S), "& = & ", latexMatrix(V), "& &", diag(Lambda), "& &", latexMatrix(V, transpose=TRUE),
    align = TRUE)

To get the symbols middle aligned you'd need to add '&' within the matrices themselves. I can take a stab at this later (right now family responsibilities are calling....).

@john-d-fox
Copy link
Collaborator

It's been awhile since I thought about this.
Your points:

  • That was the design. You can remove the row/column names if you don't want to see them, or add a new option or argument to control printing row/column labels.
  • You wanted, e.g., to be able to label columns by parameters such as \beta_0 which implies math mode. To be able to use both text and math implies a more complex design, or try using row/column names like "\\mathrm{desired text}" probably created by a new convert-to-text-mode function.
  • the print() method works very hard, if imperfectly, to try to align the column names with the contents of the matrix; changing the size of the column-names font would wreak havoc with the alignment.

I think that to get everything you want in an automatic way would require a complete redesign of the how the row/column names are handled. OTOH patching the current approach should be feasible but more complicated to use.

@friendly
Copy link
Owner Author

OK, I wasn't proposing anything in the way of re-design, just making some observations. I can try to work around-- e.g., by explicitly using \\text{} when I re-define the colnames from cov()

The main point had to do with alignment.

@john-d-fox
Copy link
Collaborator

I was able to quickly implement much of what you want at the expense of additional complexity. For example,

> S <- matrix(1:9, 3, 3)
> rownames(S) <- colnames(S) <- letters[1:3]
> S
  a b c
a 1 4 7
b 2 5 8
c 3 6 9

> latexMatrix(S)
\begin{matrix}
  &  \begin{matrix} \phantom{i} a & b & c
  \end{matrix} \\ 
 \begin{matrix}  
   a\\ 
   b\\ 
   c\\ 
\end{matrix}  & 
\begin{pmatrix}  
1 & 4 & 7 \\ 
2 & 5 & 8 \\ 
3 & 6 & 9 \\ 
\end{pmatrix}
\\ 
\end{matrix} 

> print(latexMatrix(S), display.labels=FALSE)
\begin{pmatrix} 
1 & 4 & 7 \\ 
2 & 5 & 8 \\ 
3 & 6 & 9 \\ 
\end{pmatrix}

> print(latexMatrix(S), text.labels=c(row=TRUE, column=TRUE))
\begin{matrix}
  &  \begin{matrix} \phantom{i} \mathrm{a} & \mathrm{b} & \mathrm{c}
  \end{matrix} \\ 
 \begin{matrix}  
   \mathrm{a}\\ 
   \mathrm{b}\\ 
   \mathrm{c}\\ 
\end{matrix}  & 
\begin{pmatrix}  
1 & 4 & 7 \\ 
2 & 5 & 8 \\ 
3 & 6 & 9 \\ 
\end{pmatrix}
\\ 
\end{matrix} 

There are several new options that control default behaviour; see the code and help file for details.

I didn't implement changing the size of the row/column labels text for the reason I mentioned previously.

The changes are in the GitHub repo for the package. My testing was cursory, so the code should be exercised more.

@john-d-fox
Copy link
Collaborator

If you want horizontal alignment to work when mixing matrices some of which have column labels and some not, I think you'll have to define empty column labels (e.g., "" or " ") for those without. I think it would be very hard to automate that in Eqn().

I don't really understand why vertical alignment is so difficult. I'd be tempted simply to align on = and let the RHSs be left-justified.

@john-d-fox
Copy link
Collaborator

I screwed around a bit with the size of the row/column labels, and the effect wasn't as extreme as I expected, so I added a mathtext.size argument to print.latexMatrix(), controlled by a corresponding option, and I changed the default for mathtext from mathrm to text to support font-size changes. For example,

> print(latexMatrix(S), text.labels=c(row=TRUE, column=TRUE),
+       mathtext.size="footnotesize")
\begin{matrix}
  &  \begin{matrix} \phantom{i} \text{\footnotesize{a}} & \text{\footnotesize{b}} & \text{\footnotesize{c}}
  \end{matrix} \\ 
 \begin{matrix}  
   \text{\footnotesize{a}}\\ 
   \text{\footnotesize{b}}\\ 
   \text{\footnotesize{c}}\\ 
\end{matrix}  & 
\begin{pmatrix}  
1 & 4 & 7 \\ 
2 & 5 & 8 \\ 
3 & 6 & 9 \\ 
\end{pmatrix}
\\ 
\end{matrix}

So, more flexibility at the expense of a bit more complexity.

@friendly
Copy link
Owner Author

Hi John

Your solution looks nice, but it turns out \text{\footnotesize{}} isn't supported by MathJax. I found an online latex editor that allows different rendering engines, https://arachnoid.com/latex/

image

vs. Codecogs, whatever that is

image

So, I'm not sure what to do about this commit, 30992cf

Your example works fine with just \text{}. It is the \footnotesize` that causes the problem, so I'd say let's dispense with this.

@john-d-fox
Copy link
Collaborator

Why dispense with it rather than just not using it if the target is an html document to be processed by mathjax? BTW, the text size commands don't work in math mode, so not with, e.g., \mathrm{}.

Another thought: There are now too many (7) options used by print.latexMatrix(). I'd like to consolidate them in a single "print.latexMatrix" option. Any objections?

@john-d-fox
Copy link
Collaborator

I went ahead and consolidated the "print.latexMatrix" options.

Feel free to remove the mathtext.size argument if you wish, though as I said I don't see the point now that it's implemented.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants