2 Image Processing

In this section, we study how to embed images created by Matplotlib, Bokeh, and HoloViews libraries.

2.1 Matplotlib

First, figsize of figure is set to [2, 1.6] to show small figures for saving space.

import matplotlib
import matplotlib.pyplot as plt
matplotlib.rcParams['figure.figsize'] = [2, 1.6]

A call of plt.plot generates a standard plain text output (a list of Line object in this example) and a PNG image as display data:

plt.plot([1, 3, 5], marker='o')
[<matplotlib.lines.Line2D at 0x27cca91b400>]

image/png

If you want to hide the input source and the plain text output, you can use a display option to show just the display data such as an image or HTML:

```python display
plt.plot([4, 2, 3], marker='o')
```

image/png

"Inline code" is useful to display a plot in shorthand notation. {{plt.plot([1, 2, 4])}} generates:

image/png

Note that the plain text output ([<matplotlib.lines...]) does not displayed if the inline code generates display data.

An inline code statement ({{<expr>}}) can be written in a fenced code block. In this case, the expression in the statement is evaluated dynamically during the evaluation of the fenced code block.

In the next example, two plots are overlayed. axes[0] and axes[1] refer to the same image object.

axes = []
for k, color in enumerate(['red', 'blue']):
  plt.plot([1, k + 3], color)
  axes.append(plt.gca())
axes
[<matplotlib.axes._subplots.AxesSubplot at 0x27cca9bba58>,
 <matplotlib.axes._subplots.AxesSubplot at 0x27cca9bba58>]

image/png

You can use the inline code to get different images at the every evaluation time while the iteration is going. You have to call plt.cla() method to continuously clear the previous plot.

```python hide inline
axes = []
for k, color in enumerate(['red', 'blue']):
    plt.plot([0, k + 3], color)
    axes.append({{plt.gca()}})
    plt.cla()
```

Here, hide option disables the output of plot from the fenced code block, which we don't need now.

Check the type of elements of the variable axes.

[type(ax) for ax in axes]
[str, str]

They are str objects, not any Matplotlib objects. Actually, their content is a base64-encoded markdown image source:

axes[0][:50]
'![png](data:image/png;base64,iVBORw0KGgoAAAANSUhEU'

Thanks to this Pheasant feature, you can put images anywhere. For example, in a table:

#Tab A Markdown table with Matplotlib plot
~~~
|Red         |Blue       |
|------------|-----------|
|{{axes[0]}} |{{axes[1]}}|
~~~

Table 2.4 A Markdown table with Matplotlib plot

Red Blue
png png

Herer, a fenced code is required because {{axes[0]}} and {{axes[1]}} are not normal Markdown sources.

If you prefer a Pandas DataFrame, HTML-type inline code can be used with {{^ and }} which return an IPython HTML object. So you can use the data attribute to get a HTML string.

```python hide inline
axes = []
for k, color in enumerate(['red', 'blue']):
    plt.plot([0, k + 3], color)
    axes.append({{^plt.gca()}}.data)
    plt.cla()
```

Then,

#Tab A Pandas DataFrame with a Matplotlib plot
```python display
import pandas as pd
pd.DataFrame([axes], columns=['Red', 'Blue'])
```

Table 2.5 A Pandas DataFrame with a Matplotlib plot

Red Blue
0 png png

2.2 Bokeh

You can embed Bokeh's plots into MkDocs HTML documents. Following User Guide "Embedding Plots and Apps" from the official Bokeh documents, Pheasant automatically adds extra stylesheet and javascript in HTML <head> tag. You don't need to configure extra_css and extra_javascript in your mkdocs.yml manually.

In order to embed plots in your document, bokeh.embed.components function can be used. This function returns <script> and <div> tags in HTML format. For example:

from bokeh.plotting import figure
from bokeh.embed import components

plot = figure(plot_width=250, plot_height=250)
plot.circle([1, 2, 3, 4, 5], [1, 3, 0, 2, 4], size=10)
script, div = components(plot)
print('[script]:', script[:140].strip(), '...')
print('[div]:', div[:40].strip(), '...')
[script]: <script type="text/javascript">
  (function() {
    var fn = function() {
      Bokeh.safely(function() {
        (function(root) { ...
[div]: <div class="bk-root" id="00460fba-9032- ...

Pheasant uses this functionality inside automatically. You can get a Bokeh plot just write {{plot}}:

2.3 HoloViews

HoloViews provides an explorable multi-dimensional dictionary of HoloViews objects called HoloMap. Pheasant can also embed this interactive object in your MkDocs Documents as well as other HoloViews objects.

First, a normal HoloViews object.

```python
import holoviews as hv
curve = hv.Curve(([1, 2, 3], [2, 3, 1]))
curve
```
import holoviews as hv
curve = hv.Curve(([1, 2, 3], [2, 3, 1]))
curve
:Curve   [x]   (y)
type(curve)
holoviews.element.chart.Curve

As you can see, HoloView's Curve object doesn't supply any visual representation. To get a HTML source to visualize it, we have to render the object.

renderer = hv.renderer('bokeh')
html = renderer.html(curve)
print(html[:40], '...')
<div style='display: table; margin: 0 au ...

Extra assets which should be written in a HTML source to display the image are provided by the renderer's class method: html_assets().

js_html, css_html = renderer.html_assets()
print(js_html.strip()[:50])
<script src="https://cdn.pydata.org/bokeh/release/
print(css_html.strip()[:50])
<link rel="stylesheet" href="https://cdn.pydata.or

The above process to display a HTML image from a HoloViews object can be done by just an inline code like this.

{{curve}}

Showing a HoloMap is straightforward. From HoloViews's official documents,

import numpy as np
frequencies = [0.5, 0.75, 1.0, 1.25]

def sine_curve(phase, freq):
    xvals = [0.1* i for i in range(100)]
    return hv.Curve((xvals, [np.sin(phase+freq*x) for x in xvals]))

curve_dict = {f:sine_curve(0,f) for f in frequencies}
hmap = hv.HoloMap(curve_dict, kdims='frequency')
{{hmap}}
phases = [0, np.pi/2, np.pi, 3*np.pi/2]
curve_dict_2D = {(p,f):sine_curve(p,f) for p in phases for f in frequencies}
hmap = hv.HoloMap(curve_dict_2D, kdims=['phase', 'frequency'])
{{hmap}}