How to plot a 2d streamline in 3d view in matplotlib

后端 未结 2 699
暖寄归人
暖寄归人 2020-12-17 07:32

I need to plot a 2d streamline in 3d view like this. As suggested by the post, I need to extract streamlines and arrows from a 2d plot and then transform it to 3d data. How

相关标签:
2条回答
  • 2020-12-17 07:47

    this example should get you started:

    import matplotlib.pyplot as plt
    import numpy as np
    
    fig_tmp, ax_tmp = plt.subplots()
    x, y = np.mgrid[0:2.5:1000j, -2.5:2.5:1000j]
    vx, vy = np.cos(x - y), np.sin(x - y)
    res = ax_tmp.streamplot(x.T, y.T, vx, vy, color='k')
    fig_tmp.show()
    # extract the lines from the temporary figure
    lines = res.lines.get_paths()
    #for l in lines:
    #    plot(l.vertices.T[0],l.vertices.T[1],'k')
    
    fig = plt.figure()
    ax = fig.add_subplot(111, projection='3d')
    for line in lines:
        old_x = line.vertices.T[0]
        old_y = line.vertices.T[1]
        # apply for 2d to 3d transformation here
        new_z = np.exp(-(old_x ** 2 + old_y ** 2) / 4)
        new_x = 1.2 * old_x
        new_y = 0.8 * old_y
        ax.plot(new_x, new_y, new_z, 'k')
    

    this generates an intermediate temporary figure: enter image description here

    from which the lines are extracted. Then you apply your 2d to 3d point transformation of your liking, and plot the same lines in a new 3d figure:enter image description here

    0 讨论(0)
  • 2020-12-17 08:01

    pyplot.streamplot returns "lines" and "arrows".

    "Lines" consists of series of pair of interpolated points(in x,y given in streamplot) from streamplot function. One particular streamline starts with a seed point (uniformly distributed I guess) and ends when integrator inside streamline gives same pair of points more than 5 times. Then it choose next seed and repeat the procedure.

    "arrows" are actually information about the patch object with edge points measured by the fig(gca) unlike "lines" . That is why if you get res.arrows.get_paths() and plot vertices of it it runs from zero to (figsize[0]-2)*dpi and (figsize[1]-2)*dpi.

    In principle one can invert the logic back and get the arrow. But I think that would be tedious. So better way would be, get all the segments of a particular streamline from "lines". Map to 3d and draw 3d-arrow using one or more segments, depending upon the arrow density you want.

    Conditions to get individual streamlines from "lines" is. 1. New streamline if all the four points of two consecutive segments differ. 2. End of a streamline if all the four points of two consecutive segments are same for more than 5 consecutive pairs.

    A naive solution might be

        fig = figure(figsize=(8,6), dpi =160)
    
        ax = fig.add_subplot(111, projection='3d' )
        i = 0
        for line in lines:
            i += 1
            old_x = line.vertices.T[0]
            old_y = line.vertices.T[1]
            # apply for 2d to 3d transformation here
            new_z = np.exp(-(old_x ** 2 + old_y ** 2) / 4)
            new_x = 1.2 * old_x
            new_y = 0.8 * old_y
            ax.plot(new_x, new_y, new_z, 'k')
    
            if i%10 ==1:
                ax.quiver(new_x[0],new_y[0],new_z[0],new_x[0]-new_x[1],new_y[0]-new_y[1],new_z[0]-new_z[1], length=0.2)
    
    0 讨论(0)
提交回复
热议问题