Search code examples
pythonmatplotlibpointpath-finding

How to use a point to describe the trail of an object with package matplotlib


In the while loop,the command plt.plot(x,y,'*') paints the trail of an object.SO there are many points painted in the axes. But I just want a moving point to describe the trail.

Details are in the "while loop" of following code:

import matplotlib.pyplot as plt
import numpy as np
#just a dynamic painting
tolerance = 1e-1
radius = np.pi

# missile 1
x_m1, y_m1 = -np.pi, 0
v_m1 = 5

# missile 2
x_m2, y_m2 = 0, np.pi
v_m2 = v_m1
# missile 3
x_m3, y_m3 = np.pi, 0
v_m3 = v_m1
# missile 4
x_m4, y_m4 = 0, -np.pi
v_m4 = v_m1

plt.figure(figsize=(10, 10), dpi=80)
plt.title(" missile flight simulator ", fontsize=40)
plt.xlim(-4, 4)
plt.ylim(-4, 4)
#plt.xticks([])
#plt.yticks([])

# set spines
ax = plt.gca()
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')
ax.xaxis.set_ticks_position('bottom')
ax.spines['bottom'].set_position(('data', 0))
ax.yaxis.set_ticks_position('left')
ax.spines['left'].set_position(('data', 0))


plt.annotate('missile start point', xy=(x_m1, y_m1),  xycoords='data',
             xytext=(+15, +15), textcoords='offset points', fontsize=12,
             arrowprops=dict(arrowstyle="->", connectionstyle="arc3,rad=.2"))

# alpha labels
for label in ax.get_xticklabels() + ax.get_yticklabels():
    label.set_fontsize(16)
    label.set_bbox(dict(facecolor='white', edgecolor='None', alpha=0.65))


class ob(object):
    """docstring for ob"""
    def __init__(self, x, y):
        self.x = x
        self.y = y


class missile(ob):
    """docstring for missile"""
    def __init__(self, x, y):
        super(missile, self).__init__(x, y)

    def forward(self, v, target):
        """docstring for forward"""
        if self.x < target.x:
            alpha = np.arctan((target.y - self.y) / (target.x - self.x))
        elif self.x > target.x:
            alpha = np.pi + np.arctan((target.y - self.y) / (target.x - self.x))
        elif self.x == target.x and self.y < target.y:
            alpha = np.pi / 2
        else:
            alpha = -np.pi / 2
        self.x = self.x + v * 0.01 * np.cos(alpha)
        self.y = self.y + v * 0.01 * np.sin(alpha)
        return self.x, self.y

    def distance(self, target):
        """docstring for distance"""
        return np.sqrt((self.x - target.x) ** 2 + (self.y - target.y) ** 2)


class target(ob):
    """docstring for target"""
    def __init__(self, x, y):
        super(target, self).__init__(x, y)

    def newposition(self, x, y):
        """docstring for newposition"""
        self.x = x
        self.y = y

m1 = missile(x_m1, y_m1)
m2 = missile(x_m2, y_m2)
m3 = missile(x_m3, y_m3)
m4 = missile(x_m4, y_m4)

while True: #details
#just a dynamic painting
    if m1.distance(m2) < tolerance or m1.distance(m3) < tolerance or m1.distance(m4) < tolerance:    #In the loop,many points are painted to discribe the trail    
        print "collision"
        plt.plot(x_m1, y_m1, 'o')
        plt.annotate('crash point', xy=(x_m1, y_m1),  xycoords='data',
                     xytext=(+15, +15), textcoords='offset points', fontsize=12,
                     arrowprops=dict(arrowstyle="->", connectionstyle="arc3,rad=.2"))
        plt.pause(0.1)
        plt.show()
        break
    elif m3.distance(m2) < tolerance or m3.distance(m4) < tolerance:
        print "collision"
        plt.plot(x_m3, y_m3, 'o')
        plt.annotate('crash point', xy=(x_m3, y_m3),  xycoords='data',
                     xytext=(+15, +15), textcoords='offset points', fontsize=12,
                     arrowprops=dict(arrowstyle="->", connectionstyle="arc3,rad=.2"))
        plt.pause(0.1)
        plt.show
        break
    x_m1, y_m1 = m1.forward(v_m1, m2)
    x_m2, y_m2 = m2.forward(v_m2, m3)
    x_m3, y_m3 = m3.forward(v_m3, m4)
    x_m4, y_m4 = m4.forward(v_m4, m1)
    #print alpha, beta
    plt.plot(x_m1, y_m1, 'bx', alpha=.5)
    plt.plot(x_m2, y_m2, 'k*', alpha=.5)
    plt.plot(x_m3, y_m3, 'r.', alpha=.5)
    plt.plot(x_m4, y_m4, 'gp', alpha=.5)
    plt.legend(("missile1", "missile2", "missile3", "missile4"), loc="upper left", prop={'size': 12})

    plt.pause(0.1)

Are there any resolution given? This program is just for dynamic painting... aka paint a moving point to show the track of an object. The point's coordinate get updated with its regular speed. In my code, all points of the track are painted, but I only need one moving point. Just like an running car in the road, every time you see one moving car in a different place of the track. You can delete the "while" loop, if you could use other ways to achieve my expectation.


Solution

  • I'm still not sure I understood your question, but:

    It looks like you've fallen into the same trap as 90% of people asking about animations and matplotlib, in that you are repeatedly calling plot() at each step of your iterations, thus creating new points (really, new Line2D objects) at each steps, instead of updating the properties of the existing one.

    The general procedure for animations is to:

    1. create your figure and all the fixed elements that do not need to be updated
    2. create the artists that need to be updated, and keep a reference to them
    3. in your loop, update (instead of replacing or creating new artists) the properties of the artists created in the previous step.

    Since you did not get my hint about creating a minimal working example, let me show that 99% of your code was useless and that your problem can be simplified and solved just like so:

    import matplotlib.pyplot as plt
    import numpy as np
    
    plt.figure()
    # create a placeholder artist object, and keep a reference to it
    my_line, = plt.plot([], [], 'bx', alpha=.5)
    plt.legend(["my line"], loc="upper left", prop={'size': 12})
    plt.xlim([0, 10])
    plt.ylim([0, 10])
    i = 0
    
    while True:
        # do whatever to get next coordinates
        i = (i + 1) % 10
        new_x, new_y = i, i
        # update artist
        my_line.set_data(new_x, new_y)
        plt.draw()
        plt.pause(0.1)
    

    Finally, I will echo @ImportanceOfBeingErnest's comment and suggest you look into the FuncAnimation module to produce your animations, although the overall strategy remains exactly the same.