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

2019-01-19 09:34发布

问题:

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 to transform this 2d streamline data to 3d data and plot using mplot3d?

Thanks in advance

Raj

EDIT: @gg349, with your help I could plot streamline in 3d view. The plot is here

I have two questions:

  1. How to extract arrows from streamplot and plot it in 3d as you did in your earlier post

  2. How to extract a imshow() data and plot it in 3d. The 2d streamline with imshow() is here

回答1:

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:

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:



回答2:

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)