I have a Mathematica expression generated by another program, which I would like to open in a notebook, properly formatted. For instance, the other program generates this:<
Unless you create the BoxData
expressions explicitly there is no way to format your expression without actually invoking at least the Mathematica FrontEnd.
The closest I can think of is that you add the following:
SelectionMove[EvaluationNotebook[], Next, EvaluationCell];
FrontEndExecute[{FrontEndToken[FrontEnd`InputNotebook[],
"SelectionConvert", "StandardForm"]}];
Plot[{Exp[x], Interpolation[Table[{k/5, Exp[(1/5)*(k - 1/2)]}, {k, 0, 5}],
InterpolationOrder -> 0][x]}, {x, 0, 1},
Filling -> {1 -> {{2}, {Yellow, Orange}}},
PlotLabel -> Style["Formatting", Blue, FontFamily -> "Courier"],
Evaluated -> True]
SelectionMove[EvaluationNotebook[], After, GeneratedCell];
which automatically formats the Plot
command when the cell is evaluated.
(BTW: You probably should either add Evaluate
in front of the list or add the (not-so-well documented) Evaluate->True
option.
Here is the solution I adopted. Thanks for all the help.
The main step of the solution is to format the command via the kernel:-
FullForm[ToBoxes[
Defer[Plot[{Exp[x],
Interpolation[Table[{k/5, Exp[(k - 1/2)/5]}, {k, 0, 5}],
InterpolationOrder -> 0][x]}, {x, 0, 1},
Filling -> {1 -> {{2}, {Yellow, Orange}}},
PlotLabel ->
Style["Formatting", Blue, FontFamily -> "Courier"]]]]]
Then the formatted data is encapsulated to create a notebook:-
Notebook[{Cell[BoxData[
... ( inserted box-formatted output ) ...
], "Input"]
},
WindowSize->{615, 750},
WindowMargins->{{328, Automatic}, {Automatic, 76}},
StyleDefinitions->"Default.nb"
]
This is written to a file, suffixed ".nb". All fine and dandy.
This approach works well for multi-statement blocks of code, but some additional processing was included to format a single function call of the form Function[expression, options] to add a line-break before each option. Here is the C# code used to produce both types of output:-
public static class MathematicaHelpers
{
public static string CreateNotebook(string mathCommand, string fileLocation, MathKernel kernel, bool addNewLines)
{
if (addNewLines) {
mathCommand = string.Format("{0}{1}{2}", "Module[{boxoutput,b2},boxoutput=FullForm[ToBoxes[Defer[", mathCommand, "]]];b2=boxoutput[[1,1,3,1]];boxoutput[[1,1,3,1]]=Join[Flatten[Riffle[Partition[b2,2],\"\\[IndentingNewLine]\"],1],{\"\\[IndentingNewLine]\",Last[b2]}];boxoutput]");
} else {
mathCommand = string.Format("{0}{1}{2}", "FullForm[ToBoxes[Defer[", mathCommand, "]]]");
}
fileLocation = Path.ChangeExtension(fileLocation, ".nb");
mathCommand = ComputeMathCommand(mathCommand, kernel);
mathCommand = string.Format("{0}{1}{2}", "Notebook[{Cell[BoxData[", mathCommand,
"], \"Input\"]},WindowSize->{615, 750}, WindowMargins->{{328, Automatic}, {Automatic, 76}},StyleDefinitions->\"Default.nb\"]");
File.WriteAllText(fileLocation, mathCommand);
return fileLocation;
}
private static string ComputeMathCommand(string command, MathKernel kernel)
{
kernel.Compute(command);
return kernel.Result.ToString();
}
}
How about this:
Export["C:\\Temp\\formatTest1.nb",
ToExpression[Import["C:\\Temp\\formatTest.nb", "Text"], InputForm, MakeBoxes]]
I tested it and it seems to work (importing from the plain file, exporting to the one you will then open). This does create explicit boxes, but with a very little effort on the user's side. I did not test, but you should be able to run this code in the script mode, from the command line.
EDIT
To test from within Mathematica, you can use e.g.
Export["C:\\Temp\\formatTest.nb",
ToString@HoldForm@FullForm@
Plot[{Exp[x],Interpolation[Table[{k/5, Exp[(k - 1/2)/5]}, {k, 0, 5}],
InterpolationOrder -> 0][x]}, {x, 0, 1},
Filling -> {1 -> {{2}, {Yellow, Orange}}},
PlotLabel -> Style["Formatting", Blue, FontFamily -> "Courier"]],
"Text"]
before running the code above.
You can use the following wrapping:
nb = CreateWindow[
DocumentNotebook[{
Plot[{Exp[x],
Interpolation[Table[{k/5, Exp[(k - 1/2)/5]}, {k, 0, 5}],
InterpolationOrder -> 0][x]}, {x, 0, 1},
Filling -> {1 -> {{2}, {Yellow, Orange}}},
PlotLabel ->
Style["Formatting", Blue, FontFamily -> "Courier"]]
}]]
then commands NotebookSave and NotebookClose can be used to save and close the thing ;)