6

I just want to draw simple shape by points, like this:

import matplotlib.pyplot as plt

rectangle = [(0,0),(0,1),(1,1),(1,0)]
hexagon = [(0,0),(0,1),(1,2),(2,1),(2,0),(1,-1)]
l_shape = [(0,0),(0,3),(1,3),(1,1),(3,1),(3,0)]
concave = [(0,0),(0,3),(1,3),(1,1),(2,1),(2,3),(3,3),(3,0)]

for points in [rectangle, hexagon, l_shape, concave]:
    # 1. Can I get rid of the zip? plot directly by points 
    # 2. How can I make the shape complete?
    xs, ys = zip(*points)
    plt.plot(xs, ys, 'o')
    plt.plot(xs, ys, '-')

    automin, automax = plt.xlim()
    plt.xlim(automin-0.5, automax+0.5)
    automin, automax = plt.ylim()
    plt.ylim(automin-0.5, automax+0.5)
    # Can I display the shapes 2 in 1 line?
    plt.show()

My question is enter image description here

  1. How can I get rid of the *zip? I mean, directyly draw by points, rather than 2 array.
  2. How to make these shapes complete? Since I'm looping through all the points, the first and last cannot connect together, how can I do it?
  3. Can I draw the shape without giving the specific points order?(Something like convex hull?)
unDeadHerbs
  • 1,306
  • 1
  • 11
  • 19
ZK Zhao
  • 19,885
  • 47
  • 132
  • 206
  • why do you want to get rid of `*zip`? It is a convenient way to plot points and connect them with lines. – Konstantin May 15 '15 at 03:10
  • @Alik I mean something like this`plt.plot([(0,0),(0,1),(1,1),(1,0)], 'o')`, so I can directly pass points to `plot`, without `zipping` them. – ZK Zhao May 15 '15 at 03:46
  • 1
    then do `plt.plot(*zip(*(points+points[:1])), marker='o')` instead of `xs, ys = zip(*points) plt.plot(xs, ys, 'o') plt.plot(xs, ys, '-')` – Konstantin May 15 '15 at 04:05
  • This will solve #1 and #2. As for #3 - I do not get what your really want. Convex hull for `l_shape` will be different, it won't contain `(1,1)` point – Konstantin May 15 '15 at 04:06
  • @Alik, Thanks. For #3, I'm just trying to descript what I want. Certainly `Convexl hull` woud suffice. I think a more proper description would be `draw simple shape without ordering points`? – ZK Zhao May 15 '15 at 06:10
  • Take a look at getting the ccworder from here: http://stackoverflow.com/questions/5040412/how-to-draw-the-largest-polygon-from-a-set-of-points. – leekaiinthesky May 15 '15 at 07:42

2 Answers2

3

To close the shape, just add the first point again at the end of the list:

# rectangle = [(0,0),(0,1),(1,1),(1,0)]
rectangle = [(0,0),(0,1),(1,1),(1,0),(0,0)]

plt.plot takes a list of x coordinates and a list of y coordinates. I would say that the way you're doing it now is already the way of doing it "by points rather than 2 arrays". Because if you wanted to do it without zip, it would look like this:

rectangleX = [0, 0, 1, 1, 0]
rectangleY = [0, 1, 1, 0, 0]
plt.plot(rectangleX, rectangleY, 'o')
plt.plot(rectangleX, rectangleY, '-')

Update:

For better polygon support, use the patches module [example]. This may be more along the lines of what you're looking for. By default (closed = True), it will close the path for you, and it also allows you to add vertices directly to a list (not two separate lists):

import matplotlib.pyplot as plt
import matplotlib.patches as mpatches

rectangle = [(0,0),(0,1),(1,1),(1,0)]

fig, ax = plt.subplots()
ax.add_patch(mpatches.Polygon(rectangle))

automin, automax = plt.xlim()
plt.xlim(automin-0.5, automax+0.5)
automin, automax = plt.ylim()
plt.ylim(automin-0.5, automax+0.5)
plt.show()
leekaiinthesky
  • 5,413
  • 4
  • 28
  • 39
  • But I feel adding the first point again is quite repetative, is there more elegant way of doing this? – ZK Zhao May 15 '15 at 03:06
  • Does this need the points be in a specific order? So it can displayed as a shape, and there won't be lines across(lie in) the shape? – ZK Zhao May 15 '15 at 06:15
  • The edges will be drawn in the order provided, same as what you had before. – leekaiinthesky May 15 '15 at 06:19
  • Got it, sadly it does not solve my #3 problem. I think it is a quite big one. I'll edit it out and make it a standalone question. – ZK Zhao May 15 '15 at 06:21
  • Try this http://stackoverflow.com/questions/5040412/how-to-draw-the-largest-polygon-from-a-set-of-points or this http://docs.scipy.org/doc/scipy-dev/reference/generated/scipy.spatial.ConvexHull.html. – leekaiinthesky May 15 '15 at 06:26
  • @leekaiinthesky well, it won't solve the problem, because not all points in OP's shapes are on respective convex hulls. – Konstantin May 15 '15 at 06:28
  • I already tried the `convex hull`, it does not help with `L-shape` and `Concave`. – ZK Zhao May 15 '15 at 06:29
1

The code below doesn't use temporary variables xs and ys, but a direct tuple unpacking. Also I add first point from points list to make shapes complete.

rectangle = [(0,0),(0,1),(1,1),(1,0)]
hexagon = [(0,0),(0,1),(1,2),(2,1),(2,0),(1,-1)]
l_shape = [(0,0),(0,3),(1,3),(1,1),(3,1),(3,0)]
concave = [(0,0),(0,3),(1,3),(1,1),(2,1),(2,3),(3,3),(3,0)]

for points in [rectangle, hexagon, l_shape, concave]:
    plt.plot(*zip(*(points+points[:1])), marker='o')

    automin, automax = plt.xlim()
    plt.xlim(automin-0.5, automax+0.5)
    automin, automax = plt.ylim()
    plt.ylim(automin-0.5, automax+0.5)

    plt.show()

Provide this answer as an alternative leekaiinthesky's post

Konstantin
  • 24,271
  • 5
  • 48
  • 65