2
\$\begingroup\$

I have following code that creates parallel swathes of specified sizes. Can someone suggest a better way of doing this?

import matplotlib.pyplot as plt
import numpy as np
len=10; width=5;
pts=[];
for i in xrange(1,width+1):
    y_curr=i-1;
    if y_curr%2==0 :
        for j in xrange(0,len+1):
            pts.append([j,y_curr]);
    elif y_curr%2==1:
        for j in  xrange(1,len+2):
            pts.append([len+1-j,y_curr]);
pts=np.asarray(pts);
plt.plot(pts[:,0], pts[:,1])
plt.axis([-1, len+1, -1, width])
plt.show()

enter image description here

\$\endgroup\$
3
\$\begingroup\$

First of all, please remove all those semicolons. In Python, semicolons and newlines are two ways of indicating the end of a statement. Putting them both there is redundant.

Speaking of newlines, you should probably put one after your imports as a separator and probably another one between your len=10 and width=5. An interesting read is PEP 8, the official Python style guide.

As long as you're changing len=10 anyway, it's generally considered bad practice to define a variable with the same name as a built-in function because it masks the built-in. You use a full word for width; maybe it would be better to do the same for length.

There are some other spacing things I don't like. I would put some spaces around your operators, for example, and after the commas when passing arguments to xrange() and when creating your lists.


Now that we're done with style changes, on to the logic part.

I see some unnecessary +1s in your code. For example, your outer loop uses for i in xrange(1, width+1), yet the only place where i is used is y_curr=i-1. If you're just going to subtract 1 from it anyway, why add 1 to it in the first place? You can keep it simply for y_curr in xrange(width):.

Similarly, your second inner loop can be simplified as:

for j in xrange(len + 1):
    pts.append([len - j, y_curr])

You may notice now that your inner for loops are very similar. You can then simplify your code a little like this:

for y_curr in xrange(width):
    for j in xrange(len + 1):
        if y_curr % 2 == 0:
            pts.append((j, y_curr))
        else:
            pts.append((len - j, y_curr))

or even:

for y_curr in xrange(width):
    for j in xrange(len + 1):
        pts.append((j if y_curr % 2 == 0 else len - j, y_curr))

And if you're in the mood, you could use a list comprehension:

pts = [(j if y_curr % 2 == 0 else len - j, y_curr) for y_curr in xrange(width) for j in xrange(len + 1)]

though I don't recommend that because it is not at all readable.

I also decided to change to using tuples instead of lists. This is because the immutable nature of tuples makes them generally more efficient than lists. In addition, you probably noticed that I've used only one argument to xrange() in several places. When that is done, it assumes that the starting value is 0 and the stop is the supplied argument. This is the desired behavior in most cases, including yours.

I'm not sure why you're using NumPy here. You can do this very simply with standard Python:

plt.plot(*zip(*pts))

You could even keep separate lists in the first place:

x = []
y = []
for y_curr in xrange(width):
    for j in xrange(len + 1):
        x.append(j if y_curr % 2 == 0 else len - j)
        y.append(y_curr)

plt.plot(x, y)
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.