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

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

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

MatplotlibはPythonのおよび、NumPy用のグラフ描画ライブラリです。多くの場合、IPythonと連携して使われます。

Python

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

Q&A

解決済

4回答

3092閲覧

【python】【至急】2つのグラフの交点をプロットする

yowakunaran

総合スコア1

Matplotlib

MatplotlibはPythonのおよび、NumPy用のグラフ描画ライブラリです。多くの場合、IPythonと連携して使われます。

Python

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

0グッド

1クリップ

投稿2023/05/19 02:35

実現したいこと

2つのグラフがあり、その交点をプロットしたい。例えば、y=cos xとy=cos(π cos x)の交点を自動的にもとめて、プロットしたいです。
交点の座標は簡単には求められないものです。

前提

y=cos xとy=cos(π cos x)の交点を自動的に算出して、プロットするようなプログラムを書きたい。Pythonで無理なら、別の言語でも大丈夫です。

np.argwhereを使ってみたものの、xの値はnp.linspaceなどで離散的に取得するので、交点となる無理数の解はリストの中に入らないため、プロットされない。

一方で、absなどで丸め誤差を利用するも、2つのグラフが接近する部分で無駄な部分にプロットされる。

そのため、複雑なグラフでは別のアプローチをとるべきなのかなと思いましたが、当方初心者で何もわかりません。調べてみたものの何もヒットしませんでしたので、ここで質問させてください。

今までは、LaTeXでグラフを書いていたのですが、LaTeXでは自動的にグラフの交点を算出するコマンドがありました。しかし、LaTeXでは複雑なグラフを書くことができず、matplotlibを使おうと思って、最近Pythonを学習し始めました。

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

xの値はnp.linspaceなどで離散的に取得するので、交点となる無理数の解はリストの中に入らない。

absなどで丸め誤差を利用するも、2つのグラフが接近する部分で無駄な部分にプロットされる。

そのため、別のアプローチで交点を求めることが必要?

該当のソースコード

Python

1import matplotlib.pyplot as plt 2import numpy as np 3 4N = 99 5x_min = 0 6x_max = 2 * np.pi 7 8def f(x): 9 return np.cos(x) 10 11def g(x): 12 return np.cos(np.pi * f(x)) 13 14x = np.linspace(x_min, x_max, N) 15y1 = f(x) 16y2 = g(x) 17 18idx = np.argwhere(np.sign(y1 - y2) == 0) 19 20plt.plot(x[idx], y1[idx],'.', markersize=8) 21 22plt.plot(x, y1) 23plt.plot(x, y2) 24 25plt.show()

イメージ説明

試したこと

・Nの数を増やしてみたものの、交点の数は増えない。
・absを使って丸め誤差を利用するも、不要な点がプロットされてしまう。

補足情報(FW/ツールのバージョンなど)

VS codeを使用

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

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

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

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

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

guest

回答4

0

「2つのグラフがあり、その交点をプロットしたい。
例えば、y=cos xとy=cos(π cos x)の交点を自動的にもとめて、プロットしたいです。」
の部分だけをChatGPTさんに丸投げしてプログラムを書いてもらいました。

Python

1import numpy as np 2import matplotlib.pyplot as plt 3 4 5# Functions 6def f1(x): 7 return np.cos(x) 8 9def f2(x): 10 return np.cos(np.pi * np.cos(x)) 11 12# Finding intersection points 13x = np.linspace(-2 * np.pi, 2 * np.pi, 1000) 14y1 = f1(x) 15y2 = f2(x) 16intersection_points = np.argwhere(np.diff(np.sign(y1 - y2))).flatten() 17x_points = x[intersection_points] 18y_points = y1[intersection_points] 19 20# Plotting 21plt.plot(x, y1, label="y = cos(x)") 22plt.plot(x, y2, label="y = cos(pi*cos(x))") 23plt.plot(x_points, y_points, "o", label="Intersection points") 24plt.legend() 25plt.show()

投稿2023/05/19 02:58

poto568

総合スコア250

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

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

yowakunaran

2023/05/19 05:08 編集

ありがとうございます ChatGPTすごいですね 重解の場合は、条件式使って書けばいいですね!
guest

0

すでに解決していますが、グラフ描画のために線分の組のデータは作成済みなので、それらが使えそうです。
すなわちxの開始~終了までfとgの各線分の交点を求めればよいかと思います。
この手法だと、Nが小さい(間隔が粗い)場合でも見た目と同じ場所に交点を打てます。

Python

1import numpy as np 2import matplotlib.pyplot as plt 3 4 5N = 99 6x_min = 0 7x_max = 2 * np.pi 8 9def f(x): 10 return np.cos(x) 11 12def g(x): 13 return np.cos(np.pi * f(x)) 14 15# 交点を求める 16# ChatGPTの生成したコードなので注意 17def find_intersection(line1, line2): 18 xdiff = (line1[0][0] - line1[1][0], line2[0][0] - line2[1][0]) 19 ydiff = (line1[0][1] - line1[1][1], line2[0][1] - line2[1][1]) 20 21 def det(a, b): 22 return a[0] * b[1] - a[1] * b[0] 23 24 div = det(xdiff, ydiff) 25 if div == 0: 26 # 線分が平行であるため交点は存在しない 27 return None 28 29 d = (det(*line1), det(*line2)) 30 x = det(d, xdiff) / div 31 y = det(d, ydiff) / div 32 33 if not (min(line1[0][0], line1[1][0]) <= x <= max(line1[0][0], line1[1][0])): 34 # 交点が線分の範囲外にあるため交点は存在しない 35 return None 36 37 if not (min(line1[0][1], line1[1][1]) <= y <= max(line1[0][1], line1[1][1])): 38 # 交点が線分の範囲外にあるため交点は存在しない 39 return None 40 41 return x, y 42 43 44x = np.linspace(x_min, x_max, N) 45y1 = f(x) 46y2 = g(x) 47 48# 各線分の交点を求める 49pts = [] 50for xs, xe, y1s, y1e, y2s, y2e in zip(x[0:-1], x[1:], y1[0:-1], y1[1:], y2[0:-1], y2[1:]): 51 t = find_intersection( ((xs,y1s),(xe,y1e)), ((xs,y2s),(xe,y2e)) ) 52 if t: 53 pts.append(t) 54pts = np.array(pts) 55 56plt.plot(x, y1) 57plt.plot(x, y2) 58plt.plot(pts[:,0], pts[:,1],'.', markersize=8) 59 60plt.show()

イメージ説明

投稿2023/05/19 06:30

編集2023/05/19 06:36
can110

総合スコア38234

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

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

yowakunaran

2023/05/19 06:45

これ精度がものすごくたかいですね! 解読してみたいと思います!
guest

0

既に解決済みですので御参考です。

先に交点の x 座標を求める方針で考えてみました。

  • 交点の x 座標(xr)は scipy.optimize.root() に差分の関数 h(x) とグラフから読み取った近似解 [1.2, 2.5, 3.1, 3.8, 5.1] を与えて求める

  • 交点の x 座標(xr)に最も近い x 軸配列(xl)の要素のインデックス(ind_xr)は bisect.bisect_left() を利用して求める

    • a は単調増加数列」を条件として,a[n-1] < x <= a[n] のとき bisect_left(a, x)n を返す

    • 次に xa[n-1]a[n] のどちらに近いかを調べてインデックスを決定

下記に記述例を示します。
なお,実際の交点とマークのずれを目立たなくするために N = 629 に増やしています。

Python

1import matplotlib.pyplot as plt 2import numpy as np 3from scipy.optimize import root 4from bisect import bisect_left 5 6N = 629 7x_min = 0 8x_max = 2 * np.pi 9 10def f(x): 11 return np.cos(x) 12 13def g(x): 14 return np.cos(np.pi * f(x)) 15 16def h(x): 17 return f(x) - g(x) 18 19xl = np.linspace(x_min, x_max, N) 20y1 = f(xl) 21y2 = g(xl) 22 23xr = root(h, [1.2, 2.5, 3.1, 3.8, 5.1]).x 24print(xr) 25## [1.18427679 2.48133238 3.14159265 3.80185292 5.09890852] 26 27ind_xr = np.empty_like(xr, dtype=int) 28for i, xi in enumerate(xr): 29 n = bisect_left(xl, xi) 30 ind_xr[i] = n - 1 if xl[n] - xi > xi - xl[n - 1] else n 31 32np.set_printoptions(suppress=True) 33print(xl[ind_xr] - xr) 34## [-0.00367827 -0.00007449 0.00000001 0.00007449 0.00367827] 35 36plt.plot(xl, y1) 37plt.plot(xl, y2) 38plt.plot(xl[ind_xr], y1[ind_xr], '.', markersize=8) 39 40plt.show()

グラフ出力

投稿2023/06/11 14:26

編集2023/06/11 14:43
little_street

総合スコア302

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

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

0

ベストアンサー

個々の関数(?)のグラフを描画することができるのであれば,画像的にANDを取ればどうですか?
(質問文に示されたグラフで言えば,オレンジ色のグラフと緑色のグラフが重なっている個所を画像処理的に見つけるという話)

単純には,ANDで残った領域(グラフの太さや交差具合次第になるけど,小さな領域になることを期待)の真ん中(重心とか)の位置に点をプロットすればどうでしょうか.
複数の交点があれば複数の領域が得られるので,それらに同じことをすればよいだけです.

……っていうような絵的な結果だけが欲しいだけじゃなくて「交点の座標の値も示す必要があるんだよ」という場合でも,この方法で

  • 交点の個数
  • それらの座標の荒い値

が得られるのだとすれば,あとはそこから座標を Refinement すれば良いのではないでしょうか.「荒い」とは言え,その値は何らかの Solver に初期値として与えるには十分なんじゃないかな,と.(例えば数ステップのイテレーションで十分に精度改善できそうな気がします.)

投稿2023/05/19 02:50

編集2023/05/19 02:52
fana

総合スコア11634

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

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

fana

2023/05/19 02:56 編集

グラフの線の太さを細くするとか,グラフ画像の解像度を上げる,とかすることで「荒い座標」の精度はマシになるかな.
fana

2023/05/19 03:00

> 交点の座標は簡単には求められない ということらしいので,解析解を求めることが望めないなら,数値計算みたいなことをすることになるのだろうから,その実施に必要な情報を得る手段として手っ取り早いと思う話を書いた.
fana

2023/05/19 03:10

> 真ん中(重心とか) だとちょっと……みたいな場合には, 領域の各画素位置での関数値をちゃんと調べてやれば「グラフ画像のピクセル精度での」最良位置にできるかと.
yowakunaran

2023/05/19 05:00

そういうアプローチもあるんですね。 画像認識の分野はノータッチなので難しいですが、やってみようと思いました!
fana

2023/05/19 06:17

まぁ,「交点」とは字のごとく「交わる場所 = 両方のグラフが共通して通る場所」ですから, グラフの絵の上で両方の線が描画されている場所 を見つけてやろう,というだけの話です.
fana

2023/05/19 07:46

※現時点で(何故か)この回答がベストアンサーになってますが,実際に他の方法があなたの問題解決に寄与した場合にはそっちに変えてもらえれば良いかと思います.
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問