もともと、私はマーカーの一種のクラスを で作成できることを望んでいましたmatplotlib
。これは、たとえば x 座標とラベルを示すテキストを含む正方形であり、(疑似コード) のようなものでインスタンス化できます。
plt.plot(..., marker=myMarkerClass(label="X:"), ... )
...しかし、私が見る限り、そのようなことはできません。
ただし、マーカーのカスタマイズは古いものでは利用できないようですmatplotlib
。だから私は私の質問を次のように減らしたいと思います:古い でカスタム(パス)マーカーを取得する方法matplotlib
、そのサイズは画面座標で定義されます(マーカーはズーム時にスケーリングされません)? 明確にするために、いくつかの例を次に示します。
デフォルト (カスタマイズされていない) マーカー
以下は、古い で動作するデフォルトmatplotlib
マーカーの例ですmatplotlib
。を使用する代わりに試したことに注意してください。直接操作pyplot.plot()
しようとしていることに注意してくださいmatplotlib.figure.Figure
(これは通常、さまざまなバックエンドで使用される形式であるため)、「図マネージャー」を使用する必要があります ( matplotlib-devel - バックエンド オブジェクト構造も参照):
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.figure
import numpy as np
t = np.arange(0.0,1.5,0.25)
s = np.sin(2*np.pi*t)
mfigure = matplotlib.figure.Figure(figsize=(5,4), dpi=100)
ax = mfigure.add_subplot(111)
ax.plot(t,s, marker='o', color='b', markerfacecolor='orange', markersize=10.0)
fig = plt.figure() # create something (fig num 1) for fig_manager
figman = matplotlib._pylab_helpers.Gcf.get_fig_manager(1)
figman.canvas.figure = mfigure # needed
mfigure.set_canvas(figman.canvas) # needed
plt.show()
ここで任意のズーム矩形を実行すると、マーカーは同じサイズのままです。
パスによるカスタマイズされたマーカー
これはアーティスト (Line2D.set_marker) — Matplotlib 1.2.1 ドキュメントに記載されています。ただし、古いものでは機能しませんmatplotlib
。例を次に示します。
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.figure
import matplotlib.path
import numpy as np
print("matplotlib version {0}".format(matplotlib.__version__))
def getCustomSymbol1(inx, iny, sc, yasp):
verts = [
(-0.5, -0.5), # left, bottom
(-0.5, 0.5), # left, top
(0.5, 0.5), # right, top
(0.5, -0.5), # right, bottom
(-0.5, -0.5), # ignored
]
codes = [matplotlib.path.Path.MOVETO,
matplotlib.path.Path.LINETO,
matplotlib.path.Path.LINETO,
matplotlib.path.Path.LINETO,
matplotlib.path.Path.CLOSEPOLY,
]
pathCS1 = matplotlib.path.Path(verts, codes)
return pathCS1, verts
t = np.arange(0.0,1.5,0.25)
s = np.sin(2*np.pi*t)
mfigure = matplotlib.figure.Figure(figsize=(5,4), dpi=100)
ax = mfigure.add_subplot(111)
pthCS1, vrtCS1 = getCustomSymbol1(0,0, 1,1)
# here either marker=pthCS1 or marker=np.array(vrtCS1)
# have the same effect:
ax.plot(t,s, marker=pthCS1, markerfacecolor='orange', markersize=10.0)
#ax.plot(t,s, marker=np.array(vrtCS1), markerfacecolor='orange', markersize=10.0)
fig = plt.figure() # create something (fig num 1) for fig_manager
figman = matplotlib._pylab_helpers.Gcf.get_fig_manager(1)
figman.canvas.figure = mfigure # needed
mfigure.set_canvas(figman.canvas) # needed
plt.show()
これは newermatplotlib
では問題なく動作しますが、古いものでは失敗します:
$ python3.2 test.py
matplotlib version 1.2.0
$ python2.7 test.py # marker=pthCS1
matplotlib version 0.99.3
Traceback (most recent call last):
File "test.py", line 36, in <module>
ax.plot(t,s, marker=pthCS1, markerfacecolor='orange', markersize=10.0)
...
File "/usr/lib/pymodules/python2.7/matplotlib/lines.py", line 804, in set_marker
self._markerFunc = self._markers[marker]
KeyError: Path([[-0.5 -0.5]
[-0.5 0.5]
[ 0.5 0.5]
[ 0.5 -0.5]
[-0.5 -0.5]], [ 1 2 2 2 79])
$ python2.7 test.py # marker=np.array(vrtCS1)
matplotlib version 0.99.3
Traceback (most recent call last):
File "test.py", line 38, in <module>
ax.plot(t,s, marker=np.array(vrtCS1), markerfacecolor='orange', markersize=10.0)
...
File "/usr/lib/pymodules/python2.7/matplotlib/lines.py", line 798, in set_marker
if marker not in self._markers:
TypeError: unhashable type: 'numpy.ndarray'
ただし、Python 3.2 で動作する場合、予想どおり、グラフのズーム全体でマーカーのサイズが再び維持されます。
... ただし、この問題に注意してください:頂点リストから作成されたカスタム マーカーのスケールが間違っています · Issue #1980 · matplotlib/matplotlib · GitHub、このタイプのカスタム マーカーに関して。
PatchCollection のスルー パス
いくつかのインターネット投稿からこのコードの一部をピックアップしましたが、現在リンクを見つけることができません。いずれにせよ、マーカーの描画を避けることができ、PatchCollection を使用して、マーカーであるべきものを描画できます。古い で実行されるコードは次のmatplotlib
とおりです。
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.figure
import matplotlib.path, matplotlib.patches, matplotlib.collections
import numpy as np
def getCustomSymbol1(inx, iny, sc, yasp):
verts = [
(inx-0.5*sc, iny-0.5*sc*yasp), # (0., 0.), # left, bottom
(inx-0.5*sc, iny+0.5*sc*yasp), # (0., 1.), # left, top
(inx+0.5*sc, iny+0.5*sc*yasp), # (1., 1.), # right, top
(inx+0.5*sc, iny-0.5*sc*yasp), # (1., 0.), # right, bottom
(inx-0.5*sc, iny-0.5*sc*yasp), # (0., 0.), # ignored
]
codes = [matplotlib.path.Path.MOVETO,
matplotlib.path.Path.LINETO,
matplotlib.path.Path.LINETO,
matplotlib.path.Path.LINETO,
matplotlib.path.Path.CLOSEPOLY,
]
pathCS1 = matplotlib.path.Path(verts, codes)
return pathCS1
def getXyIter(inarr):
# this supports older numpy, where nditer is not available
if np.__version__ >= "1.6.0":
return np.nditer(inarr.tolist())
else:
dimensions = inarr.shape
xlen = dimensions[1]
xinds = np.arange(0, xlen, 1)
return np.transpose(np.take(inarr, xinds, axis=1))
t = np.arange(0.0,1.5,0.25)
s = np.sin(2*np.pi*t)
mfigure = matplotlib.figure.Figure(figsize=(5,4), dpi=100)
ax = mfigure.add_subplot(111)
ax.plot(t,s)
customMarkers=[]
for x, y in getXyIter(np.array([t,s])): #np.nditer([t,s]):
#printse("%f:%f\n" % (x,y))
pathCS1 = getCustomSymbol1(x,y,0.05,1.5*500.0/400.0)
patchCS1 = matplotlib.patches.PathPatch(pathCS1, facecolor='orange', lw=1) # no
customMarkers.append(patchCS1)
pcolm = matplotlib.collections.PatchCollection(customMarkers)
pcolm.set_alpha(0.9)
ax.add_collection(pcolm)
fig = plt.figure() # create something (fig num 1) for fig_manager
figman = matplotlib._pylab_helpers.Gcf.get_fig_manager(1)
figman.canvas.figure = mfigure # needed
mfigure.set_canvas(figman.canvas) # needed
plt.show()
さて、ここで図の初期アスペクト比を考慮しようとしましたが、実際、最初のレンダリングでは、「マーカー」はサイズに関して正しく見えますが...:
...任意のズームを実行しようとすると、パスがデータ座標で指定されていることは明らかであり、そのサイズはズーム四角形に応じて変化します。(もう 1 つの問題は、facecolor='orange'
従わないことですが、これは で修正できますpcolm.set_facecolor('orange')
)
matplotlib
それで、レンダリングされたパスが画面座標で定義され、任意のズーム時にサイズが変更されないという意味で、PatchCollection を古い のマーカーとして使用できる方法はありますか?