2013-04-27 11 views
11

私は、matplotlibを使って球の周りの磁場の流線をプロットしようとしています。それは非常にうまく動作します。しかし、結果として得られる画像は対称ではありませんが、(私は)そうでなければなりません。 enter image description herematplotlibの対称ストリームプロット

これはイメージの生成に使用されるコードです。長さを許してください、しかし、私はそれが単に働いていないスニペットを投稿するよりも良いと思った。また、それは非常にpythonicではありません。それは私がMatlabから変換したためです。これは予想以上に簡単でした。

from __future__ import division 
import numpy as np 
import matplotlib.pyplot as plt 
from matplotlib.patches import Circle 

def cart2spherical(x, y, z): 
    r = np.sqrt(x**2 + y**2 + z**2) 
    phi = np.arctan2(y, x) 
    theta = np.arccos(z/r) 
    if r == 0: 
     theta = 0 
    return (r, theta, phi) 

def S(theta, phi): 
    S = np.array([[np.sin(theta)*np.cos(phi), np.cos(theta)*np.cos(phi), -np.sin(phi)], 
        [np.sin(theta)*np.sin(phi), np.cos(theta)*np.sin(phi), np.cos(phi)], 
        [np.cos(theta),    -np.sin(theta),    0]]) 
    return S 

def computeB(r, theta, phi, a=1, muR=100, B0=1): 
    delta = (muR - 1)/(muR + 2) 
    if r > a: 
     Bspherical = B0*np.array([np.cos(theta) * (1 + 2*delta*a**3/r**3), 
            np.sin(theta) * (delta*a**3/r**3 - 1), 
            0]) 
     B = np.dot(S(theta, phi), Bspherical) 
    else: 
     B = 3*B0*(muR/(muR + 2)) * np.array([0, 0, 1]) 
    return B 

Z, X = np.mgrid[-2.5:2.5:1000j, -2.5:2.5:1000j] 
Bx = np.zeros(np.shape(X)) 
Bz = np.zeros(np.shape(X)) 
Babs = np.zeros(np.shape(X)) 
for i in range(len(X)): 
    for j in range(len(Z)): 
     r, theta, phi = cart2spherical(X[0, i], 0, Z[j, 0]) 
     B = computeB(r, theta, phi) 
     Bx[i, j], Bz[i, j] = B[0], B[2] 
     Babs[i, j] = np.sqrt(B[0]**2 + B[1]**2 + B[2]**2) 

fig=plt.figure() 
ax=fig.add_subplot(111) 

plt.streamplot(X, Z, Bx, Bz, color='k', linewidth=0.8*Babs, density=1.3, 
       minlength=0.9, arrowstyle='-') 
ax.add_patch(Circle((0, 0), radius=1, facecolor='none', linewidth=2)) 
plt.axis('equal') 
plt.axis('off') 
fig.savefig('streamlines.pdf', transparent=True, bbox_inches='tight', pad_inches=0) 
+0

ルックを、これはそれだけでひどくストリームラインを選んだように見えますが、あなたのデータは結構です。 – tacaswell

+0

@tcaswell私は基本的な問題は、境界のフィールドの不連続であると思う。この場合、プロットを2つの領域に分割することが賢明だと思います。 – Hooked

答えて

6

まず、好奇心のために、なぜ対称データをプロットする必要がありますか?なぜ半分をプロットしても問題ないのですか?

これは、可能なハックです。

mask = X>0 
BX_OUT = Bx.copy() 
BZ_OUT = Bz.copy() 
BX_OUT[mask] = None 
BZ_OUT[mask] = None 
res = plt.streamplot(X, Z, BX_OUT, BZ_OUT, color='k', 
      arrowstyle='-',linewidth=1,density=2) 

その後は、streamplotから結果解像度で保存ラインを抽出し、反対のX座標とそれらをプロット:夢中はそれの半分をプロットするために提案されるようにあなたは、マスクアレイを使用することができます。

lines = res.lines.get_paths() 
for l in lines: 
    plot(-l.vertices.T[0],l.vertices.T[1],'k') 

私はこのハックを使用して2Dプロットから流線と矢印を抽出し、次に3D変換を適用してmplot3dでプロットしました。写真は私の質問の1つであるhereです。

+4

データの完全性PoVの場合、これは実際には厄介な解決策です。 – tacaswell

8

ドキュメントからの引用:

density : float or 2-tuple 
    Controls the closeness of streamlines. When density = 1, 
    the domain is divided into 
    a 25x25 grid—density linearly scales this grid. 
    Each cell in the grid can have, at most, one traversing streamline. 
    For different densities in each direction, use [density_x, density_y]. 

ので、あなたはそれがストリームラインがどこにあるかを判断するために使用する細胞、および問題の対称性との間にエイリアシング効果を得ています。グリッドサイズ(データのサイズ)と密度を慎重に選択する必要があります。

また、ボックスの境界が球の上部を基準にしている場所にも敏感です。あなたの球の中心が上のはデータグリッドポイントかデータグリッドポイントの間ですか? の場合、グリッドポイントの場合、中心点を含むボックスは、隣接するボックスとは異なります。

私はどのストリーム線を描くのか正確には分かりませんが、欲張りアルゴリズムなので、高密度領域と離れた密度領域に歩いて異なる結果が出ると思います。

ストリームの行がで間違っているのではなく、有効なストリーム行であることを確認してください。審美的に満足できる結果が得られません。

+0

私がこの権利を理解すれば、これは '密度= 1.6 'を選択すると、40個のセル、各面に20個、各セルに25個のデータポイントがあることを意味します。プロットはまだ対称ではありません。 – Psirus

+1

Psirusが密度を対称にすることは必ずしも対称プロットを与えるとは限らないことに注意してください。他の主な問題は、streamplotがストリームラインを螺旋状に描画するための開始点を選択したことです。これらをカスタマイズするには '_gen_starting_points'をハックすることができます。合理化も数値的に統合されているため、グリッドデータ(密度選択から)と開始点が完全に対称であることを保証することに注意する必要があります。 –

5

関心の2つの領域を分離するためにマスクを使用します。

mask = np.sqrt(X**2+Z**2)<1 

BX_OUT = Bx.copy() 
BZ_OUT = Bz.copy() 
BX_OUT[mask] = None 
BZ_OUT[mask] = None 
plt.streamplot(X, Z, BX_OUT, BZ_OUT, color='k', 
       arrowstyle='-', density=2) 

BX_IN = Bx.copy() 
BZ_IN = Bz.copy() 
BX_IN[~mask] = None 
BZ_IN[~mask] = None 
plt.streamplot(X, Z, BX_IN, BZ_IN, color='r', 
       arrowstyle='-', density=2) 

enter image description here

結果のプロットが正確に対称ではありませんが、アルゴリズムにヒントを与えることによって、それはよりもはるかに近いですあなたが以前持っていたもの。お探しのエフェクトを実現するには、meshgriddensityパラメータでグリッドの密度で再生してください。

2

代わりに物理学を使用する...磁界は、z(垂直)軸に関して対称である。だから、あなたはちょうど2つのstreamplot年代必要があります: `streamplot`の引数で

plt.streamplot(X, Z, Bx, Bz, color='k', linewidth=0.8*Babs, density=1.3, minlength=0.9, arrowstyle='-') 
plt.streamplot(-X, Z, -Bx, Bz, color='k', linewidth=0.8*Babs, density=1.3, minlength=0.9, arrowstyle='-') 
関連する問題