Message Boards Message Boards

Best way to reuse some code in multiple notebooks?

GROUPS:

I have some code I'd like to reuse in multiple notebooks. Simple definitions, like

ratioFromDb[db_] := 10^(db / 20)

I expect I should put these definitions in their own file, and then somehow include that file in various notebooks. What are the details for this process, please? I have researched this in the documentations, and I've probably already seen the correct answer there, but I'm still not sure about this.

My best guess is, put my library in a regular .nb file, and then invoke the library like this:

Once[Get["myLibrary.nb"]]

Do I have it right? If not, if someone could direct me to the specific page or section in the documentation that covers this, I'd appreciate it. Thank you.

POSTED BY: Joe Donaldson
Answer
17 days ago

Joe,

I would save it as a package and do:

Needs[mypackage`]

to use the package from other notebooks.

This is a great way to reuse code. The package can either be installed with Needs[] or you can even add it to your init file and have it automatically available every time you start Mathematica.

Look at the package documentation to get started.

Regards,

Neil

POSTED BY: Neil Singer
Answer
17 days ago

Thanks very much.

I am trying this, but unable to get it to work so far. When I evaluate

Needs["myLibrary`"]

I get an error message:

Get::noopen: Cannot open myLibrary`.
Needs::nocont: Context myLibrary` was not created when Needs was evaluated.

I suspect there's a problem with how my search-paths are setup. All my notebooks, along with my newly created package, are in a directory, but I notice that directory doesn't appear in (dollar-sign, capital p, lowercase a, lowercase t, lowercase h) when I evaluate (dollar-sign, capital p, lowercase a, lowercase t, lowercase h). I have to spell out that variable, because Wolfram's website formats it strangely when I just try to type it in verbatim. So many surprises.

I'd rather not hardcode the full pathname into the Needs statement, because if my I did that, my code would break if I later moved my files to a different directory.

In C I would just do "include myLibray", and this common task would be very easy.

POSTED BY: Joe Donaldson
Answer
16 days ago

So the Needs function doesn't have an option for setting Path, so I've gone back to trying the Get function. When I try

Once[Get["myLibrary.nb", Path -> NotebookDirectory[]]]

it prints out the entire contents of myLibrary.nb, and when it's done, the symbol ratioFromDb still is not defined. I could write a book on making this not work, but still having no idea how to perform this common task in Mathematica, so easy in numerous other languages.

POSTED BY: Joe Donaldson
Answer
16 days ago

Now I have found yet another way to make this not work:

AppendTo[$Path, NotebookDirectory[]];

Needs["myLibrary2`"]

?? ratioFromDb

Information::notfound: Symbol ratioFromDb not found.
POSTED BY: Joe Donaldson
Answer
16 days ago

Removing the double-quotes yields a new way to make this not work:

In[3]:= AppendTo[$Path, NotebookDirectory[]];

In[5]:= Needs[myLibrary2`]

During evaluation of In[5]:= Syntax::tsntxi: "Needs[myLibrary2`]" is incomplete; more input is needed.

In[4]:= ratioFromDb[4]

Out[4]= ratioFromDb[4]
POSTED BY: Joe Donaldson
Answer
16 days ago

Here are two additional ways to make this not work:

In[3]:= AppendTo[$Path, NotebookDirectory[]];

In[4]:= Needs[myLibrary2`]

In[4]:= << myLibrary2`

In[5]:= ratioFromDb[4]

Out[5]= ratioFromDb[4]

In[6]:= << myLibrary2.wl

In[7]:= ratioFromDb[4]

Out[7]= ratioFromDb[4]
POSTED BY: Joe Donaldson
Answer
16 days ago

Joe,

Create your package and use the install menu item. It will place the file in the proper directory. On the mac it is in Library/Mathematica/applications (from memory-- I am not in front of my computer).

POSTED BY: Neil Singer
Answer
16 days ago

I appreciate your advice, but for me, the proper directory is "C:\Users\MyFirstName\Documents\Wolfram Mathematica", even though Mathematica has a different opinion about what's proper. The directory I've named above is where I have version-control set up for Mathematica code.

I am grateful for your trying to help me get this working, but I really just want Mathematica to evaluate a file containing function-definitions, when I specifically request it. I don't want Mathematica to automatically evaluate these function-definitions. I only want them to be evaluated when I specifically ask Mathematica to evaluate them. And I'd hope I could keep this file in the directory I've set up for Mathematica files, because that's the location where my version-control is tracking files. That's the location where my bash scripts operate when I tell them to operate on Mathematica files. That's the location that my backup-software backs up when I run it.

There's no "just read this file and evaluate everything in it" command in all of Mathematica?

POSTED BY: Joe Donaldson
Answer
16 days ago

Try Get["path_to_file"] or use the second argument to Needs[]. See documentation if needed.

POSTED BY: Michael Rogers
Answer
16 days ago

"Try Get["pathtofile"]"

Thank you, but that didn't work for me:

In[14]:= Get[
  "C:\Users\MyFirstName\Documents\Wolfram Mathematica\myLibrary.nb"];

During evaluation of In[14]:= Syntax::stresc: Unknown string escape \U.

During evaluation of In[14]:= Syntax::stresc: Unknown string escape \M.

During evaluation of In[14]:= Syntax::stresc: Unknown string escape \D.

During evaluation of In[14]:= Syntax::stresc: Unknown string escape \W.

During evaluation of In[14]:= Syntax::stresc: Unknown string escape \m.

In[12]:= Get[
  "C:\\Users\\MyFirstName\\Documents\\Wolfram \
Mathematica\\myLibrary.nb"];

In[13]:= ratioFromDb[4]

Out[13]= ratioFromDb[4]
POSTED BY: Joe Donaldson
Answer
16 days ago

"or use the second argument to Needs[]. See documentation if needed."

doesn't work:

In[19]:= Needs["myLibrary2`", "myLibrary2.wl"]

In[20]:= ratioFromDb[4]

Out[20]= ratioFromDb[4]

In[21]:= Needs["myLibrary2`", \
"C:\\Users\\MyFirstName\\Documents\\Wolfram \
Mathematica\\myLibrary2.wl"]

In[22]:= ratioFromDb[4]

Out[22]= ratioFromDb[4]
POSTED BY: Joe Donaldson
Answer
16 days ago

"use the install menu item"

Now I've tried this too, and it too does not work.

POSTED BY: Joe Donaldson
Answer
16 days ago

A Mathematica Style (for application development).

I'm fairly certain you will object to this but it is the procedure that WRI has set up for development of significant projects and it works.

POSTED BY: David J M Park Jr
Answer
16 days ago

Thanks for the link. If it works at all, I'll object to it less than the proposed solutions that do not work at all. I can see how that might be good for significant projects, but for my projects it would be overkill incurring overhead. I got this working in a different computer algebra system in less time than it would take me to even read that document. "load(filename)". Done.

POSTED BY: Joe Donaldson
Answer
16 days ago

I've found a solution that survives preliminary testing. It is undocumented and it has not been mentioned before in this thread. It is the only solution that has survived preliminary testing here. myLibrary02.wl:

BeginPackage["myLibrary02`"]

ratioFromDb[db_] := 10^(db / 20)

dBFromRatio[ratio_] := 20 * Log10[Abs[ratio]]

EndPackage[]

Invocation:

In[1]:= Get[NotebookDirectory[] <> "myLibrary02.wl"]

In[2]:= ratioFromDb[4]

Out[2]= 10^(1/5)

In[3]:= dBFromRatio[6]

Out[3]= (20 Log[6])/Log[10]

An essential but undocumented step is to select all cells in the .wl file and set them to be "Initialization Cells".

POSTED BY: Joe Donaldson
Answer
16 days ago

double-post deleted

POSTED BY: Joe Donaldson
Answer
16 days ago

By the way, I notice that your example is a decibel conversion. If you want to send me your email address I will send you a Dropbox link to an application I developed called UnitsHelper. It has a generalized decibel conversion facility as well as routines to install reduced unit systems, such as geometric units or atomic units, as well as other nifty features.

It also has style sheets, palettes and documentation and thus illustrates a rather complete example of setting up an application in Mathematica.

My email is on my profile page.

POSTED BY: David J M Park Jr
Answer
16 days ago

Thanks, that is very gracious of you. I will take you up on it.

POSTED BY: Joe Donaldson
Answer
16 days ago

Joe,

I am back to my computer. If keeping the file in that directory is what you care about than just do the following:

NotebookEvaluate[NotebookDirectory[] <>"myfile.nb"]

This will execute the notebook contents and define all of its functions as if you opened it up manually and executed it in the kernel.

I still recommend packages. The way I do it is I develop the package in my "home" directory (so it is backed up and version controlled etc.). I install a COPY of the file into the $BaseDirectory/Applications. When I make improvements they are done on the home version of the file and then installed (usually manually by copying the file). If I have a really complicated package, I use eclipse with Wolfram Workbench installed because you can debug it and develop documentation for it. I hope this helps. If you need better instructions or an example, let me know.

Regards,

Neil

POSTED BY: Neil Singer
Answer
16 days ago

Thank you. I will try NotebookEvaluate.

I will not forget your advice about packages when I advance to larger-scale projects. For the time-being, my projects and my library are small, and I don't think it's a good point yet for me to invest the time learning how to set up for large-scale applications.

Do you have any insight about the relevance of the "Initialization Cells" for what I'm trying to do? As I reported earlier, I was only able to make this work (using Get and a .wl file) by setting all cells in my .wl file to "Initialization Cells". I happened upon that solution, but it is not documented in the Wolfram documentation I'm familiar with. I thought Get was supposed to evaluate all cells regardless of whether they're "Initialization Cells", but apparently the Wolfram documentation on that is misleading, or I misunderstood the documentation.

POSTED BY: Joe Donaldson
Answer
16 days ago

If keeping the file in that directory is what you care about than just do the following:

NotebookEvaluate[NotebookDirectory[] <>"myfile.nb"]

This is not a safe way to assemble paths because it assumes that NotebookDirectory[] returns a string ending in the path separator. When I tried it on my system, that was indeed the case. But can you trust it to always do this, for any directory, on any operating system, and with any version of Mathematica? Directory[] doesn't put a path separator at the end of its return value on my computer, therefore the above method wouldn't work with it.

Use this instead:

FileNameJoin[{NotebookDirectory[], "myfile.nb"}]
POSTED BY: Szabolcs Horvát
Answer
16 days ago

You do not need to learn how to create proper packages for this task. Note that unlike Get, Needs is meant to be used with packages that must follow a number of conventions. I do not recommend you start with this just yet (and therefore I do not recommend you use Needs). Get is simpler and can be used to evaluate any plain text file containing Mathematica expressions, whether it follows package conventions or not, and regardless of its location in the file system.

(Note: The documentation and the Mathematica user interface are a bit confusing in that they often refer to .m file as "packages" whether or not they follow these conventions.)

Instead, start like this:

  • Put your definitions in a plain text file with the .m extension
  • Use Get with the full path to this file to evaluate those definitions

You can use any text editor to work with .m files. If you prefer the Mathematica front end, start with File -> New -> Package, then Save As... -> Wolfram Mathematica Package.

How do you conveniently transfer the cells from a notebook (.nb file) to a plain text .m file?

  • Mark those cells that must get exported as initialization cells. Alternatively, mark a whole section of the notebook as initialization group. (Cell menu, Cell Properties)
  • Use File -> Save As... -> Wolfram Mathematica package

How do you do this nb -> m conversion automatically every time the notebook is saved?

POSTED BY: Szabolcs Horvát
Answer
16 days ago

Thanks very much.

POSTED BY: Joe Donaldson
Answer
15 days ago

Group Abstract Group Abstract