forked from sheetjs/docs.sheetjs.com
		
	Mathematica Extension demo refresh
This commit is contained in:
		
							parent
							
								
									5f443931f8
								
							
						
					
					
						commit
						67294eeeae
					
				| @ -25,7 +25,12 @@ data from opaque spreadsheets and parse the data from Mathematica. | ||||
| 
 | ||||
| :::note Tested Deployments | ||||
| 
 | ||||
| This demo was last tested by SheetJS users on 2023 November 04 in Mathematica 13. | ||||
| This demo was tested by SheetJS users in the following deployments: | ||||
| 
 | ||||
| | Architecture | Version | Date       | | ||||
| |:-------------|:--------|:-----------| | ||||
| | `darwin-x64` | `14.0`  | 2024-06-05 | | ||||
| | `win10-x64`  | `14.0`  | 2024-06-05 | | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| @ -81,7 +86,7 @@ Dataset object assuming one header row. | ||||
| <Tabs groupId="os"> | ||||
|   <TabItem value="unix" label="Linux/MacOS"> | ||||
| 
 | ||||
| ```mathematica title="Complete Function" | ||||
| ```mathematica title="SheetJSImportFileEE" | ||||
| (* Import file stored in the Documents folder (e.g. C:\Users\Me\Documents) *) | ||||
| SheetJSImportFileEE[filename_]:=Module[{csv}, ( | ||||
|   (* This was required in local testing *) | ||||
| @ -107,7 +112,7 @@ SheetJSImportFileEE[filename_]:=Module[{csv}, ( | ||||
|   </TabItem> | ||||
|   <TabItem value="win" label="Windows"> | ||||
| 
 | ||||
| ```mathematica title="Complete Function" | ||||
| ```mathematica title="SheetJSImportFileEE" | ||||
| (* Import file stored in the Documents folder (e.g. C:\Users\Me\Documents) *) | ||||
| SheetJSImportFileEE[filename_]:=Module[{csv}, ( | ||||
|   (* This was required in local testing *) | ||||
| @ -133,70 +138,6 @@ SheetJSImportFileEE[filename_]:=Module[{csv}, ( | ||||
|   </TabItem> | ||||
| </Tabs> | ||||
| 
 | ||||
| <details open> | ||||
|   <summary><b>How to run the example</b> (click to hide)</summary> | ||||
| 
 | ||||
| :::note Tested Deployments | ||||
| 
 | ||||
| This example was last tested on 2023 November 04 with Mathematica 13.3. | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| 0) Install NodeJS. When the demo was tested, version `20.9.0` was installed. | ||||
| 
 | ||||
| 1) Install dependencies in the Home folder (`~` or `$HOME` or `%HOMEPATH%`): | ||||
| 
 | ||||
| <CodeBlock language="bash">{`\ | ||||
| npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz zeromq@6.0.0-beta.17`} | ||||
| </CodeBlock> | ||||
| 
 | ||||
| 2) Open a new Mathematica Notebook and register NodeJS. When the example was | ||||
| tested in Windows, the commands were: | ||||
| 
 | ||||
| <Tabs groupId="os"> | ||||
|   <TabItem value="unix" label="Linux/MacOS"> | ||||
| 
 | ||||
| ```mathematica | ||||
| RegisterExternalEvaluator["NodeJS","/usr/local/bin/node"] | ||||
| FindExternalEvaluators["NodeJS"] | ||||
| ``` | ||||
| 
 | ||||
|   </TabItem> | ||||
|   <TabItem value="win" label="Windows"> | ||||
| 
 | ||||
| ```mathematica | ||||
| RegisterExternalEvaluator["NodeJS","C:\\Program Files\\nodejs\\node.exe"] | ||||
| FindExternalEvaluators["NodeJS"] | ||||
| ``` | ||||
| 
 | ||||
|   </TabItem> | ||||
| </Tabs> | ||||
| 
 | ||||
| The second argument to `RegisterExternalEvaluator` should be the path to the | ||||
| `node` or `node.exe` binary. | ||||
| 
 | ||||
| If NodeJS is registered, the value in the "Registered" column will be "True". | ||||
| 
 | ||||
| 4) To determine the base folder, run `require("process").cwd()` from NodeJS: | ||||
| 
 | ||||
| ```mathematica | ||||
| ExternalEvaluate["NodeJS", "require('process').cwd()"] | ||||
| ``` | ||||
| 
 | ||||
| 5) Download [`pres.numbers`](https://docs.sheetjs.com/pres.numbers) and move | ||||
| the file to the base folder as shown in the previous step. | ||||
| 
 | ||||
| 6) Copy and evaluate the "Complete Function" in the previous codeblock. | ||||
| 
 | ||||
| 7) Run the function and confirm the result is a proper Dataset: | ||||
| 
 | ||||
| ```mathematica | ||||
| SheetJSImportFileEE["pres.numbers"] | ||||
| ``` | ||||
| 
 | ||||
|  | ||||
| 
 | ||||
| </details> | ||||
| 
 | ||||
| ### Command-Line Tools | ||||
| 
 | ||||
| @ -236,31 +177,177 @@ flowchart LR | ||||
| 
 | ||||
| ## Complete Demo | ||||
| 
 | ||||
| 1) Create the standalone `xlsx-cli` binary[^14]: | ||||
| This demo tests the NodeJS external engine and dedicated command line tools. | ||||
| 
 | ||||
| ### NodeJS Engine | ||||
| 
 | ||||
| 0) Install NodeJS. When the demo was tested, version `20.14.0` was installed. | ||||
| 
 | ||||
| 1) Install dependencies in the Home folder (`~` or `$HOME` or `%HOMEPATH%`): | ||||
| 
 | ||||
| <CodeBlock language="bash">{`\ | ||||
| npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz zeromq@6.0.0-beta.19`} | ||||
| </CodeBlock> | ||||
| 
 | ||||
| 2) Open a new Mathematica Notebook and register NodeJS. When the example was | ||||
| tested in Windows, the commands were: | ||||
| 
 | ||||
| <Tabs groupId="os"> | ||||
|   <TabItem value="unix" label="Linux/MacOS"> | ||||
| 
 | ||||
| ```mathematica | ||||
| RegisterExternalEvaluator["NodeJS","/usr/local/bin/node"] | ||||
| FindExternalEvaluators["NodeJS"] | ||||
| ``` | ||||
| 
 | ||||
| The second argument to `RegisterExternalEvaluator` should be the path to the | ||||
| `node` program, which can be found by running the following command in a new | ||||
| terminal window: | ||||
| 
 | ||||
| ```bash | ||||
| which node | ||||
| ``` | ||||
| 
 | ||||
|   </TabItem> | ||||
|   <TabItem value="win" label="Windows"> | ||||
| 
 | ||||
| ```mathematica | ||||
| RegisterExternalEvaluator["NodeJS","C:\\Program Files\\nodejs\\node.exe"] | ||||
| FindExternalEvaluators["NodeJS"] | ||||
| ``` | ||||
| 
 | ||||
| The second argument to `RegisterExternalEvaluator` should be the path to the | ||||
| `node.exe` program, which can be found by running the following command in a new | ||||
| PowerShell window: | ||||
| 
 | ||||
| ```powershell | ||||
| Get-Command node.exe | ||||
| ``` | ||||
| 
 | ||||
|   </TabItem> | ||||
| </Tabs> | ||||
| 
 | ||||
| If NodeJS is registered, the value in the "Registered" column will be "True". | ||||
| 
 | ||||
| 4) To determine the base folder, run `require("process").cwd()` from NodeJS: | ||||
| 
 | ||||
| ```mathematica | ||||
| ExternalEvaluate["NodeJS", "require('process').cwd()"] | ||||
| ``` | ||||
| 
 | ||||
| 5) Download [`pres.numbers`](https://docs.sheetjs.com/pres.numbers) and move | ||||
| the file to the base folder as shown in the previous step. | ||||
| 
 | ||||
| 3) Copy, but do not run, the following snippet into the running notebook: | ||||
| 
 | ||||
| <Tabs groupId="os"> | ||||
|   <TabItem value="unix" label="Linux/MacOS"> | ||||
| 
 | ||||
| ```mathematica title="SheetJSImportFileEE" | ||||
| (* Import file stored in the Documents folder (e.g. C:\Users\Me\Documents) *) | ||||
| SheetJSImportFileEE[filename_]:=Module[{csv}, ( | ||||
|   (* This was required in local testing *) | ||||
|   /* highlight-next-line */ | ||||
|   RegisterExternalEvaluator["NodeJS","/usr/local/bin/node"]; | ||||
| 
 | ||||
|   (* Generate CSV from first sheet *) | ||||
|   csv:=ExternalEvaluate["NodeJS", StringJoin[ | ||||
|     (* module installed in home directory *) | ||||
|     "var XLSX = require('xlsx');", | ||||
|     (* read specified filename *) | ||||
|     "var wb = XLSX.readFile('",filename,"');", | ||||
|     (* grab first worksheet *) | ||||
|     "var ws = wb.Sheets[wb.SheetNames[0]];", | ||||
|     (* convert to CSV *) | ||||
|     "XLSX.utils.sheet_to_csv(ws)" | ||||
|   ]]; | ||||
| 
 | ||||
|   (* Parse CSV into a dataset *) | ||||
|   Return[ImportString[csv, "Dataset", "HeaderLines"->1]]; | ||||
| )] | ||||
| ``` | ||||
| 
 | ||||
|   </TabItem> | ||||
|   <TabItem value="win" label="Windows"> | ||||
| 
 | ||||
| ```mathematica title="SheetJSImportFileEE" | ||||
| (* Import file stored in the Documents folder (e.g. C:\Users\Me\Documents) *) | ||||
| SheetJSImportFileEE[filename_]:=Module[{csv}, ( | ||||
|   (* This was required in local testing *) | ||||
|   /* highlight-next-line */ | ||||
|   RegisterExternalEvaluator["NodeJS","C:\\Program Files\\nodejs\\node.exe"]; | ||||
| 
 | ||||
|   (* Generate CSV from first sheet *) | ||||
|   csv:=ExternalEvaluate["NodeJS", StringJoin[ | ||||
|     (* module installed in home directory *) | ||||
|     "var XLSX = require('xlsx');", | ||||
|     (* read specified filename *) | ||||
|     "var wb = XLSX.readFile('",filename,"');", | ||||
|     (* grab first worksheet *) | ||||
|     "var ws = wb.Sheets[wb.SheetNames[0]];", | ||||
|     (* convert to CSV *) | ||||
|     "XLSX.utils.sheet_to_csv(ws)" | ||||
|   ]]; | ||||
| 
 | ||||
|   (* Parse CSV into a dataset *) | ||||
|   Return[ImportString[csv, "Dataset", "HeaderLines"->1]]; | ||||
| )] | ||||
| ``` | ||||
| 
 | ||||
|   </TabItem> | ||||
| </Tabs> | ||||
| 
 | ||||
| After pasting, edit the highlighted line to reflect the path of the `node` or | ||||
| `node.exe` binary. This path was discovered in Step 2. | ||||
| 
 | ||||
| After editing the snippet, run the expression. | ||||
| 
 | ||||
| 7) Run the function and confirm the result is a proper Dataset: | ||||
| 
 | ||||
| ```mathematica | ||||
| SheetJSImportFileEE["pres.numbers"] | ||||
| ``` | ||||
| 
 | ||||
|  | ||||
| 
 | ||||
| ### Standalone Binary | ||||
| 
 | ||||
| 8) Create the standalone `xlsx-cli` binary[^14]. The commands should be run in a | ||||
| Terminal or PowerShell window: | ||||
| 
 | ||||
| <CodeBlock language="bash">{`\ | ||||
| npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz exit-on-epipe commander@2 | ||||
| curl -LO https://docs.sheetjs.com/cli/xlsx-cli.js | ||||
| npx nexe -t 14.15.3 xlsx-cli.js`} | ||||
| npx -y nexe -t 14.15.3 xlsx-cli.js`} | ||||
| </CodeBlock> | ||||
| 
 | ||||
| <Tabs groupId="os"> | ||||
|   <TabItem value="unix" label="Linux/MacOS"> | ||||
| 
 | ||||
| 2) Move the generated `xlsx-cli` to a fixed location in `/usr/local/bin`: | ||||
| 9) Move the generated `xlsx-cli` to a fixed location in `/usr/local/bin`: | ||||
| 
 | ||||
| ```bash | ||||
| mkdir -p /usr/local/bin | ||||
| mv xlsx-cli /usr/local/bin/ | ||||
| ``` | ||||
| 
 | ||||
| :::note pass | ||||
| 
 | ||||
| If there are permission errors, the command should be run with the root user: | ||||
| 
 | ||||
| ```bash | ||||
| sudo mv xlsx-cli /usr/local/bin/ | ||||
| ``` | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
|   </TabItem> | ||||
|   <TabItem value="win" label="Windows"> | ||||
| 
 | ||||
| 2) Find the current directory: | ||||
| 9) Find the current directory: | ||||
| 
 | ||||
| ```bash | ||||
| cd | ||||
| pwd | ||||
| ``` | ||||
| 
 | ||||
| The generated binary will be `xlsx-cli.exe` in the displayed path. | ||||
| @ -270,9 +357,12 @@ The generated binary will be `xlsx-cli.exe` in the displayed path. | ||||
| 
 | ||||
| ### Reading a Local File | ||||
| 
 | ||||
| 3) In a new Mathematica notebook, run the following snippet: | ||||
| <Tabs groupId="os"> | ||||
|   <TabItem value="unix" label="Linux/MacOS"> | ||||
| 
 | ||||
| ```mathematica | ||||
| 10) In a new Mathematica notebook, run the following snippet: | ||||
| 
 | ||||
| ```mathematica title="SheetJSImportFile" | ||||
| SheetJSImportFile[x_] := ImportString[Block[{Print}, ExternalEvaluate[ | ||||
|   "Shell" -> "StandardOutput", | ||||
|   // highlight-next-line | ||||
| @ -280,17 +370,24 @@ SheetJSImportFile[x_] := ImportString[Block[{Print}, ExternalEvaluate[ | ||||
| ]], "Dataset", "HeaderLines" -> 1] | ||||
| ``` | ||||
| 
 | ||||
| <Tabs groupId="os"> | ||||
|   <TabItem value="unix" label="Linux/MacOS"> | ||||
| 
 | ||||
|   </TabItem> | ||||
|   <TabItem value="win" label="Windows"> | ||||
| 
 | ||||
| 10) In a new Mathematica notebook, copy but do not run the following snippet: | ||||
| 
 | ||||
| ```mathematica title="SheetJSImportFile" | ||||
| SheetJSImportFile[x_] := ImportString[Block[{Print}, ExternalEvaluate[ | ||||
|   "Shell" -> "StandardOutput", | ||||
|   // highlight-next-line | ||||
|   "/usr/local/bin/xlsx-cli " <> x | ||||
| ]], "Dataset", "HeaderLines" -> 1] | ||||
| ``` | ||||
| 
 | ||||
| Change `/usr/local/bin/xlsx-cli` in the string to the path to the generated | ||||
| `xlsx-cli.exe` binary. For example, if the path in step 2 was | ||||
| `C:\Users\Me\Documents\`, then the code should be: | ||||
| 
 | ||||
| ```mathematica | ||||
| ```mathematica title="SheetJSImportFile" | ||||
| SheetJSImportFile[x_] := ImportString[Block[{Print}, ExternalEvaluate[ | ||||
|   "Shell" -> "StandardOutput", | ||||
|   // highlight-next-line | ||||
| @ -298,25 +395,58 @@ SheetJSImportFile[x_] := ImportString[Block[{Print}, ExternalEvaluate[ | ||||
| ]], "Dataset", "HeaderLines" -> 1] | ||||
| ``` | ||||
| 
 | ||||
| The `\` characters must be doubled. | ||||
| :::info pass | ||||
| 
 | ||||
| Mathematica requires the `\` characters must be doubled. | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| After making the change, run the snippet. | ||||
| 
 | ||||
|   </TabItem> | ||||
| </Tabs> | ||||
| 
 | ||||
| 4) Download https://docs.sheetjs.com/pres.numbers and save to Downloads folder: | ||||
| 11) Download https://docs.sheetjs.com/pres.numbers and save to Downloads folder: | ||||
| 
 | ||||
| ```bash | ||||
| cd ~/Downloads/ | ||||
| curl -LO https://docs.sheetjs.com/pres.numbers | ||||
| ``` | ||||
| 
 | ||||
| 5) In the Mathematica notebook, run the new function. If the file was saved to | ||||
| 12) In the Mathematica notebook, run the new function. If the file was saved to | ||||
| the Downloads folder, the path will be `"~/Downloads/pres.numbers"` in macOS: | ||||
| 
 | ||||
| <Tabs groupId="os"> | ||||
|   <TabItem value="unix" label="Linux/MacOS"> | ||||
| 
 | ||||
| ```mathematica | ||||
| data = SheetJSImportFile["~/Downloads/pres.numbers"] | ||||
| ``` | ||||
| 
 | ||||
|   </TabItem> | ||||
|   <TabItem value="win" label="Windows"> | ||||
| 
 | ||||
| On Windows, the absolute path to the file must be used. To find this path, run | ||||
| the following commands in PowerShell: | ||||
| 
 | ||||
| ```powershell | ||||
| cd $HOME\Downloads | ||||
| pwd | ||||
| ``` | ||||
| 
 | ||||
| Append `\\pres.numbers` to the displayed path. For example, if the path was | ||||
| `C:\Users\Me\Downloads`, the command will be | ||||
| 
 | ||||
| ```mathematica | ||||
| data = SheetJSImportFile["C:\\Users\\Me\\Downloads\\pres.numbers"] | ||||
| ``` | ||||
| 
 | ||||
| The `\` characters must be doubled. | ||||
| 
 | ||||
|   </TabItem> | ||||
| </Tabs> | ||||
| 
 | ||||
| 
 | ||||
| The result should be displayed in a concise table. | ||||
| 
 | ||||
|  | ||||
| @ -326,9 +456,9 @@ The result should be displayed in a concise table. | ||||
| `FetchURL`[^15] downloads a file from a specified URL and returns a path to the | ||||
| file. This function will be wrapped in a new function called `SheetJSImportURL`. | ||||
| 
 | ||||
| 6) In the same notebook, run the following: | ||||
| 13) In the same notebook, run the following: | ||||
| 
 | ||||
| ```mathematica | ||||
| ```mathematica title="SheetJSImportURL" | ||||
| Needs["Utilities`URLTools`"]; | ||||
| SheetJSImportURL[x_] := Module[{path},( | ||||
|   path = FetchURL[x]; | ||||
| @ -336,7 +466,7 @@ SheetJSImportURL[x_] := Module[{path},( | ||||
| )]; | ||||
| ``` | ||||
| 
 | ||||
| 7) Test by downloading the test file in the notebook: | ||||
| 14) Test by downloading the test file in the notebook: | ||||
| 
 | ||||
| ```mathematica | ||||
| data = SheetJSImportURL["https://docs.sheetjs.com/pres.numbers"] | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user