Plotting a 2D iso-probability curve

I have a library function that returns a pair of two numbers like this

def library_function(x0, x1):
return x0**2 + x1**2, 10*x0*x1 + 1


(Actually, it is a function that returns predicted probabilities of two classes for some object, but it doesn't matter, so I created an artificial one.) I want to draw contours where the difference between two numbers returned by library_function is zero. To do so, I have to create a two-dimensional list (or array) with the differences.

I have the following possibilities:

X0 = np.linspace(-10, 10, 200)
X1 = np.linspace(-10, 10, 200)

results = [[(lambda u: u[0]-u[1])(library_function(x0, x1))
for x0 in X0] for x1 in X1]
plt.contour(X0, X1, results, [0])


This approach is concise but I have to introduce lambda which seem to be considered not so Pythonic.

Another way:

values = [[library_function(x0, x1) for x0 in X0] for x1 in X1]
results = [[a-b for a, b in row] for row in values]


I have to introduce temporary two-dimensional list and this approach is longer.

Are there any ideas how to do it better (more concise and readable)?

• Why must you have a single library_function that returns a pair? Perhaps it would be better as two functions? I think I would like to see what your real library_function is. Nov 24, 2016 at 23:57
• It's pybrain's .activate() method. It returns a predicted vector. I use it as two-class classifier and my output space is two-dimensional, and I'd like to draw a border between two classes, so I have to calculate the difference between the plausibilities returned by the function activate() and compare it with 0. (Oh, I just discovered that I can just use the first component and compare it with 1/2, which will work if my outputs are probabilites…) Nov 25, 2016 at 0:03

Since you are using NumPy, you should deal with grids the NumPy way instead of performing list comprehensions.

def probability_diff(x0, x1):
probs = library_function(x0, x1)
return probs[0] - probs[1]

results = np.vectorize(probability_diff)(X0[:, np.newaxis], X1)


I wouldn't try to get too clever with the lambdas.

Also, since the grid happens to be a square, you could use X0 again instead of defining X1.

• Good point about np.vectorize, didn't know about it, and a good reference to SO answer. Nov 26, 2016 at 14:48

I think using list comprehensions is generally considered Pythonic. As an improvement, you can opt to use generators for your values variable.

values = ((library_function(x0, x1) for x0 in X0) for x1 in X1)
results = [[a-b for a, b in row] for row in values]


By using a generator, you're using a constant amount of space for the values variable. I also think that using more descriptive variable names would be helpful.