質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

1回答

1096閲覧

Axes3Dにて三次元グラフを描画しながらその隣に関係する写真を表示する

nbm140

総合スコア0

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2021/04/01 13:06

編集2021/04/04 14:49

前提・実現したいこと

独学でPythonの学習をしております。
3次元のデータをAxes3Dにて3次元グラフ上で表示し、そのグラフの隣に各座標に対応する画像を表示させたいと考えております。
具体的には今回のサンプルプログラムでプロットされている30点それぞれに画像が用意されており、マウスと一番近い座標にあるポイントに対応する画像を表示します。
3次元グラフの必要事項としてマウスオーバーでラベル表示させる必要があり、以下のサイトを参考にプログラムを作成しました。

参考プログラムの流れ

参考サイト
[https://www.xspdf.com/help/51593042.html]

visualize3DDataにてグラフを用意し、マウスイベントを監視する。

onMouseMotionにてマウスイベントを取得。

calcClosestDatapointとdistanceにてマウスに一番近い座標を計算する。

annotatePlotにてマウスから一番近い座標にラベルを追加する。

Print_Picにてマウスから一番近い座標に対応する画像を表示する。(この部分を追加したい)

発生している問題・エラーメッセージ

画像はax1=plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))で表示しようとしました。
3次元グラフと上記の画像を並べた際に「"'AxesSubplot' object has no attribute 'get_proj'"」とエラーが出る現象を解決したいです。
おそらく画像上にマウスカーソルを移動させた際に、画像には2次元座標しかないため「x2, y2, _ = proj3d.proj_transform(point[0], point[1], point[2], plt.gca().get_proj())」がエラーになっていると考えておりますが、
解決策がありましたらご教授いただければ幸いです。

コード

import

1import pandas as pd 2from PIL import Image 3import cv2 4import matplotlib 5matplotlib.use('tkagg') 6import matplotlib.pyplot as plt 7from mpl_toolkits.mplot3d import Axes3D 8from mpl_toolkits.mplot3d import proj3d 9 10def visualize3DData (X): 11 fig = plt.figure(figsize = (16,10)) 12 ax = fig.add_subplot(111, projection = '3d') 13 ax.grid(True) 14 ax.scatter(X[:, 0], X[:, 1], X[:, 2], depthshade = False, picker = True,s=2) 15 16 def distance(point, event): 17 assert point.shape == (3,), "distance: point.shape is wrong: %s, must be (3,)" % point.shape 18 x2, y2, _ = proj3d.proj_transform(point[0], point[1], point[2], plt.gca().get_proj()) 19 x3, y3 = ax.transData.transform((x2, y2)) 20 return np.sqrt ((x3 - event.x)**2 + (y3 - event.y)**2) 21 22 23 def calcClosestDatapoint(X, event): 24 distances = [distance (X[i, 0:3], event) for i in range(X.shape[0])] 25 return np.argmin(distances) 26 27 def annotatePlot(X, index): 28 if hasattr(annotatePlot, 'label'): 29 annotatePlot.label.remove() 30 x2, y2, _ = proj3d.proj_transform(X[index, 0], X[index, 1], X[index, 2], ax.get_proj()) 31 annotatePlot.label = plt.annotate( "Value %d" % index, 32 xy = (x2, y2), xytext = (-20, 20), textcoords = 'offset points', ha = 'right', va = 'bottom', 33 bbox = dict(boxstyle = 'round,pad=0.5', fc = 'yellow', alpha = 0.5), 34 arrowprops = dict(arrowstyle = '->', connectionstyle = 'arc3,rad=0')) 35 fig.canvas.draw() 36 37 38 def Print_Pic(X, index): 39 img = cv2.imread('test.png') 40 ax1 = fig.add_subplot(1,1,2) #これでエラーが出る 41 plt.show() 42 43 44 def onMouseMotion(event): 45 closestIndex = calcClosestDatapoint(X, event) 46 annotatePlot (X, closestIndex) 47 Print_Pic (X, closestIndex) 48 49 fig.canvas.mpl_connect('motion_notify_event', onMouseMotion) 50 plt.show() 51 52 53if __name__ == '__main__': 54 X = np.random.random((30,5)) 55 X=np.array(X, dtype=np.float64) 56 visualize3DData (X)

補足情報

Anaconda3
Python 3.7
Jupyter Notebookで描画しています。

エラー内容

ax1 = fig.add_subplot(1,1,2)を追加した際に以下のエラーがマウスイベント発生時に表示されます。

Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\user\anaconda3\lib\tkinter_init_.py", line 1892, in call
return self.func(*args)
File "C:\Users\user\anaconda3\lib\site-packages\matplotlib\backends_backend_tk.py", line 272, in motion_notify_event
FigureCanvasBase.motion_notify_event(self, x, y, guiEvent=event)
File "C:\Users\user\anaconda3\lib\site-packages\matplotlib\backend_bases.py", line 1903, in motion_notify_event
self.callbacks.process(s, event)
File "C:\Users\user\anaconda3\lib\site-packages\matplotlib\cbook_init_.py", line 229, in process
self.exception_handler(exc)
File "C:\Users\user\anaconda3\lib\site-packages\matplotlib\cbook_init_.py", line 81, in exception_printer
raise exc
File "C:\Users\user\anaconda3\lib\site-packages\matplotlib\cbook_init
.py", line 224, in process
func(*args, **kwargs)
File "<ipython-input-1-848925ac800b>", line 48, in onMouseMotion
Print_Pic (X, closestIndex)
File "<ipython-input-1-848925ac800b>", line 41, in Print_Pic
ax1 = fig.add_subplot(1,1,2) #これでエラーが出る
File "C:\Users\user\anaconda3\lib\site-packages\matplotlib\figure.py", line 1402, in add_subplot
ax = subplot_class_factory(projection_class)(self, *args, **kwargs)
File "C:\Users\user\anaconda3\lib\site-packages\matplotlib\axes_subplots.py", line 39, in init
self._subplotspec = SubplotSpec._from_subplot_args(fig, args)
File "C:\Users\user\anaconda3\lib\site-packages\matplotlib\gridspec.py", line 689, in _from_subplot_args
raise ValueError(
ValueError: num must be 1 <= num <= 1, not 2

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

etherbeg

2021/04/02 21:19

実行時に表示されたエラーも全文をコードブロックを使って質問文内に記載してください。
guest

回答1

0

"ValueError: num must be 1 <= num <= 1, not 2"(「エラー内容」の見出しの段落に記載されているエラー)について:

add_subplotメソッドが位置引数として3つの整数をとるとき、1つめの整数は、描画領域全体をグリッドで区切って描画区画を作った際の、グリッドの縦の行数、2つめの整数は同じくグリッドの横の列数、3つめの整数はそのグリッドの中でのプロットの配置位置です。
ax1 = fig.add_subplot(1,1,2) では、区画はひとつ (1x1) しか作られていないのに2区画目に配置しようとしているのでエラーが出ています。

ちなみに上の方にある ax = fig.add_subplot(111, projection = '3d') は、ax = fig.add_subplot(1, 1, 1, projection = '3d') を意味します。これは ax = fig.add_subplot(projection = '3d') と書くこともできます(省略すると 1,1,1 と指定したものとみなされる)。


"AttributeError: 'AxesSubplot' object has no attribute 'get_proj'"(「発生している問題・エラーメッセージ」の見出しの段落に記載されているエラー)について:

distance関数の中の

python

1x2, y2, _ = proj3d.proj_transform(point[0], point[1], point[2], plt.gca().get_proj())

の箇所を

python

1x2, y2, _ = proj3d.proj_transform(point[0], point[1], point[2], ax.get_proj())

に修正します。

Print_Pic関数の呼び出しが追加されたことにより、 plt.gca()で取得されるオブジェクトが、本来取得すべきオブジェクトと違うものになっていることが原因です。
ここは本来常に同じオブジェクトを参照すべき箇所ですので、その本来参照すべきオブジェクトであるaxを決めうちで使えば、エラーは出なくなります。実際、annotatePlot関数の中のproj3d.proj_transform関数では最初からそうしています。


以上でエラーは出なくなると思いますが、表示結果は作りたいものとは程遠いと思います。しかしそれはまた別の問題ということで…。

以下の解説記事も参考になるかと思いますのでご紹介しておきます。


(追記)すみません、勘違いしていました。画像は3Dグラフ上に表示するんじゃなくて、グラフの外に表示するんですね。
となると、上のエラー2件に関して述べたことが、ここでも関係してきそうです。ひとつは描画領域の区画の仕方と区画の指定の仕方、もうひとつは処理対象なるプロットが暗黙的に指定されるのを避けて明示的に指定すること、です。

投稿2021/04/05 03:30

編集2021/04/05 08:20
etherbeg

総合スコア1195

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問