1

I have this code right now:

import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np

fig = plt.figure()
ax = fig.gca(projection='3d')
x = np.arange(1,6)
y = np.arange(5,11)
z = np.arange(3,9)

for i in range(4):
    ax.plot([x[i], x[i+1]], [y[i],y[i+1]],[z[i],z[i+1]])
    plt.show()

I want to show how the curve is progressing(moving). But this doesn't work. It shows the first line and there is no way to move to the next plot, and when I close the window, the program just ends, without showing me the next 3 lines.

I also tried adding plt.waitforbuttonpress() in the end, but it didn't help.

I am new to python so I might be missing something simple. Thanks for the help!

Ank
  • 1,864
  • 4
  • 31
  • 51

1 Answers1

1

Sounds like you need a 3D animation. Hopefully this is what you want:

import numpy as np
import matplotlib.pyplot as plt
import mpl_toolkits.mplot3d.axes3d as p3
import matplotlib.animation as animation

def move_curve(i, line, x, y, z):
    line.set_data([[x[i], x[i+1]], [y[i],y[i+1]]])
    line.set_3d_properties([z[i],z[i+1]])

fig = plt.figure()
ax = fig.gca(projection='3d')
x = np.arange(1,6)
y = np.arange(5,11)
z = np.arange(3,9)

i = 0
line = ax.plot([x[i], x[i+1]], [y[i],y[i+1]], [z[i],z[i+1]])[0]
ax.set_xlim3d([1, 5])
ax.set_ylim3d([5, 10])
ax.set_zlim3d([3, 8])

line_ani = animation.FuncAnimation(fig, move_curve, 4, fargs=(line, x, y, z))

Edit: to show line growing rather than line moving.

The basic idea is to add a point to the line for each frame loop rather than changing the start and end points of the line:

import numpy as np
import matplotlib.pyplot as plt
import mpl_toolkits.mplot3d.axes3d as p3
import matplotlib.animation as animation

def move_curve(i, line, x, y, z):
    # Add points rather than changing start and end points.
    line.set_data(x[:i+1], y[:i+1])
    line.set_3d_properties(z[:i+1])

fig = plt.figure()
ax = fig.gca(projection='3d')
x = np.arange(1,6)
y = np.arange(5,11)
z = np.arange(3,9)

i = 0
line = ax.plot([x[i], x[i+1]], [y[i],y[i+1]], [z[i],z[i+1]])[0]
ax.set_xlim3d([1, 5])
ax.set_ylim3d([5, 10])
ax.set_zlim3d([3, 8])

line_ani = animation.FuncAnimation(fig, move_curve, 5, fargs=(line, x, y, z))

Edit 2: Update axis limit; draw lines with different color; skip even lines.

The basic idea is to:

  1. Pass ax as one of fargs so that you can update axis limit with ax.
  2. Set up your lines as 4 empty lines and show (or skip) corresponding lines in each frame. By default, different lines will have different color.

Here is some codes to start with. Just to be clear, the following code is not the best in design and may or may not fit your needs. But I think it's a good starting point.

import numpy as np
import matplotlib.pyplot as plt
import mpl_toolkits.mplot3d.axes3d as p3
import matplotlib.animation as animation

def move_curve(num, ax, lines, x, y, z):
    for i in range(num+1):
        if i % 2 == 1:
            continue
        lines[i].set_data([[x[i], x[i+1]], [y[i],y[i+1]]])
        lines[i].set_3d_properties([z[i],z[i+1]])
    ax.set_xlim3d([1, x[i+1]])
    ax.set_ylim3d([5, y[i+1]])
    ax.set_zlim3d([3, z[i+1]])
    return lines

fig = plt.figure()
ax = fig.gca(projection='3d')
x = np.arange(1,6)
y = np.arange(5,11)
z = np.arange(3,9)

lines = [ax.plot([], [], [])[0] for i in range(4)]

line_ani = animation.FuncAnimation(fig, move_curve, 4, fargs=(ax, lines, x, y, z), repeat=False)
Y. Luo
  • 5,622
  • 1
  • 18
  • 25
  • No, not really. I want to show the first line when the loop runs for the first time, and first & second line when the loop runs for the second time and so on... – Ank Apr 07 '18 at 03:51
  • Is it possible to show plt in the loop itself? Because actually, I am getting the next point when the loop runs, so I want to connect it with the earlier point. – Ank Apr 07 '18 at 03:54
  • @Ank Could you please check out my edit and see if that's what you want? The line will grow rather than moving. You don't have to show plt in the loop because the "plot" will be shown for each frame for `interval` milliseconds. – Y. Luo Apr 07 '18 at 04:11
  • Is it possible to update the axis also as the line grows? – Ank Apr 07 '18 at 05:04
  • Is it possible to use different colours for different lines? – Ank Apr 07 '18 at 05:04
  • @Ank To update axis, pass `ax` as an argument and use codes like `ax.set_xlim3d([1, x[i+1]])` to update axis limit. To use different colors for different lines, you are essentially plotting multiple lines rather than one line. I would suggest you check [the official example](https://matplotlib.org/examples/animation/simple_3danim.html) and use `lines` instead of `line`. If you have a specific [MCVE](https://stackoverflow.com/help/mcve), I suggest you open a new question with all your details. – Y. Luo Apr 07 '18 at 05:13
  • How to pass ax as argument? `animation.FuncAnimation(fig, move_curve, 5, ax, fargs=(line, x, y, z))` gives me some error – Ank Apr 07 '18 at 05:24
  • As you suggested, I have opened a new question here: https://stackoverflow.com/questions/49705425/matplotlib-animation-draw-lines-in-different-colours – Ank Apr 07 '18 at 08:28
  • Is it possible to skip one line alternatively? Like join point 1 & 2, and 3 & 4, but skip 2 & 3 and so on? – Ank Apr 07 '18 at 12:31
  • @Ank Your new question seems to be only a copy and paste of your comments here. Again, it will be very helpful if you can provide more descriptions on exact effects you are looking for. That way those real experts will come and help you. Matplotlib animation has a lot of useful options and I highly recommend you looking into them yourself. My skills are limited and I hope the new code can be a good starting point for you. – Y. Luo Apr 07 '18 at 16:29