26

Is there a way to separate open Mathematica notebooks so that they don't share any variables? How about making it so some variables are shared but not all?

knpwrs
  • 15,691
  • 12
  • 62
  • 103

3 Answers3

36

Yes, there is. I recommend reading documentation related to Mathematica contexts. In a nutshell, all variables belong to some context (namespace), and all variables can be accessed via their fully-qualified names of the form "ContextName`varName". If you just use "varName", Mathematica will search contexts in $ContextPath (try evaluating the variable $ContextPath to see what it is), and will use the first context where it finds that variable. In addition, each notebook specifies a context (stored in the variable $Context) where all its variables are stored (unless fully-qualified name is used).

By default, for all notebooks the context is "Global`". Also by default, $ContextPath for all notebooks includes the "Global`" context (as well as "System`" and some others). The net result is that variables are shared across notebooks, and this can rather quickly become annoying. However, there's an easy solution. To create a "private" context for a notebook, evaluate the following:

SetOptions[EvaluationNotebook[], CellContext -> Notebook]

This notebook will be assigned a unique context (evaluate the variable $Context to see what it is). Also, global context will be removed from ContextPath (try evaluating $ContextPath before and after the SetOptions[...] above to see what's going on.)

[Update: As pointed out by rcollyer on the new Mathematica stack exchange, to set this option as the default for new notebooks, do the following: open the Options Inspector (Ctrl+Shift+O), change the scope (in the dropdown on the top) from "Selection" to "Global Preferences"; on the left expand the nodes Cell Options -> Evaluation Options, and change the CellContext setting to "Notebook."]

Now, here's how to create a shared context:

Begin["SharedContext`"];
varShared1 = "Shared string";
End[];

Alternatively, you could've just typed

SharedContext`varShared1 = "Shared string";

Now you can either use the fully qualified names ("SharedContext`varShared1" will work in any notebook), or you can add the context to $ContextPath:

AppendTo[$ContextPath, "SharedContext`"]

If you do this in all notebooks, varShared1 will become visible without a fully-qualified name.

To summarize, context work a lot like many other search paths. However, there are many subtleties (for example, if a symbol has already been defined in some other context, the Begin["SharedContext`"]/End[] block might not work as you expect -- the existing context of the symbol will be used instead of SharedContext`), so I recommend a healthy dose of experimentation and perusing the docs.

Leo Alekseyev
  • 12,893
  • 5
  • 44
  • 44
  • Yep. Much better than mine. Deleting. – Dr. belisarius Feb 04 '11 at 14:32
  • 6
    You can also set this via the Evaluation > Notebook's Default Context menu (instead of SetOptions.) [The documentation uses the "Unique to Each Cell Group" setting so that there aren't any variable conflicts.] – Brett Champion Feb 04 '11 at 14:56
  • 1
    Followup question: is there anyway to make Mathematica set the context of new notebooks to be private by default, instead of having to create a private context for every new notebook manually? – Joe Aug 29 '11 at 07:16
  • 2
    @Joe: Not that I know of, but I have written some convenience functions to easily set and access private contexts. I just type `setPrivate[]` when I start a new notebook, and `spawnScratch[]` when I want to duplicate the existing notebook's context in another notebook. I've used this for over a year and found it to be acceptably convenient. The code is here: https://github.com/leoalekseyev/mma-context – Leo Alekseyev Jan 11 '12 at 23:10
  • @LeoAlekseyev: Someone finally found a way to make Mathematica set the context of new notebooks to be private by default: check out [this answer](http://mathematica.stackexchange.com/a/854/253) – Joe Mar 24 '12 at 09:25
1

I'm not really sure if this is a wise thing to do, but anyway.

Here is a schematic solution for two Notebooks. It may be generalized, but it's not straightforward.

  1. Open two Notebooks

  2. In each of them go to the menu (evaluation -> Notebook's default context -> Unique to this Notebook) With this, the symbols are not shared anymore.

  3. In each Notebook enter something like Context[] to get the Notebook Context

  4. Now in each Notebook enter the following code

.

   Needs["Experimental`"];  
   SetAttributes[f, HoldFirst];  

   f[s_, val_] := ToExpression@StringJoin["Notebook$$17$799580`", 
                   ToString@Unevaluated@s, "=", ToString@val];

   ValueFunction[t] = f

Where the Notebook$$17$799580 is the context of THE OTHER Notebook (this should be able to be obtained "automatically", but this is a proof of concept only.

Now when you want to share a symbol enter

 f[symbolToShare]  

That's it.

You may share the value bidirectionally, or just in one direction, entering f[x] only in the Notebook you want as source value for x. The other Notebook will get the updated value, but it'll not update it back.

HTH!

Edit

Towards automation:

You may get all other open Notebook Contexts to update your shared symbols as:

ctxs[]:= Complement[Contexts["Notebook$$*"], 
                  Flatten@Union[{Context[]}, 
                  StringCases[Contexts["Notebook$$*"], __ ~~ "Private" ~~ __]]]

So your f will become something like this (not tested)

   f[s_, val_] := ToExpression@StringJoin[#, 
                   ToString@Unevaluated@s, "=", ToString@val]&/@ctxs[];
Dr. belisarius
  • 60,527
  • 15
  • 115
  • 190
0

To give all notebooks unique contexts open Options Inspector and set Cell OptionsEvaluation OptionsCell Context to Notebook.

stakx - no longer contributing
  • 83,039
  • 20
  • 168
  • 268