## Using Matplotlib in Perl 6 (part 3)

2017-03-06

This is Part 3 in a series. You can start at the Intro here.

So far this Perl 6 wrapper class for Matplotlib is going well. With the first graph in the gallery under my belt, I moved on to second example, `fill_demo.py`. Here's the Python code

```import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(0, 1, 500)
y = np.sin(4 * np.pi * x) * np.exp(-5 * x)

fig, ax = plt.subplots()

ax.fill(x, y, zorder=10)
ax.grid(True, zorder=5)
plt.show()
```

Being a rather simple graph, you might think that the Perl code would be fairly straight forward, and you'd be right. The only minor curveball is another Numpy function `linspace`, and that rather hairy looking operation for the `y` value.

To reiterate what I've said in previous parts, I'm not familiar with Numpy at all. Or at least, I wasn't before I started working on these graphs. I inserted a `print(x)` into the Python code to see what `linspace` did. In hindsight, the name is obvious; It simply creates a linearly spaced sequence of numbers. Here's a quick demonstration

```>>> numpy.linspace(0, 1, 3)
array([ 0. ,  0.5,  1. ])
>>> numpy.linspace(0, 1, 5)
array([ 0.  ,  0.25,  0.5 ,  0.75,  1.  ])
>>> numpy.linspace(0, 1, 6)
array([ 0. ,  0.2,  0.4,  0.6,  0.8,  1. ])
```

In the case of `x` in the graph, it's a sequence of 500 numbers evenly spaced from 0 to 1. So how would I do this in Perl. It is a monotonic sequence, so maybe the Sequence operator can help us again. So far we've seen a couple simple Sequences. The most simple sequence defines the start of a number series, and Perl lazily generates the rest.

```> 0, 2, 4, 8 ... 1024
(0 2 4 8 16 32 64 128 256 512 1024)
```

This is nice and all, but I had to define 4 numbers for Perl to understand that sequence. If I dropped the `8`, then it would have generated a sequence of even numbers. Instead, I can define a function which calculates how the next value should be generated.

```> 0, 2, * × 2 ... 1024
(0 2 4 8 16 32 64 128 256 512 1024)
```

Here we see our old friend, the Whatever `*`. This time I'm asking for the Sequence starting `0, 2`, then I define a mini-function that takes Whatever the last number in the Sequence was and multiplies it by 2. Sequences are a fascinating part of Perl 6 that could occupy a blog post all their own, but for now, that's enough of a foundation to create a simplified `linspace` function.

```sub linspace(\$start, \$end, \$steps) {
my \$step = (\$end - \$start) ÷ (\$steps - 1);
return \$start, * + \$step ... \$end;
}

linspace(0, 1, 3); # Result: (0, 0.5, 1)
linspace(0, 1, 5); # Result: (0, 0.25, 0.5, 0.75, 1)
linspace(0, 1, 6); # Result: (0, 0.2, 0.4, 0.6, 0.8, 1)
```

This function does what I need, but it could stand to be a little more robust. I'll make a module to house this function, just in case I need it for future plots. I'll also add type constraints to the parameters, and multiple dispatch functions to handle steps of 0 or 1. I'm calling my library `Numpl`. Any resemblance to actual libraries is purely coincidental.

```class Numpl {
proto method linspace(Real \$start, Real \$end, Int \$steps) { * }
multi method linspace(\$start, \$end, 0) { Empty }
multi method linspace(\$start, \$end, 1) { \$start }
multi method linspace(\$start, \$end, Int \$steps) {
my \$step = (\$end - \$start) ÷ (\$steps - 1);
return \$start, * + \$step ... \$end
}
}
```

So that was a very scenic tour around the Sequence operator, but now that we have a `linspace` function, the rest is smooth sailing. Getting back to the plot, the final code now looks like this.

```use Matplotlib;
use Numpl;

my \$plt = Matplotlib.new;

my @x = Numpl.linspace(0, 1, 500);
my @y = @x.map(-> \$x {
sin(4 × π × \$x) × exp(-5 × \$x)
});

my (\$fig, \$ax) = \$plt.subplots();

\$ax.fill(\$@x, \$@y, :zorder(10));
\$ax.grid(True, :zorder(5));
\$plt.show();
```

Oh yeah, there was that hairy looking operation for the `y` values. To refresh your memory, the python looked like this

```y = np.sin(4 * np.pi * x) * np.exp(-5 * x)
```

I can pretty much copy this operation exactly as it appears and put it inside the map. I've put the map operation on it's own line as I think this aids readability.

You might have also noticed I'm using proper `@arrays` in this one, and there is a valid reason for this. Sequences are lazy, and typically can only be iterated over once. `x` is iterated over in the map and that would prevent any later iterations. Here I've assigned the Sequence to a fully reified Array, which also means the Sequence is evaluated eagerly at assignment (ie. not lazily). As covered in part 2, Python doesn't like Perl arrays as positional arguments, so I coerce them to scalar values when I pass them.

The other way I could have handled this was to coerce my Sequence to a List on assignment like so.

```my \$x = Numpl.linspace(0, 1, 500).List;
```

Then I could have assigned it to a scalar variable and still be free to iterate over it as many times as I like. If you have no need for laziness from your `linspace` function, you could modify it to return a reified List either coercing the return value as above, or by instructing the Sequence to be eagerly evaluated.

```return (\$start, * + \$step ... \$end).List
# or
return eager \$start, * + \$step ... \$end
```

But I like to be able to control the laziness of my `linspace` result from outside the function.

Whichever way you do it, the end result should look like this

The wrapper module is working out well... a little too well. I wanted to tackle something a little more complex, and scrolling through the Matplotlib gallery I saw it. It's high time for a histogram.

To be continued...