4

I have a numpy array with xy co-ordinates for points. I have plotted each of these points and want a line connecting each point to every other point (a complete graph). The array is a 2x50 structure so I have transposed it and used a view to let me iterate through the rows. However, I am getting an 'index out of bounds' error with the following:

     plt.plot(*zip(*v.T)) #to plot all the points
     viewVX = (v[0]).T
     viewVY = (v[1]).T
     for i in range(0, 49):
        xPoints = viewVX[i], viewVX[i+1]
        print("xPoints is", xPoints)
        yPoints = viewVY[i+2], viewVY[i+3]
        print("yPoints is", yPoints)
        xy = xPoints, yPoints
        plt.plot(*zip(*xy), ls ='-')

I was hoping that the indexing would 'wrap-around' so that for the ypoints, it'd start with y0, y1 etc. Is there an easier way to accomplish what I'm trying to achieve?

3
  • 1
    I'm a little lost. First, plt.plot(*zip(*v.T)) seems to do the same thing as plt.plot(v[0], v[1]). Second, your question makes it sound like you want a line between every pair of points (maybe a complete graph?) but that's not what your code does. Could you be a little more clear about what you're trying to do. Commented Jan 1, 2012 at 19:27
  • Yes Bago, I'm trying to draw a complete graph and getting my code to do that is proving a problem for me. Thanks for the simpler plt.plot(v[0], v[1]) syntax. I'm new to numpy and matplotlab. I'll edit my question to make explicit the complete graph. Commented Jan 1, 2012 at 19:37
  • possible duplicate of How do you create line segments between two points? Commented Jan 3, 2012 at 10:21

4 Answers 4

3
import matplotlib.pyplot as plt
import numpy as np
import itertools

v=np.random.random((2,50))
plt.plot(
    *zip(*itertools.chain.from_iterable(itertools.combinations(v.T,2))),
    marker='o', markerfacecolor='red')
plt.show()

The advantage of doing it this way is that there are fewer calls to plt.plot. This should be significantly faster than methods that make O(N**2) calls to plt.plot.

Note also that you do not need to plot the points separately. Instead, you can use the marker='o' parameter.


Explanation: I think the easiest way to understand this code is to see how it operates on a simple v:

In [4]: import numpy as np
In [5]: import itertools
In [7]: v=np.arange(8).reshape(2,4)
In [8]: v
Out[8]: 
array([[0, 1, 2, 3],
       [4, 5, 6, 7]])

itertools.combinations(...,2) generates all possible pairs of points:

In [10]: list(itertools.combinations(v.T,2))
Out[10]: 
[(array([0, 4]), array([1, 5])),
 (array([0, 4]), array([2, 6])),
 (array([0, 4]), array([3, 7])),
 (array([1, 5]), array([2, 6])),
 (array([1, 5]), array([3, 7])),
 (array([2, 6]), array([3, 7]))]

Now we use itertools.chain.from_iterable to convert this list of pairs of points into a (flattened) list of points:

In [11]: list(itertools.chain.from_iterable(itertools.combinations(v.T,2)))
Out[11]: 
[array([0, 4]),
 array([1, 5]),
 array([0, 4]),
 array([2, 6]),
 array([0, 4]),
 array([3, 7]),
 array([1, 5]),
 array([2, 6]),
 array([1, 5]),
 array([3, 7]),
 array([2, 6]),
 array([3, 7])]

If we plot these points one after another, connected by lines, we get our complete graph. The only problem is that plt.plot(x,y) expects x to be a sequence of x-values, and y to be a sequence of y-values.

We can use zip to convert the list of points into a list of x-values and y-values:

In [12]: zip(*itertools.chain.from_iterable(itertools.combinations(v.T,2)))
Out[12]: [(0, 1, 0, 2, 0, 3, 1, 2, 1, 3, 2, 3), (4, 5, 4, 6, 4, 7, 5, 6, 5, 7, 6, 7)]

The use of the splat operator (*) in zip and plt.plot is explained here.

Thus we've managed to massage the data into the right form to be fed to plt.plot.

Sign up to request clarification or add additional context in comments.

1 Comment

that is fantastic - thanks! I haven't used itertools before so some of the syntax in the plt.plot call is unfamiliar to me. Is this similar to nditer?
2

With a 2 by 50 array,

 for i in range(0, 49):
    xPoints = viewVX[i], viewVX[i+1]
    print("xPoints is", xPoints)
    yPoints = viewVY[i+2], viewVY[i+3]

would get out of bounds for i = 47 and i = 48 since you use i+2 and i+3 as indices into viewVY.

4 Comments

Is there a way of iterating through array elements from different starting points so the iteration wraps back round to the starting element?
Modular indexing, (i + 2(3)) % 50 would wrap it back to 0 when it reaches 50.
thanks that solved my indexing problem. But I just need to sort out which points to send for a complete graph.
Happy to help. I'm afraid I can't help you with the plotting, though,not my domain.
2

This is what I came up with, but I hope someone comes up with something better.

def plot_complete(v):
     for x1, y1 in v.T:
          for x2, y2, in v.T:
             plt.plot([x1, x2], [y1, y2], 'b')
     plt.plot(v[0], v[1], 'sr')

The 'b' makes the lines blue, and 'sr' marks the points with red squares.

1 Comment

Bago, thanks - this is basically what I got it down to too. I prefer your cleaner syntax. I am starting to get used to the idea of labelling columns with just the 'for x1, y1 in v.T' syntax.
1

Have figured it out. Basically used simplified syntax provided by @Bago for plotting and considered @Daniel's indexing tip. Just have to iterate through each xy set of points and construct a new set of xx' yy' set of points to use to send to plt.plot():

        viewVX = (v[0]).T #this is if your matrix is 2x100 ie row [0] is x and row[1] is y
        viewVY = (v[1]).T
        for i in range(0, v.shape[1]): #v.shape[1] gives the number of columns
           for j in range(0, v.shape[1]):
              xPoints = viewVX[j], viewVX[i]
              yPoints = viewVY[j], viewVY[i]
              xy = [xPoints, yPoints]         #tuple/array of xx, yy point
              #print("xy points are", xy)
              plt.plot(xy[0],xy[1], ls ='-')

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.