31

My init.m Feels Like it's Missing Something

Although I am familiar with about a dozen or so programming languages I am only sort of, kind of, halfway competent in about three. MMA with it's boxes, expressions, patterns, symbols, and cells is a whole new beast to me. It forces you to forget everything you think you know about programming and think differently. Then it throws a wrench into the whole mess hy introducing the init.m without a good explanation.

The following working code is what I have so far. It is what I call my pre-alpha init.m. My concerns are that it may be missing something that MMA experts normally place in there. For example is this a good place to clean out old temp files, remove obsolete symbols or delete obsolete objects, create persistent objects, set new paths, set $HistoryLength, ClearSystemCache, is using Once here okay, etc.? My other concern is where should I drop copies of init.m if I want it to survive a refreshed Kernel or a crashed FrontEnd?

(* overload immediately needed repository resources *)

Once@( Quiet@PersistResourceFunction["PersistResourceFunction"]; Quiet@PersistResourceFunction["SymbolQ"]; Quiet@PersistResourceFunction["ResourceFunctionMessage"]; Quiet@ResourceUpdate[ResourceObject["PersistResourceFunction"]]; );

(* overload immediately needed packages *)

Once@Map[Get,{"Alphas", "NBEssentials", "NBTaskmate","NBStyles"}];

(* other cool tasks TBD *)

Since I have your attention is it okay to do this: Once@Get /@ {"Alphas", "NBEssentials", "NBTaskmate","NBStyles"};?

There is Almost No Help Published by Wolfram

Some of our most essential code is hidden away in a file that we can just drop 'n' forget. Although the proper contents of this infamous file is expected to be well understood by all seasoned programmers the official documentation at Wolfram only hints at but gives no solid examples of the kind of things to put in there. This would help coders like me who are not programmers but come from a different field like physics and engineering who need to employ coding with their work and must adhere to best practices to go with it.

What Mathematica Stack Exchange Has to Offer

As of this writing a search for init.m yields 419 help posts. However these are all about fixing specific-area applications or broken code not about building a proper init.m.

There are a few "big-list" posts such as the ambitious undisputed world heavyweight that grew into Godzilla which I really like, Where can I find examples of good Mathematica programming practice?, unfortunately in its quest to answer all best practices under the sun it forgets to even mention the init.m. Another one I really like is the more focused Getting serious about Mathematica programming but it too omits the init.m. There are others. This is just a very small sampling that stood out to me as expected to have a dedicated category on the init.m.

The Five Secondary Goals of this Post Are to Help Build Best Practices

Of course the primary goal is to examine my init.m which will help me figure out what is good to put in there and what not to put in there. Along the way we can help many others by identifying some best practices.

  1. Let others learn from your best practices by sharing your code in an Answer.
  2. Let others share their expertise in how to improve your shared code.
  3. By identifying what every init.m file should have and why.
  4. By identifying what what every init.m file should NOT have and why.
  5. By identifying in which directories we should drop 'n' forget our init.m and why.

With posts like these there are no losers, everybody wins. The only catch is we all need to participate to win.

Jules Manson
  • 2,457
  • 11
  • 19
  • 2
    Great question! I too would like advice on how to improve my init.m – DrMrstheMonarch May 20 '22 at 06:48
  • 1
    @DrMrstheMonarch you can probably get the ball rolling by sharing your init.m regardless of how satisfied or unsatisfied you may be with it and ask for a critique. if too long remove the fat. if it has private data remove or obscurificate those details.. i intend to share my init.m in the next 2 or 3 days. – Jules Manson May 20 '22 at 09:38
  • 1
    I set this to CW for the time being; if anyone wants to discuss on whether we should keep this, please open something on Meta. – J. M.'s missing motivation May 20 '22 at 22:27
  • 1
    I do not use an init.m file; I have a longish intialization cell with my standard functions which I paste into each notebook on which I will work for a long time on a project. The one thing I would like to see in this dicussion is how to standardize the Stylesheet location. In my home computer I have to create an otherwise unused directory and have a copy of my stylesheet there that matches the directory structure of my office computer. Otherwise, if I would start a notebook on my office laptop, it would not find the stylesheet after I copied it to my home computer. – Nicholas G May 21 '22 at 14:57
  • @J.M. please put my post back. im sure you meant well but by moving it to the gulag otherwise known as "communist" wiki it has already begun to die a slow grueling death. this is evident if you examine the lively activity before and other than my own the zero activity afterwards. to ease your conscience i went through the trouble of doing some surgical edits so that it now looks like a proper Question. also it is policy to discuss with author before moving it. thank you for reconsidering. o_~ – Jules Manson May 29 '22 at 05:31
  • JulesManson, @J.M. asked that such a request be put on Meta, so that the community can discuss it. (Comments are not meant for such debates.) – Michael E2 May 29 '22 at 14:13
  • @MichaelE2 and i pointed out that a policy error was made by moderator not discussing the move with me beforehand. all i am asking is that said moderator correct his mistake. im certain his error weighs much more heavily than any non-policy request for me to ask on meta. – Jules Manson May 29 '22 at 21:00
  • 3
    I disagree. This question should be closed as too broad ("Needs more focus"), but by making it CW, I'm in favor of keeping it open, similar to other CW posts with a broad focus ("Pitfalls", "good examples", etc.). Now closure would be more like sending it to a gulag. But here we are debating the issue, which should be happening on meta. – Michael E2 May 30 '22 at 00:15
  • 2
    I like the question. I'm going to look over all the answers and pick-and-choose from the ideas presented. I'm sure other Mathematica users will benefit in the same way. So I'd prefer to keep this open and accepting answers. If it needs to be CW to do that, fine by me. TBH, I don't understand the distress of the OP. The Q has attracted interest, and good answers. Over time there will be more answers. What's not to like? (I hope it isn't a matter of rep ...) – davidbak May 30 '22 at 00:49
  • "by moving it to the gulag otherwise known as "communist" wiki it has already begun to die a slow grueling death." - I note that one of my own questions, which seems to be very popular, is itself CW, so your characterization of CW status as a "gulag" is unfounded at best. I will not discuss further in these comments; please make a meta post if you wish to state your case, but I agree with Michael that CW is better than the alternative of closing this question. – J. M.'s missing motivation May 30 '22 at 01:07
  • @J.M. you win. but you are wrong and biased. you refuse to correct your initial mistake: policy that you need to first discuss move with author. but i will NOT honor your non-policy request. i hope this "win" makes you feel powerful because im a nobody. – Jules Manson May 30 '22 at 03:46

6 Answers6

18

I am an init.m ascetic. And I doubt after 30+ years of using Mathematica I will change. Everyone else, who wishes to, may proclaim how it is indispensable to their workflow, and I will accept their pronouncements without comment or criticism.

My Kernel init.m has nothing in it. My Front End init.m has whatever the FE puts in there from setting preferences, some history from the SEUploader palette, and hopefully little else. I try to avoid SetOptions[$FrontEnd,...] and use SetOptions[$FrontEndSession,...] instead.

I do have a notebook I always use to open Mathematica with some standard things, like $HistoryLength = 5, tucked away in section called "Init" that I select and execute whenever the Kernel starts or restarts. Many years ago I put something in one of the init.m files that caused bugs in something I was working on. It took me a long time to figure out what was causing the problem, because it's hard to remember everything you put in a file you never see. Once I had something in init.m that caused the kernel to crash. After few problem like that, I decided sometime in the 1990s to ditch using init.m and perform initializations optionally and separately from starting the kernel. Since then I've generally come to realize that learning to use a tool as it was designed is easier than trying to make a tool into something else. That's not an absolute rule though, and this tool, Mathematica, comes designed with init.m and SetOptions[], among other things. So others may have different opinions as well as good reasons for their particular setup. I will add this: If you are working with others, it's helpful for everyone to have the same setup.

Here are the "Init" codes I use:

$HistoryLength = 5;
Needs["NDSolve`FEM`"];
Needs["GeneralUtilities`"];
Needs["CompiledFunctionTools`"];
traceView2[..] := ... (*https://mathematica.stackexchange.com/a/29340/4999*)
traceView2i[..] := ... (*=traceView2[] + TraceInternal->True*)
BoxForm`UseApproximations = False;
(* add Okabe-Ito colorblind palette to ColorData[]
     per https://mathematica.stackexchange.com/a/57893/4999 *)
Typeset`$InformationGridOpen = False;(* start ?symbol closed *)
qlink[..] := ... (* create link to Mma.SE question;
     see https://mathematica.stackexchange.com/questions/87375/plotting-the-tangent-of-a-curve#comment237773_87375 *)
echo = (Print[#]; #) &; (* for debugging (don't like Echo[]) *)
dbecho[lbl_] := (Print[lbl -> #]; #) &; (* ditto *)

Plus a few useless utilities I won't mention because I've never used them. In fact I forgot they were there, until looking up my "Init" codes for this answer.


P.S. I think this Q&A might ought to be a "Community Wiki." I feel my answer is strongly opinionated and what is best will depend on individual situations. So what seems the best answer to one person may seem a bad answer to another.


Update 2022.06.12

Here's one of those useless things I used today....

I hate it when users leave off semicolons that would suppress unnecessary output on a dozen or two input lines. I'd only use this function on this site, so more useful to someone like me.

addsemis[c_CellObject] := Module[{ce},
  ce = NotebookRead@c;
  SelectionMove[c, After, Cell];
  NotebookWrite[ParentNotebook[c],
   Replace[ce, {
     e : RowBox[{_, ";"}] :> e,
     e_RowBox :> RowBox[{e, ";"}]}, 3]];
  NotebookDelete[c]
  ]

Example usage: addsemis[PreviousCell[]].

Caveat: 1. It writes in a notebook, so I'd use it only on a temporary notebook in case I trashed it. 2. In a month or two, I'll forget all about this function again, or forget its name, and then think it's faster to type 20 semicolons than to look up the function again.

Acknowledgement: I probably got the idea from Cell splitting in mathematica, since a couple of the lines are identical.

Michael E2
  • 235,386
  • 17
  • 334
  • 747
  • i also had a buggy init.m so i stopped using it. this time im building it up from scratch based on best practices or examples contributed here. although a mod did move this post to the gulag aka "communist" wiki i am asking to have it moved back. it is where posts go to die a slow grueling death as is evident by examining lively activity before and other than my own the zero activity afterwards. i also have an echo in which if placed inside a function it will automatically Echo any symbol's name along with value. it has more difficulty with arguments but i fixed that too. – Jules Manson May 29 '22 at 06:29
  • 2
    @JulesManson 2 answers before CW, 4 more answers after. More upvoting after CW, (my impression, I didn't count everyone's; but 13/14 upvotes on my post came after CW). Doesn't seem a gulag to me. – Michael E2 May 29 '22 at 14:07
11

I tend to put a lot of little functions in my init.m file, functions that take arguments and use module variables. I found that I would now have Global symbols like x, var, date, name, etc, before even running any commands.

So the interesting thing I have in my init.m file is a package structure:

BeginPackage["Init`"]

<exported functions list>

Begin["Private"] <implement functions> End[] EndPackage[]

never regretted it.

Jason B.
  • 68,381
  • 3
  • 139
  • 286
  • 2
    Could also simplify the init.m to use an explicitly designed package, i.e. just put in it something like Needs["JasonTools`"] to avoid needing to define a bunch of functions in a portion of the layout that is less discoverable – b3m2a1 Jun 06 '22 at 19:21
7
(** User Mathematica initialization file **)

$PrePrint = Replace[# , mat_?MatrixQ :> MatrixForm[mat]] &;

Needs["Let`"];

Needs["sprintf`"];

Get["AcademicTheme`"];

The reason to keep it relatively empty is to avoid problems when sharing a notebook with someone else (who may not have the same init.m customizations).

One thing I used to have was a hook in $Pre (or maybe $PreRead?) that removed some front-end formatting. It's usually a mistake if eg. MatrixForm is in the input if you use the above $PrePrint. I ultimately removed it. The combination can be good for new users who are sometimes mistakenly learn that the construction // MatrixForm is a formatting directive, rather than // is a form of composition.

evanb
  • 6,026
  • 18
  • 30
  • I've been thinking more about this, and I think the reason I've kept it so bare is really the difficulty a highly-customized init.m poses when sharing my work. Changing a plot theme or how matrices are presented is fine, that just changes what I see. But adding functions that others might have would cause an issue if they tried to rerun the notebook. – evanb May 23 '22 at 08:06
  • i like how you mixed Get with Needs. i just use Get for all my packs but i can identify two that should only be called with Needs. ill do that too. thanks for sharing. – Jules Manson May 29 '22 at 21:26
6
SetOptions[$FrontEnd, 
  EvaluationCompletionAction->{"ShowTiming"}, 
  CodeAssistOptions->{"FloatingElementEnable" -> False, "MaxGlobalMatches" -> 10}, 
  ShowPredictiveInterface->False, 
  TranslationOptions -> {"Enabled" -> False},
  FractionBoxOptions->{AllowScriptLevelChange->False},
  Graphics3DBoxOptions -> {SphericalRegion -> True},
  "EvaluationQueueActions"->{"Icon","Flash","NotificationCenter","ProgressIndicator"},
  MessageOptions -> {"InsufficientVersionWarning" -> False, "KernelMessageAction" -> "PrintToNotebook"},
  "NotebookSecurityOptions" -> {"TrustByDefault" -> True},
  PrivateFrontEndOptions->{"ShowAtStartup"->"NewDocument"},
  RenderingOptions->{"HardwareAntialiasingQuality"->1},
  CellLabelPositioning -> Left
];

If[$VersionNumber>=12,SetSystemOptions[ "TypesetOptions" -> "NumericalApproximationForms" -> False]];

Related link:
When calculating, the taskbar icon will not change in Mathematica 12.2
Magnification messing up styles

chyanog
  • 15,542
  • 3
  • 40
  • 78
5

As I mentioned in a comment, I do not use an init.m file, I paste my frequently used functions from project notebook to project notebook as an initialization cell. That having been said, my initialization cell is:

If[False, {(* 
  true for saving to PDF at true dimensions and ImageResolution of \
1200 PDI, false for large graphs for screen and saving as PNG, 
  see  https://mathematica.stackexchange.com/a/234591/43662*)
  ftsz = 12,(*fontsize 12 for graph publication quality PDFs*)
  imgsz = 100, 
  imgrez = 2400}(*imagesize coefficient 57/was100 equal to one inch*)
\

, {ftsz = 38, imgsz = 267, imgrez = 72}];(else for large images and publishing PNG graphs
42/200
) fntandsz = {FontFamily -> (fntFam = "Georgia")("Times"), FontSize -> ftsz}; $HistoryLength = 5; txt[a_, b_, c : {?NumericQ, _?NumericQ} : {0, 0}, d : {?NumericQ, ?NumericQ} : {1, 0}, opt : OptionsPattern[]] := Text[Style[a, opt, FontFamily -> "Georgia"("Times"), FontSize -> ftsz], b, c, d](* This simplifies the input for text in raphics to avoid the
need to nest Text[Style[ ] ] in every graphic. The options at the end
get passed to Style[]. The previous arguments are made optional by
getting a default value ":{0,0}" while a test prevents the code from
confusing an option for those with ":{
?NumericQ,NumericQ}" ) fpath = (NotebookBrowseDirectory /. Options[$
FrontEnd]) <> "\";(save in notebook path) (stop evaluation if the path does not end in \Documents*) If[StringTake[fpath, -11] != "\Documents\", (Remove cells from evaluation queue)( SelectionMove[EvaluationNotebook[], All, Notebook, AutoScroll -> False]; FrontEndExecute@FrontEndToken@"RemoveFromEvaluationQueue"; SelectionMove[EvaluationCell[], After, Cell, AutoScroll -> False]; (set $Pre to abort current cell but before that schedule a task to
un-define $
Pre
) SessionSubmit[ScheduledTask[$Pre =., {Quantity[3, "Seconds"]}]]; MessageDialog[ "Wrong working directory! Open and close a file in /Documents and
rerun."]; $
Pre = Abort[] &; Abort[];)];(end of sequence stopping evaluation if the directory
is false
) droptrailingperiod[x] := If[Round[x] == x,(is the rightmost a period, from some precision?)

Round[x](then use Round to drop the trailing period) , x](else not) adollartick[ x_] := {x,(define a function that creates a tick label pair for
dollar amounts
) NumberForm[droptrailingperiod@x, NumberSigns -> {"-$", "$"}, DigitBlock -> 3](put dollar sign and comma and drop the trailing period) } dollarticks[min_, max_] := adollartick[#] & /@ N[FindDivisions[{min, max}, 3]](to produce dollar amounts as tick marks with three tickmarks)

dollarticks7[min_, max_] := adollartick[#] & /@ N[FindDivisions[{min, max}, 7]](to produce dollar amounts as tick marks with seven tickmarks)

apercenttick[x_] := {x,(function of tick pair for percentages) ToString[ droptrailingperiod[ 100 x]](multiply by 100 and drop trailing period) <> "%"}(and append a % sign) percentticks[min_, max_] := apercenttick[#] & /@ N[FindDivisions[{min, max}, 7]] fewpercentticks[min_, max_] := apercenttick[#] & /@ N[FindDivisions[{min, max}, 4]] fewticks[min_, max_] := droptrailingperiod[#] & /@ N[FindDivisions[{min, max}, 4]] acommatick[x_] := {x, AccountingForm[x]} commaticks[min_, max_] := acommatick[#] & /@ FindDivisions[{min, max}, 7] fewcommaticks[min_, max_] := acommatick[#] & /@ FindDivisions[{min, max}, 4] seagreen = RGBColor[{46/255, 139/255, 87/255}];(also define some extra colors) yellowgreen = RGBColor[{173/255, 1, 47/255}]; darkyellow = RGBColor[{204/255, 204/255, 0}]; (a very complex function for placing text in 3D:) text3D[str_, location_ : {0, 0, 0}, scaling : {?NumericQ, _?NumericQ} : { 1, 1}, longitude : _?NumericQ : 0, elevation : _?NumericQ : 0, tilt : _?NumericQ : 0, opt : OptionsPattern[]] := Module[{mesh = DiscretizeGraphics[ Text[ Style[str, opt, FontFamily -> "Georgia"("Times"), FontSize -> 12(don't scale with ftsz)]], _Text, MaxCellMeasure -> 0.04], rotmatrx = RotationMatrix[longitude, {0, 0, 1}] . RotationMatrix[-elevation, {0, 1, 0}] . RotationMatrix[tilt, {1, 0, 0}]}, Join[{EdgeForm[]}, MeshPrimitives[mesh, 2] /. {x?NumberQ, y_?NumberQ} :> (rotmatrx . (scaling~Join~{1} {x, y, 0}) + location) (,{Black},MeshPrimitives[BoundaryMesh[mesh],1]/.{x_?NumberQ,y_? NumberQ}[RuleDelayed](rotmatrx.(scaling~Join~{1} {x,y,0})+ location)REMOVE REM IF NEEDING OUTLINES, see https:// mathematica.stackexchange.com/a/131842/43662)]] twoYrDigitAbbrev[yr_] := "[CloseCurlyQuote]" <> StringTake[ToString[yr], -2](Show 1964 as '64) twoDgNo[x_] := NumberForm[ x, {5, 2}](Show 3.1415923 as 3.14; no not use for numbers with
over 5 digits
) numericOrPercent[num_, digits_ : {2, 0}] := Which[ 0 <= num <= 1 && NumericQ[num], Style[PercentForm[num, digits], FontSlant -> Plain], NumericQ[num], Style[num, FontSlant -> Plain], True, num] tblFm2Dgt[x_List, opt : OptionsPattern[]] /; Length@Dimensions@x > 1 := TableForm[Map[twoDgNo[#] &, x, {2}], opt](to make tables show two digits while exportable with built-in
precision
) (define the chi-squared test) chiSquareTest[obs_List, exp_List] /; Dimensions[obs] == Dimensions[exp] := Block[{t}, t = Total[(Flatten@obs - Flatten@exp)^2/Flatten@exp] // N; {Rule["chisqr", t], Rule[pval, SurvivalFunction[ ChiSquareDistribution[ Times @@ Table[Dimensions[exp][[i]] - 1, {i, Length@Dimensions@exp}]], t]]}] expTable[u_List] := Module[(Create null hypothesis matrix) {rs = Plus @@ u, cs = Plus @@ Transpose[u], n = Total[Flatten[u]]}, Transpose@Outer[Times, rs, cs]/n] lineAndPoints[lst_List] := {Line[lst], Tooltip[Point[#], #[[2]]] & /@ lst} percent[n_] := If[n > 1 || n < 0, "Erroneous use of percent.", If[n == 1, "100%", StringTake[ToString[twoDgNo[n]], -2] <> "%"]] SetOptions[AccountingForm, DigitBlock -> 3];(Use AccountingForm to see numbers with commas and spaces every third decimal digit.)

I also have some functions for abbeviations according to the Blue Book citation system that legal practice uses, if anyone is interested I 'd gladly share.

Nicholas G
  • 1,981
  • 10
  • 15
  • i used to do that. i had two very long init cells. then one day i decided to tie everything in each cell to user defined function as a persistent symbol. it worked. all i then needed was one init cell calling two persistent symbols once. give it a try. it should work. :) – Jules Manson May 29 '22 at 21:20
3

The documentation for init.m is functional, if sparse. There are no Examples, and there is no Applications section.

The init.m documentation points to Wolfram System Setup under "Related Guides", but that topic apparently doesn't point back to init.m, or at least, not directly.

The "See Also" for init.m contains four items, three of which are not helpful in the least. Those three are wolfram, mathematica, and Mathematica, all of which appear to be largely nonsensical in this context.

  • 2
    You can write your observations in the comments below the answer. Or, you can expand this answer to include a use-case/scenario originating from an entry in a typical init.m file that, at least partially, addresses the question. Thanks. – Syed May 20 '22 at 15:42
  • @StevenBlack i love how you summed up the lack of good documentation by wolfram site. do you mind if i add it to my post as a slightly edited or paraphrased quote by you? – Jules Manson May 29 '22 at 05:58
  • @JulesManson – Steven Black May 30 '22 at 11:35
  • 2
    One of the "nonsensical" items explicitly points out how to add an init.m file or importantly, to prevent it from being loaded. To me that's a sensible reason to include it. I wonder if the others have the same options, even though it is not mentioned. – Michael E2 Jun 01 '22 at 05:23
  • @MichaelE2 even my own rudimentary init.m (shown in Question post) would probably have been very useful in giving noobs like me ideas of how to use the init.m. – Jules Manson Jun 05 '22 at 21:59