Kei Minagawa's Blog

皆川圭(@keimina)のブログ、Pythonで試したことを書いていきます

Pythonで2次元データ作成ー三角形に収まる点の集合

前回の続きです。今回は、前回に引き続き、Pythonで三角形に収まる点の集合を作成します。アルゴリズムは簡単で、ランダムに点を打ち、それが三角形の内側であれば点を残す、三角形の外側であれば点を消すを繰り返すだけです。「三角形の内側か?」を判定する関数を作成し、その関数に点の位置を次々と問い合わせればよいでしょう。ここでは三角形は直角二等辺三角形ということにします。

前回の記事:
keimina.hatenablog.jp

1. 三角形の領域の定義

実装する前に使用する三角形の形を明確にします。以下のように使用する三角形の領域を定義します。

三角形の領域の定義:
 x-y座標上の点(x, y)で「x > 0 かつ y > 0 かつ y < -x + 1」を満たす点の集合

この条件を満たす点(x, y)は3つの点(0, 0)と(1, 0)と(0, 1)を結ぶとできる三角形の領域を構成します。なぜそうなるかについては、以下の①②③を参考にしてください。

①「x > 0 かつ y > 0」 の領域は x-y座標の右上の領域すべてを表します。
②「y < -x + 1』の領域 は 直線 y = -x + 1 より下側の領域をすべてを表します。
③「x > 0 かつ y > 0 かつ y < -x + 1」 の領域は上記①②の領域が重なった領域であり、三角形になります。

①②③を図で表すと以下になります。

f:id:keimina:20190120142434j:plain
図1. 三角形の領域の定義

2. 三角形の領域内の点であるかどうかを判定する関数を作成する

点(x, y)が上記1.で定義したの三角形の領域内の点であるかどうかを判定する関数を実装します。以下のようになります。

def is_inside_triangle(x, y):
    if x >= 0 and \
       y >= 0 and \
       y <= -x + 1:
        # 「xが0以上の領域」かつ「yが0以上の領域」かつ「y=-x+1の直線より下の領域」
        # すなわち点(x,y)が三角形の内側ならTrue
        return True
    else:
        # 三角形の外側ならFalse
        return False


is_inside_triangle関数は引数で与えられた点(x, y)の情報が1.で定義した三角形の内側にあるかどうかを判定します。三角形の内側であればTrue、それ以外はFalseを戻します。

3. コード1(ライブラリを極力使わない場合)

2.で作成した関数を使用することで、三角形に収まる点の集合を求めることができます。ライブラリを極力つかわないで全体のコードを書くとこんな感じになるかと思います。前回の記事のコードにある、is_inside_square関数 を 今回作成したis_inside_triangle関数 に置き換えただけです。

※matplotlibは可視化のため使用

import random
import matplotlib.pyplot as plt

def is_inside_triangle(x, y):
    if x >= 0 and \
       y >= 0 and \
       y <= -x + 1:
        # 「xが0以上の領域」かつ「yが0以上の領域」かつ「y=-x+1の直線より下の領域」
        # すなわち点(x,y)が三角形の内側ならTrue
        return True
    else:
        # 三角形の外側ならFalse
        return False

N = 1000
for _ in range(N):
    # 点を打つ場所をランダムに決める
    x = random.random()
    y = random.random()
    # 決めた点(x, y)が三角形の内側にあればグラフに点を打つ
    if is_inside_triangle(x, y):
        plt.plot(x, y, color='k', marker='.')

# グラフを表示する
plt.gca().set_xlim(-2,2)
plt.gca().set_ylim(-2,2)
plt.gca().set_aspect('equal')
plt.show()

4. コード2(Numupyを使用して書いた場合)

Numpyを使用して書くと以下のようになると思います。これも、前回の記事のコードにある、is_inside_square関数 を 今回作成したis_inside_triangle関数 に置き換えただけです。

import numpy as np
import matplotlib.pyplot as plt

def is_inside_triangle(x, y):
    if x >= 0 and \
       y >= 0 and \
       y <= -x + 1:
        # 「xが0以上の領域」かつ「yが0以上の領域」かつ「y=-x+1の直線より下の領域」
        # すなわち点(x,y)が三角形の内側ならTrue
        return True
    else:
        # 三角形の外側ならFalse
        return False

# 関数をnumpy化する
is_inside_triangle = np.vectorize(is_inside_triangle)

N = 1000

# ランダムに点を打つ場所を決める
x = np.random.random(N)
y = np.random.random(N)

# 三角形の内側にある点だけを抜き出す
conditions = is_inside_triangle(x, y)
x = x[conditions]
y = y[conditions]

# グラフに点を打つ
plt.plot(x, y, color='k', marker='.')

# グラフを表示する
plt.gca().set_xlim(-2,2)
plt.gca().set_ylim(-2,2)
plt.gca().set_aspect('equal')
plt.show()

5. 出力

以下のようなグラフが出力されると思います。Pythonで三角形に収まる点の集合を作成できました。

f:id:keimina:20190120145112p:plain
図2. 出力

以上です。