Disclaimer: I don't have matlab so I used python for testing instead (see end of post). This really is only a proof of concept.
as @cfr pointed out: from a LaTeX point of view, this problem is rather simple:
First you need a script that executes the matlab code and prints the variables to a text file in a format LaTeX understands.
Then you import the text file and use the variables.
Lets get to the LaTeX side of it first. We therefore assume we have a matlab script save_workspace_vars.m
which executes any given matlab file, e.g. example.m
, and stores all its workspace variables and values as LaTeX macros into the file example_vars.txt
like so: \newcommand{\varname}{varvalue}
. But since we do not know the names of the variables and there could be a lot of them, there could easily be name clashes if we run multiple matlab scripts from one LaTeX file. So we better use \newcommand{\prefixvarname}{varvalue}
where prefix
could be any string, especially the name of the matlab script, making the macro name unique.
So now we have a matlab script that generates a text file containing neat macros with unique names expanding to all our variables values, how do we use it?
- We need a macro to execute the script from inside LaTeX with
\immediate\write18
. This requires us to compile the .tex
file with --shell-escape
like so: pdflatex --shell-escape mydocument.tex
- We need to import the textfile with
\import
- We need a macro that allows us to print the variables in a convenient way, e.g.
\matlabvariable{prefix}{varname}
1 and 2 can be dealt with in a single command that may be used in the preamble:
\newcommand{\getvars}[1]{
\immediate\write18{matlab -batch "save_workspace_vars('#1')"}%
\input{#1_vars.txt}
}
3 is now even simpler
\newcommand{\matlabvariable}[2]{\csname #1#2\endcsname}
Assume we have the variables h = 42
and pi = 3.1415
inside our matlab workspace in example.m
(and example.m
and save_workspace_vars.m
are inside our working directory). Our whole document would simply look like this:
\documentclass{article}
\newcommand{\getvars}[1]{
\immediate\write18{matlab -batch "save_workspace_vars('#1')"}%
\input{#1_vars.txt}
}
\newcommand{\matlabvariable}[2]{\csname #1#2\endcsname}
\getvars{example}
\begin{document}
The value of h is: \matlabvariable{example}{h}
The value of pi is: \matlabvariable{example}{pi}
\end{document}
Output:
Things to consider:
- The variable names inside the matlab script have to be possible LaTeX macro names, e.g. they should not contain numbers or dots et. al. As @cfr pointed out: due to
\csname
and \endcsname
some of the restrictions for normal LaTeX macro names are lifted but I can't tell you which ones and so it might be better to stick to names that you are shure to work.
- same applies to the name of the matlab script.
- the matlab scripts are assumed to be in the same directory as the tex file
Now comes the hard part: the matlab script for saving the variables.
I dont have matlab and don't know much about it. So I tested all the above code with python instead of matlab. In order to give you a hint in the right direction I asked an AI to generate a corresponding matlab script and chatgpt gave me this:
function save_workspace_vars(script_name)
% Load the workspace of the specified MATLAB file
% Assume the script_name is passed without the '.m' extension
try
run(script_name); % Executes the specified MATLAB script
catch ME
error('Error executing %s.m: %s', script_name, ME.message);
end
% Get all variables from the workspace
vars = whos;
% Prepare the output file
filename = strcat(script_name, '_vars.txt');
fid = fopen(filename, 'w');
% Loop through each variable in the workspace
for i = 1:length(vars)
var_name = vars(i).name;
var_value = eval(var_name); % Get the value of the variable
% Generate the LaTeX command for the variable based on its type
if isnumeric(var_value) && isscalar(var_value)
% Handle integer or double scalar values
fprintf(fid, '\\newcommand{\\%s%s}{%g}\n', script_name, var_name, var_value);
elseif ischar(var_value)
% Handle string (character array) values
fprintf(fid, '\\newcommand{\\%s%s}{%s}\n', script_name, var_name, var_value);
elseif isstring(var_value) && isscalar(var_value)
% Handle scalar string values
fprintf(fid, '\\newcommand{\\%s%s}{%s}\n', script_name, var_name, var_value);
else
% Unsupported data type, skip this variable
fprintf(fid, '\\newcommand{\\%s%s}{Unsupported data type}\n', script_name, var_name);
end
end
% Close the file
fclose(fid);
disp(['Variables saved to ', filename]);
end
Looks ok to me. You iterate over all variables and save them according to their type. This even allows for sophisticated formatting, where you could generate multiple commands for the same variable, say if you have a vector or a matrix or if the value of a variable is infinite..
But of course: I have no idea if this matlab script actually works. But I hope it will help you find way to do something along these lines in matlab.
Edit 2024-10-02 (4 days later)
For convenience it might be better not to assume, that all the files are in the same directory. Then we have three directories of interest:
- The current working directory (
workDir
)
- The directory where
save_workspace_vars.m
is located (exportScriptDir
)
- The directory where the matlab scripts are (
scriptDir
)
Let's assume we're ok with saving the txt
-file containing our new macros in scriptDir
and we want exportScriptDir
to be at some freely chosen location. Then we do as follows:
\documentclass{article}
\usepackage{etoolbox}
\newcommand{\getvars}[2]{
% #1 is path/to/scriptDir/
% #2 is nameOfMatlabScript without '.m'
% \exportScript stores the location of exportScriptDir. \providecommand needed if \getvars is used more then once
\providecommand{\exportScript}{/path/to/exportScriptDir/save_workspace_vars.m}
% I am assuming python here, because again: don't know much about matlab
\immediate\write18{python3 \exportScript \expandonce{ #1 #2}}
\input{#1#2_vars.txt}
}
\newcommand{\matlabvariable}[2]{\csname #1#2\endcsname}
\getvars{path/to/scriptDir}{example}
\begin{document}
The value of h is: \matlabvariable{example}{h}
The value of pi is: \matlabvariable{example}{pi}
\end{document}
You then need a matlab script save_workspace_vars.m
to which you can pass two arguments. The first beeing the full path of scriptDir
and the second beeing the name of the script without .m
.
Let me know, if you are interested in changing all this to save the _vars.txt
to an arbitrary location (for example the workDir
).
Of course I can generate another save_workspace_vars.m
in matlab for accepting a path too. But I guess you can either write it yourself or better ask someone who knows matlab better.
As I used python for testing, I should share my approach in python as well. I used the following python script save_vars.py
to fake the creation of variables:
import sys
# Ensure the correct number of arguments is provided
if len(sys.argv) != 2:
print("Usage: save_vars.py <script_name>")
sys.exit(1)
# Extract script name (without extension)
script_name = sys.argv[1]
# Simulate some variables for the given script name
variables = {
"h": 42,
"pi": 3.1415
}
# Open a file to save the variables in LaTeX command format
filename = f"{script_name}_vars.txt"
with open(filename, "w") as f:
for var_name, value in variables.items():
if isinstance(value, (int, float)):
value_str = str(value)
elif isinstance(value, str):
value_str = value
else:
value_str = "Unsupported data type"
# Write in the format: \newcommand{\prefixvarname}{var_value}
f.write(f"\\newcommand{{\\{script_name}{var_name}}}{{{value_str}}}\n")
print(f"Variables saved to {filename}")
To then call it, I used \immediate\write18{python save_vars.py #1}
example.m
you can run whatever programme you like onexample.m
. you can either collect the results directly or output them to a file you then read or whatever works for the external programme. what's the particular problem with matlab? and what about it needs lua? of course you need shell escape to do it, but I assume you know that already.