The Front End
The front end is what you’re reading this in right now. It’s the collection of cells and notebooks and palettes and windows that you use to program, do your homework, write your resume, etc.
This is separate from the back end, also known as the kernel. That is where all your definitions and variables live. That’s where the your code actually runs.
The two communicate, but it’s important to understand that they are separate entities altogether
The Front End
The front end can be accessed via the symbol $FrontEnd
. This is the most global way to set options, change formatting, etc. For example, we can get the current default window size:
WindowSize/.Options[$FrontEnd,WindowSize]
(*Out:*)
{808,755}
We can also change this, but often the better thing to do is just to change the value on the symbol $FrontEndSession
which only applies the changes for the current session. $FrontEnd
keeps track of any changes applied and caches them permanently.
SetOptions[$FrontEndSession,WindowSize{100,100}]
This will change how big any windows we make appear, although it will not change the size of windows made with File ▸ New
or +** ****N**
. We can test this out using CreateDocument
though:
CreateDocument[]
We can also remove this:
SetOptions[$FrontEndSession,WindowSizeInherited]
Since $FrontEndSession
inherits from $FrontEnd
this reverts the change
Notebooks
A notebook is any window Mathematica creates. We can find all of the notebooks:
Notebooks[]
Or notebooks matching a name:
Notebooks["Mathematica For Chemists"]
A notebook is represented by a NotebookObject
. A NotebookObject
only exists for a given front end session. We can see why if we look at its InputForm
:
CreateDocument[]//InputForm
This is a symbolic form that represents an object communicating with the front end specified by the FrontEndObject
( LinkObject
refers to a link to a kernel process—something beyond the scope of what we’re working with here). Its ID is the last argument. Every time we create a new notebook the ID increments, so that within a given front end session no two notebooks will ever have the same ID.
Mathematica has a special notebook that always exists:
First@Notebooks@"Messages"
Mathematica will dump all messages generated without a notebook to this notebook. Generally this means dynamically generated messages—that is, messages generated by Dynamic
or other front-end events.
In a given evaluation, Mathematica keeps track of the notebook that started it. This can be obtained as follows:
EvaluationNotebook[]
Note that this applies even in the case of Dynamic
evaluations:
Dynamic@EvaluationNotebook[]//
CreateDocument[#,
WindowSize->Small,
WindowTitle->"Different notebook"]&;
Dynamic@EvaluationNotebook[]
In most cases this is the most useful notebook to have, but there are a number of others that may be of interest.
This will give the notebook that currently has keyboard focus. This is very useful when making palettes.
InputNotebook[]
If the current evaluation was started by a button, this gives the notebook that button was in. Again, useful for palettes and similar functionality.
ButtonNotebook[]
We can get and set options on notebooks just like the front end:
SetOptions[CreateDocument[],BackgroundRandomColor[]]
We can also write data to a notebook:
nb=CreateDocument[];
NotebookWrite[nb,"some_string"]
We’ll go more into detail of what exactly can be written and where when discussing Cells
and Boxes
.
One final thing: although a displayed notebook is referenced by a NotebookObject
, it is stored as an expression with the head Notebook
and for a given NotebookObject
there is a way to get this expression:
NotebookGet@EvaluationNotebook[]
This pulls the entire Notebook
expression for the current notebook.
Cells
As we just saw, at the symbolic level, a notebook is a list of Cell
or CellGroupData
expressions plus some options. In practice, though, this turns into a column of cells. We can get this list of cells by doing the following:
Cells@EvaluationNotebook[]
In the case of this notebook, this is a very large list of cells. Let’s just look at the form of the first of these:
First@Cells@EvaluationNotebook[]//InputForm
(*Out:*)
CellObject[131425]
You’ll notice it’s just an ID, because the CellObject
doesn’t need to track a LinkObject
the way a NotebookObject
does. But otherwise it can largely be treated like a NotebookObject
in terms of setting and getting options.
There are a number of ways to get a CellObject
:
EvaluationCell[]
NextCell[]
PreviousCell[]
(*Out:*)
CellObject[![22-9203543330558690139](../../img/22-9203543330558690139.png)]
(*Out:*)
CellObject[![22-5574092216230116245](../../img/22-5574092216230116245.png)]
(*Out:*)
CellObject[![22-7671711646045324051](../../img/22-7671711646045324051.png)]
As with a NotebookObject
there is a stored symbolic form for a CellObject
:
First@Cells@EvaluationNotebook[]//NotebookRead
Cell["Mathematica For Chemists","Title",CellChangeTimes{ {3.684256503623343`*^9,3.684256508302112`*^9} }]
And when we use NotebookWrite
we often use it on these sorts of Cell
expressions:
NotebookWrite[EvaluationNotebook[],Cell["A newly written cell","Output",CellDingbatCell["NEW!!",BackgroundNone]]]
NotebookWrite
can also be used to overwrite cells:
bg=Darker@Red;
fg=Orange;
CellPrint@Cell[
"The phoenix burns to ashes...",
"Output",
FontColor->fg,
Background->bg
];
Do[
NotebookWrite[
NextCell[],
Cell[
"The phoenix burns to ashes...",
"Output",
FontColor->Blend[{fg,Darker[bg,i/10]},i/10],
Background->Darker[bg,i/10]
]
],
{i,10}
];
Pause[.25];
Do[
NotebookWrite[NextCell[],
Cell["And is reborn there from",
"Output",
FontColor->Blend[{Darker[bg,1-i/10],fg},i/10],
Background->Darker[bg,1-i/10]
]
],
{i,10}
]
A general Cell
expression has a deterministic form:
Cell[data_,style_,options__]
data
will generally either be a String
, BoxData
expression, or TextData
expression. The differences between these forms will become clearer in the section on Boxes
When working with a cell, it’s possible to view and edit this symbolic representation using Cell ▸ Show Expression
or +E
Boxes
If notebooks are windows and cells are elements of a notebook, then Boxes
describe front-end content. Every piece of content except for primitives such as strings and numbers has a box form for display. Boxes
allow for the interesting formatting that Mathematica permits, by giving a low-level spec for various styling options. We can view the boxes in an expression using ToBoxes
:
Framed[Style["Something super cool",FontColorCurrentValue[{StyleDefinitions,"Section",FontColor}]],RoundingRadius5,FrameStyleCurrentValue[{StyleDefinitions,"Section",FontColor}],BackgroundCurrentValue[{StyleDefinitions,"Section",Background}]]
(*Out:*)
"Something super cool"
ToBoxes@Framed[Style["Something super cool",FontColorCurrentValue[{StyleDefinitions,"Section",FontColor}]],RoundingRadius5,FrameStyleCurrentValue[{StyleDefinitions,"Section",FontColor}],BackgroundCurrentValue[{StyleDefinitions,"Section",Background}]]
(*Out:*)
To make content like Dynamic
work these boxes can’t be static objects, though. Much like CellObject
and NotebookObject
there is a BoxObject
which we can access, although with more difficulty. Easiest, though, is just to use EvaluationBox
:
Dynamic[EvaluationBox[]]
Note that this really does have to be wrapped in Dynamic
. Before it is displayed, this box doesn’t exist. But we can do something fun with this now:
Dynamic[box=EvaluationBox[]]
NotebookWrite[box,ToBoxes@Framed[Style["And the box disappears...",ShowStringCharactersFalse,FontColorCurrentValue[{StyleDefinitions,"Section",FontColor}]],RoundingRadius5,FrameStyleCurrentValue[{StyleDefinitions,"Section",FontColor}],BackgroundCurrentValue[{StyleDefinitions,"Section",Background}]]]
This gives us a way to use NotebookWrite
to overwrite data without overwriting a cell itself.
Stylesheets
Stylesheets give us the power to leverage the multitudinous styling options available to cells to make cascading stylesheets for giving custom styles to notebooks. On the whole this process is straightforward once you know how to get started.
For a given notebook, you can access its stylesheet by going to Format ▸ Edit Stylesheet
. There you can edit the default cell styles or define your own.
What the front end pays attention to are cells formatted like this:
Cell[StyleData[style_],options___]
This will set options
on all cells with style style
by default. To inherit definitions from a different cell style use:
Cell[StyleData[style_,StyleDefinitionsStyleData[parent_]],options___]
That’s pretty much it. Past that it’s simply a matter of figuring out what styles work best and knowing which options do what you want done.