After the previous recipe, we should be able to execute Mathematica functions from Clojure. We'll also need to send data to Mathematica so that there's something to call those functions on.
You must first have Clojuratica and Mathematica talking to each other. Either complete the Setting up Mathematica to Talk to Clojuratica for Mac OS X and Linux recipe or the Setting up Mathematica to Talk to Clojuratica for Windows recipe. Also, you'll need to have called the init-mma
function.
You'll also need to have Incanter listed in the dependencies in your project.clj
file:
(defproject interop "0.1.0-SNAPSHOT" :description "" :dependencies [[org.clojure/clojure "1.6.0"] [incanter "1.5.5"] [local.repo/JLink "9.0"] [local.repo/clojuratica "2.0"]] :source-paths ["src" "Clojuratica/src/clj"] :resource-paths ["src/main/resource" "/Applications/Mathematica.app/SystemFiles/Links/JLink"])
Moreover, you'll require those namespaces in your script or REPL:
(use 'clojuratica) (require '[incanter.core :as i] 'incanter.io)
Finally, we'll use the dataset of racial census data that we compiled for the Grouping data with $group-by recipe in Chapter 6, Working with Incanter DataSets. We'll bind the filename to the name data-file
. You can download this from http://www.ericrochester.com/clj-data-analysis/data/all_160.P3.csv.
(def data-file "data/all_160.P3.csv")
In this recipe, we'll load some data into Clojure, define a couple of wrapper functions that call functions defined in Mathematica, and then we'll apply those functions to our Incanter dataset, as shown here:
(def data (incanter.io/read-dataset data-file :header true))
Mean
and Median
functions:(defn mma-mean [dataset col] (math (Mean ~(i/sel dataset :cols col)))) (defn mma-median [dataset col] (math (Median ~(i/sel dataset :cols col))))
user=> (mma-mean data :POP100) 230766493/29439 user=> (mma-median data :POP100) 1081
There's one important point to note about this recipe.
~(i/sel dataset :cols col)
The code that calls Mathematica can't call back out to evaluate expressions that we pass it, so we have to do it ourselves first. If we stick a quasi-quote expander to expressions, then Clojure makes the i/sel
call and interpolates the results into the body of the function.