Message Boards Message Boards

1
|
10191 Views
|
23 Replies
|
11 Total Likes
View groups...
Share
Share this post:

Best way to reuse some code in multiple notebooks?

Anonymous User
Anonymous User
Posted 7 years ago

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: Anonymous User
23 Replies

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
Anonymous User
Anonymous User
Posted 7 years ago

Thanks very much.

POSTED BY: Anonymous User

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
Anonymous User
Anonymous User
Posted 7 years 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: Anonymous User

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
Anonymous User
Anonymous User
Posted 7 years ago
POSTED BY: Anonymous User

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.

Anonymous User
Anonymous User
Posted 7 years ago
POSTED BY: Anonymous User
Anonymous User
Anonymous User
Posted 7 years 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: Anonymous User

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.

Anonymous User
Anonymous User
Posted 7 years 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: Anonymous User
POSTED BY: Neil Singer
Anonymous User
Anonymous User
Posted 7 years 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: Anonymous User

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

POSTED BY: Michael Rogers
Anonymous User
Anonymous User
Posted 7 years 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: Anonymous User
Anonymous User
Anonymous User
Posted 7 years 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: Anonymous User
Anonymous User
Anonymous User
Posted 7 years ago

"use the install menu item"

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

POSTED BY: Anonymous User
Anonymous User
Anonymous User
Posted 7 years 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: Anonymous User
Anonymous User
Anonymous User
Posted 7 years 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: Anonymous User
Anonymous User
Anonymous User
Posted 7 years 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: Anonymous User
Anonymous User
Anonymous User
Posted 7 years 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: Anonymous User
Anonymous User
Anonymous User
Posted 7 years ago
POSTED BY: Anonymous User

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
Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
Attachments
Remove
or Discard

Group Abstract Group Abstract