How to run initialization code for a palette? - wolfram-mathematica

Occasionally it would be preferable to have some initialization code for palettes (of buttons). For example, it could define some functions that are used by palette buttons.
What is the easiest and preferable way to define/run initialization code for a palette?
The initialization can run either when the palette is loaded or when any button is pressed for the first time (possible issue: what if the kernel is restarted after the palette was loaded?)
The definitions should be somehow localized (i.e. in their own context -- do unique notebook contexts help here?)
If possible, I'd prefer a minimal effort solution (i.e. extra code at the fewest possible places, self contained palette file with no extra package files, palette creation using the existing convenience tools of palettes menu or CreatePalette, etc.)
(You can assume that the initialization code runs fast, e.g. it consists of definitions only)

You're right to be concerned about the visibility of the Dynamic being an issue. The way to absolutely guarantee a Dynamic expression to be evaluated regardless of the visibility of any of the individual cells is to use NotebookDynamicExpression. Here's an example that illustrates NotebookDynamicExpression working while a Dynamic fails because it's hidden within a closed cell group:
cell1 = First # MakeBoxes[
TextCell["Click to open", "Title",
CellMargins -> 0, System`WholeCellGroupOpener -> True],
StandardForm];
cell2 = First # MakeBoxes[
ExpressionCell[DynamicWrapper["hidden cell", Print["DynamicWrapper"]]],
StandardForm];
CreatePalette[
Notebook[{Cell[CellGroupData[{cell1, cell2}, Closed]]},
NotebookDynamicExpression :>
Dynamic[Refresh[Print["NotebookDynamicExpression"], None]]]]
When you evaluate this, note that the Dynamic in NotebookDynamicExpression evaluates immediately. The DynamicWrapper never evaluates until you open the cell group, which you can do by clicking on the "Click to open" text.
In this example, incidentally, notice that I wrapped the NotebookDynamicExpression with Refresh. The function Refresh[#, None]& will make sure that the code evaluates only once -- when the notebook is first opened. Otherwise, the code would obey the standard properties of Dynamic and evaluate whenever any of the dependencies change.
NotebookDynamicExpression has been around since v6, but was only documented in v8. Also documented are its related cousins, CellDynamicExpression and FrontEndDynamicExpression.

A DynamicBox with Initialization is capable of the basic function. You can size the palette such that the object is not visible, and it will still operate.
Here is code for a small sample palette. It sets a value for var. The active code is offset with whitespace.
(* Beginning of Notebook Content *)
Notebook[{
Cell[BoxData[{
TagBox[GridBox[{
{
ButtonBox["\<\"TSV\"\>",
Appearance->Automatic,
ButtonFunction:>None,
Evaluator->Automatic,
Method->"Preemptive"]},
{
ButtonBox["\<\"CSV\"\>",
Appearance->Automatic,
ButtonFunction:>None,
Evaluator->Automatic,
Method->"Preemptive"]},
{
ButtonBox["\<\"Table\"\>",
Appearance->Automatic,
ButtonFunction:>None,
Evaluator->Automatic,
Method->"Preemptive"]}
},
GridBoxAlignment->{"Columns" -> {{Left}}},
GridBoxItemSize->{"Columns" -> {{Automatic}}, "Rows" -> {{Automatic}}}],
"Column"], "\[IndentingNewLine]",
DynamicBox[Null,
Initialization :> ($CellContext`var = "It is done, Master.")
]
}], NotebookDefault,
CellMargins->{{0, 0}, {0, 0}},
CellBracketOptions->{"Color"->RGBColor[0.269993, 0.308507, 0.6]},
CellHorizontalScrolling->True,
PageBreakAbove->True,
PageBreakWithin->False,
ShowAutoStyles->True,
LineSpacing->{1.25, 0},
AutoItalicWords->{},
ScriptMinSize->9,
ShowStringCharacters->False,
FontFamily:>CurrentValue["PanelFontFamily"],
FontSize:>CurrentValue["PanelFontSize"]]
},
WindowSize->{55, 105},
WindowMargins->{{Automatic, 583}, {Automatic, 292}},
WindowFrame->"Palette",
WindowElements->{},
WindowFrameElements->{"CloseBox", "MinimizeBox"},
StyleDefinitions->"Palette.nb"
]
(* End of Notebook Content *)

Related

Code Fragment mode in Pycharm 3 debugging returns None always

When in debug mode in Pycharm, the Evaluate Expression -> Code Fragment tool doesn't seem to be able to assign and display a variable in one go. The only case that seems to be evaluated correctly is when the first line is a constant value.
eg.
10
results as expected in
result = {int} 10
but when trying to obtain the same result with:
c = 10
c
the output is
result = {NoneType} None
However, if I hover over each variable in fragment window, the values are shown as a popup.
Edits to sum up the comments (thanks Vaibhav Mishra):
Unfortunately, this seems to be the default behavior: (won't fix bug)
My understanding of this feature:
Although Pycharm will display a None result when evaluating multiple lines, they are all executed in the context of the currently selected stack frame. One of the consequences being the update of the namespace. Subsequently using single-line evaluations in the same context (or mouse hover) will display the expected values.
Two potential usages:
The Evaluate Code Fragment dialog is automatically prompted when evaluating multiple lines from the editor: Select a block | Evaluate Expression (Alt+F8). May be useful to tweak a couple of lines and run evaluation in one go.
As an alternative to the Debug Command Line, the code fragment mode supports loops and if/else. Although the inspection seems a bit tipsy (mistakenly unresolved variables), it can be ignored, and the editing assistance provided there can be put to good use.

Shadow problem when Getting a package from a Palette action

My simple first Palette is suppose to:
Append my packages Path to $Path
ActionMenu["test",{"The Simple Packages Path":> AppendTo[$Path, ToFileName[{NotebookDirectory[], "02 Simple Packages"}]]}]
Get my packages
ActionMenu["Load Packages", {"Get my package":> Get["myPackage`"]}]
Place on the selected input cell (or on a new input cell), a given input expression, containing different place holders.
OpenerView[{"my Package", Button["construct", Paste[StandardForm#Defer#construct[Placeholder["description"],Placeholder["another description"]]]]}]
The problem is that I keep getting "shadow" messages when I click on the "get my package" action menu item. And I'm sure I'm not double loading the package intentionally. When I click on "construct", it writes Global`construct["description","another description"]. But I'm sure I didn't define it before getting the package (I killed the kernel on my tests).
Do you know what is wrong?
(I use Get on my packages, instead of Needs, to ensure a clean start of the package context)
Also: do you know of a simpler way of doing the Paste[StandardForm#Defer... that ensures both that the expression being paste isn't evaluated and that it goes into an input cell, even when there's no cell selected?
Ok, it seems that your problem is due to the interplay between parsing and interface creation. What you would like in this case is to delay the parsing of package symbols in your interface - constructing code (package symbols that you use in button action functions), from the interface - creation time, until the "press button" time (assuming that by that time, the package has been loaded). Here is one way to do it:
Column[{ActionMenu["Load Packages",
{"Get my package" :> Get["ANOVA`"]}],
OpenerView[{"ANOVA", Button["construct",
With[{sym = Symbol["ANOVA"]},
Paste[StandardForm#Defer#sym[Placeholder["DATA"]]]]]}]}]
What we did here is to use With to inject the symbol into the code for the button function. But, at the time your interface code is parsed, we prevent the creation of the Global symbol with this name - this is what happens otherwise, and this is what causes your problem.
EDIT
If you know for sure that you only use symbols (functions) from packages, and not from the Global' context, here is a version that will be "protected" from this problem: it will Remove the generated symbol if its context turns out to be Global' - and thus pressing button before the package has been loaded would result merely in a warning message (I use the symbol package to attach the message to - should be replaced by whatever is the name of your interface - making function):
package::noload = "Please load the package containing symbol `1`";
Column[{ActionMenu["Load Packages",
{"Get my package" :> Get["ANOVA`"]}],
OpenerView[{"ANOVA", Button["construct",
With[{sym = Symbol["ANOVA"]},
If[Context[sym] === "Global`",
Message[package::noload, Style[ToString[sym], Red]];
Remove[sym];,
(* else *)
Paste[StandardForm#Defer#sym[Placeholder["DATA"]]]]]]}]}]
Well, I don't have your package, so for testing I changed the action menu to get the ANOVA package:
ActionMenu["Load Packages", {"Get my package" :> Get["ANOVA`"]}]
ANOVA[{{1, 1}, {1, 2}, {2, 4}, {2, 3}}] now works without a hitch. No complaints about shadowing. This suggests that the cause of your shadowing problem lies somewhere else. I noticed, though, that the word ANOVA stays blue. This will be related to the problem you reported here.

Syntax Coloring In Mathematica

How could user-defined function symbol such as f in
f[x_] = 2 x
or variable symbols such as lotto in
lotto = Table[2, {10}];
be colored automatically ?
In Syntax coloring on M8 no option is offered for this.
Only Local Variables or Global symbols that have no values assigned.
This is not exactly what you asked for, but it may be useful to you.
You can highlight symbols by context, using this method:
SetOptions[$FrontEndSession,
AutoStyleOptions -> {"SymbolContextStyles" -> {"highlight`" -> Green}}
]
AppendTo[$ContextPath, "highlight`"];
Now, when you create a symbol in the context highlight` it will automatically be colored green:
highlight`lotto ;
and since highlight` was appended to $ContextPath, after that the symbol can be used plainly:
lotto
Highlighting all symbols (variables)
If you want all the symbols you create to automatically be highlighted, then set:
$Context = "highlight`"
After that, all new symbols you create will belong to the context highlight` and will receive the color.
New means ones that have not been previously used in the session, or have been Removed.
It occurs to me that a better way to accomplish this, that avoids a possible "shadowing" problem, may be to set highlighting for the Global` context itself. I have not considered the ramifications of this, but it can be done with this alone:
SetOptions[$FrontEndSession,
AutoStyleOptions -> {"SymbolContextStyles" -> {"Global`" -> Green}}
]
Tips on usage
The context highlight` is completely arbitrary, and you can have multiple contexts highlighted with different colors.
You can color the contexts of packages such as Units` to distinguish which symbols belong to that package.
Such variables are automatically colored after you assign a value to them. Under the default Mathematica settings, lotto changes color from blue to black as soon as you assign the value. Strictly speaking, it is the unassigned variables that get colored according to the setting you will find under Preferences / Appearance / Syntax Coloring / Other / Global symbols that have no value assigned.
If what you are looking for is a way to assign a distinct color to global symbols whose only definitions are own-values, then I believe that you are out of luck. As far as I know, the syntax coloring machinery does not distinguish between own-values ("variable assignments"), down-values ("function definitions") and up-values ("expression part definitions").
As I said in my comment above, I think that this would be hard to completely automate. You'd have to wrap Set and SetDelayed to automatically move variables into the right context depending on whether they're creating an OwnValue or a DownValue.
To do this manually just requires a simple edit of Mr.Wizard's previous work...
SetOptions[$FrontEndSession,
AutoStyleOptions -> {"SymbolContextStyles" ->
{"functions`" -> Green, "variables`" -> Pink}}]
$ContextPath = Join[$ContextPath, {"functions`", "variables`"}]//DeleteDuplicates;
variables`x;
functions`f;
Is this what you want?

How to delete the input cell upon evaluation?

I would like to accomplish the following: upon evaluation of an input cell, it should self-destruct (i.e. delete itself). I tried to hack something together with SelectionMove and NotebookDelete, but didn't quite get what I wanted.
Here are potential use cases:
the command might be a shorthand for a series of other commands that will be generated dynamically and inserted into the notebook
the command might only be used for side effects (e.g. to set a notebook option or to open a new notebook); leaving the command in the notebook after evaluation serves no purpose and creates clutter
Edit: As per Mr. Wizard, the answer is SelectionMove[EvaluationNotebook[], Previous, Cell]; NotebookDelete[];. I don't know why it wasn't working for me before. Here is some code that uses this idiom.
writeAndEval[nb_, boxExpr_] := (NotebookWrite[nb,
CellGroupData[{Cell[BoxData[boxExpr], "Input"]}]];
SelectionMove[nb, Previous, Cell];
SelectionMove[nb, Next, Cell];
SelectionEvaluate[nb]);
addTwoAndTwo[] := Module[{boxExpr},
boxExpr = RowBox[{"2", "+", "2"}];
SelectionMove[EvaluationNotebook[], Previous, Cell];
NotebookDelete[];
writeAndEval[EvaluationNotebook[], boxExpr];
]
Now, running addTwoAndTwo[] deletes the original input and makes it look as if you've evaluated "2+2". Of course, you can do all sorts of things instead and not necessarily print to the notebook.
Edit 2: Sasha's abstraction is quite elegant. If you are curious about "real-world" usage of this, check out the code I posted in the "what's in your toolbag" question: What is in your Mathematica tool bag?
To affect all Input cells, evaluate this is the notebook:
SetOptions[EvaluationNotebook[], CellEvaluationFunction ->
( (
SelectionMove[EvaluationNotebook[], All, EvaluationCell]; NotebookDelete[];
ToExpression##
)&)
]
If you only want to affect one cell, then select the cell and use the Options Inspector to set CellEvaluationFunction as above.
Or, building on Mr. Wizard's solution, you can create a function SelfDestruct, which will delete the input cell, if you intend to only do this occasionally:
SetAttributes[SelfDestruct, HoldAllComplete];
SelfDestruct[e_] := (If[$FrontEnd =!= $Failed,
SelectionMove[EvaluationNotebook[], All, EvaluationCell];
NotebookDelete[]]; e)
Then evaluating 2+3//SelfDestruct outputs 5 and deletes the input cell. This usage scenario seems more appealing to me.

Two initialization Cells in one Notebook each autosaved in separate .m-file?

Is there a way to create Notebook in which each Initialization Cell will be auto-saved in its own .m-file with arbitrary name?
P.S. The question is related to the Mathematica program developed by Wolfram Research Inc. It is not about Mathematics or math.
I'm not sure if the following approach would satisfy you: I once wanted a way of generating compact notebooks containing only the initialisation cells found in my development notebook; the following code writes the initialization cells of the current notebook into a single new notebook and autosaves a .m file as a side-effect but it could easily be adapted to generate a separate notebook and .m file for each initialization cell.
In[162]:= nbToExtract = SelectedNotebook[]
In[163]:=
extractInitializationCells[nb_] :=
Block[{nbNew = CreateDocument[], count = 0},
(SelectionMove[nb, Next, Cell];
While[NotebookRead[nb] =!= {}, (If[InitializationCell /.
Options[NotebookSelection[nb], InitializationCell],
(count++;
NotebookWrite[nbNew, NotebookRead[nb]]), {}]; SelectionMove[nb, Next, Cell])];
Print[ToString[count] <> " initialization cell(s) found"];
CurrentValue[nbNew, AutoGeneratedPackage] = Automatic;
NotebookSave[nbNew, fn];
NotebookClose[nbNew];
Clear[nbNew](* just in case *))]
extractInitializationCells[nbToExtract]
This only extracts the initialisation cells below the cell in which the function extractInitializationCells is called. And I'd agree with the previous caveats about using the auto generation package mechanism. Also, CurrentValue is not protected indefinitely from backwards incompatibility but it has survived several major Mathematica versions so far.

Categories

Resources