# Parens for Polyglot

**This notebook is a port of ****Gigasquids "Parens for Polyglot"**** blog post, ported with her permission.**

libpython-clj has opened the door for Clojure to directly interop with Python libraries. That means we can take just about any Python library and directly use it in our Clojure REPL. But what about matplotlib?

Matplotlib.pyplot is a standard fixture in most tutorials and python data science code. How do we interop with a python graphics library?

First, set up the Clojure and Python environment:

`{:deps`

` {org.clojure/clojure {:mvn/version "1.10.1"}`

` cnuernber/libpython-clj {:mvn/version "1.32"}}}`

`pip3 install numpy`

`pip3 install matplotlib`

`pip3 install pillow`

## How do you interop?

It turns out that matplotlib has a headless mode where we can export the graphics and then display it using any method that we would normally use to display a .png file. In my case, I made a quick macro for it using the shell `open`

. I’m sure that someone out that could improve upon it, (and maybe even make it a cool utility lib), but it suits what I’m doing so far:

`(ns gigasquid.plot`

` (:require [libpython-clj.require :refer [require-python]]`

` [libpython-clj.python :as py :refer [py. py.. py.-]]`

` [clojure.java.shell :as sh]))`

`;;; This uses the headless version of matplotlib to generate a graph then copy it to the JVM`

`;; where we can then print it`

`;;;; have to set the headless mode before requiring pyplot`

`(def mplt (py/import-module "matplotlib"))`

`(py. mplt "use" "Agg")`

`(require-python matplotlib.pyplot)`

`(require-python matplotlib.backends.backend_agg)`

`(require-python numpy)`

`(defmacro with-show`

` "Takes forms with mathplotlib.pyplot to then show locally"`

` [& body]`

` (let [_# (matplotlib.pyplot/clf)`

` fig# (matplotlib.pyplot/figure)`

` agg-canvas# (matplotlib.backends.backend_agg/FigureCanvasAgg fig#)]`

` (cons do body)`

` (py. agg-canvas# "draw")`

` (matplotlib.pyplot/savefig (str "results/" gensym ".png"))))`

## Parens for Pyplot!

Now that we have our wrapper let’s take it for a spin. We’ll be following along more or less this tutorial for numpy plotting

`(ns gigasquid.numpy-plot`

` (:require [libpython-clj.require :refer [require-python]]`

` [libpython-clj.python :as py :refer [py. py.. py.-]]`

` [gigasquid.plot :as plot]))`

` `

The `plot`

namespace contains the macro for `with-show`

above. The `py.`

and others is the new and improved syntax for interop.

#### Simple Sin and Cos

Let’s start off with a simple sine and cosine functions. This code will create a `x`

numpy vector of a range from 0 to `3 * pi`

in 0.1 increments and then create `y`

numpy vector of the `sin`

of that and plot it

`(let [x (numpy/arange 0 (* 3 numpy/pi) 0.1)`

` y (numpy/sin x)]`

` (plot/with-show`

` (matplotlib.pyplot/plot x y)))`

Beautiful yes!

Let’s get a bit more complicated now and and plot both the sin and cosine as well as add labels, title, and legend.

`(let [x (numpy/arange 0 (* 3 numpy/pi) 0.1)`

` y-sin (numpy/sin x)`

` y-cos (numpy/cos x)]`

` (plot/with-show`

` (matplotlib.pyplot/plot x y-sin)`

` (matplotlib.pyplot/plot x y-cos)`

` (matplotlib.pyplot/xlabel "x axis label")`

` (matplotlib.pyplot/ylabel "y axis label")`

` (matplotlib.pyplot/title "Sine and Cosine")`

` (matplotlib.pyplot/legend ["Sine" "Cosine"])))`

We can also add subplots. Subplots are when you divide the plots into different portions. It is a bit stateful and involves making one subplot *active* and making changes and then making the other subplot *active*. Again not too hard to do with Clojure.

`(let [x (numpy/arange 0 (* 3 numpy/pi) 0.1)`

` y-sin (numpy/sin x)`

` y-cos (numpy/cos x)]`

` (plot/with-show`

` ;;; set up a subplot gird that has a height of 2 and width of 1`

` ;; and set the first such subplot as active`

` (matplotlib.pyplot/subplot 2 1 1)`

` (matplotlib.pyplot/plot x y-sin)`

` (matplotlib.pyplot/title "Sine")`

` ;;; set the second subplot as active and make the second plot`

` (matplotlib.pyplot/subplot 2 1 2)`

` (matplotlib.pyplot/plot x y-cos)`

` (matplotlib.pyplot/title "Cosine")))`

#### Plotting with Images

Pyplot also has functions for working directly with images as well. Here we take a picture of a cat and create another version of it that is tinted.

`(let [img (matplotlib.pyplot/imread cat.jpeg)`

` img-tinted (numpy/multiply img [1 0.95 0.9])]`

` (plot/with-show`

` (matplotlib.pyplot/subplot 1 2 1)`

` (matplotlib.pyplot/imshow img)`

` (matplotlib.pyplot/subplot 1 2 2)`

` (matplotlib.pyplot/imshow (numpy/uint8 img-tinted))))`

#### Pie charts

Finally, we can show how to do a pie chart. I asked people in a twitter thread what they wanted an example of in python interop and one of them was a pie chart. This is for you!

The original code for this example came from this tutorial.

`(let [labels ["Frogs" "Hogs" "Dogs" "Logs"]`

` sizes [15 30 45 10]`

` explode [0 0.1 0 0]] ; only explode the 2nd slice (Hogs)`

` `

` (plot/with-show`

` (let [[fig1 ax1] (matplotlib.pyplot/subplots)]`

` (py. ax1 "pie" sizes :explode explode :labels labels :autopct "%1.1f%%"`

` :shadow true :startangle 90)`

` (py. ax1 "axis" "equal")))) ;equal aspec ration ensures that pie is drawn as circle`

#### Onwards and Upwards!

This is just the beginning. In upcoming posts, I will be showcasing examples of interop with different libraries from the python ecosystem. Part of the goal is to get people used to how to use interop but also to raise awareness of the capabilities of the python libraries out there right now since they have been historically out of our ecosystem.

If you have any libraries that you would like examples of, I’m taking requests. Feel free to leave them in the comments of the blog or in the twitter thread.

Until next time, happy interoping!

PS All the code examples are here https://github.com/gigasquid/libpython-clj-examples