13

# gnuplotlib and broadcasting in numpy

Follow-up posts

I added generic broadcasting support to numpy: numpysane: a more reasonable numpy

Up to this point, a major part of PDL::Graphics::Gnuplot that was not supported in gnuplotlib was proper broadcasting ("threading" in PDL-speak) support. What is this? Suppose you have 3 1D vectors: x, y and y2, and you want to plot two curves: y vs x and y2 vs x. In gnuplotlib you can do

gp.plot( (x,y), (x,y2) )

But then you're repeating the x. It would be nicer to consolidate that. You can join y and y2 into a 2D numpy array:

gp.plot( x, np.vstack(y,y2) )

Interpreting the arguments in this way is what broadcasting is, and I just added support for this into gnuplotlib.

It would appear that this is something that PDL does much better than numpy, in general. While in PDL threading is a fundamental concept that's supported widely across the whole system, in numpy broadcasting only really exists for fundamental operations (addition, multiplication, etc). Thus numpy lacks an equivalent of thread_define, and I had to implement it myself. Note the implementation isn't pretty, but it's just complicated by nature.

Something numpy does better than PDL is the wider range of types that can live in their arrays. I can thus put strings into arrays, and use broadcasting to plot stuff with different labels and styles. This clearly requires an example. Let's plot the Conchoids of de Sluze:

import numpy as np
import gnuplotlib as gp

theta = np.linspace(0, 2*np.pi, 1000)  # dim=(  1000,)
a     = np.arange(-4,3)[:, np.newaxis] # dim=(7,1)

gp.plot( theta,
1./np.cos(theta) + a*np.cos(theta), # broadcasted. dim=(7,1000)

_with  = 'lines',
set    = 'polar',
square = True,
yrange = [-5,5],
legend = a.ravel() )

This is a plot in polar coordinates. I use broadcasting to generate a numpy array that has all the r values for all my curves in it. This array was generated by a single command. And I plot it against the one array of theta values, again in a single command. I also use broadcasting to generate labels. Generally these would be strings, and I can do that with numpy, but here just printing the numerical value of the a parameter is sufficient. The result:

Another example:

import numpy as np
import gnuplotlib as gp

x,y = np.mgrid[-10:11, -10:11]
z   = np.sqrt(x*x + y*y)
x  = x[:, 2:12]
z  = z[:, 2:12]

gp.plot((np.rollaxis( np.dstack((x,z)), 2,0),
{'tuplesize': 3,
'with': np.array(('points palette pt 7','points ps variable pt 6'))}),

square = 1)

Here the dimensions of x and z end up as (21,10). We stack them together into an array of dimensions (2,21,10). Furthermore, the with key option is also an array, but with dimension (2,) and two strings in it, indicating how each broadcast slice should be plotted. We thus plot x as a matrix with a varying color and z as a matrix with a varying point size. The result:

Works OK, and this will be very useful.