teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

2

d

2019/03/05 05:53

投稿

tiitoi
tiitoi

スコア21960

answer CHANGED
@@ -1,11 +1,12 @@
1
- 仕様明確でないのでアイデア
1
+ fana さん回答してくさった方法で実装してみました。
2
2
 
3
- 行列の各要素を4点で構成される正方形と考え、回転している x 軸に垂直な直線が交わる正方形を求めて、その値の平均をとる。
4
3
 
5
4
  ----
6
5
 
7
6
 
8
7
  ```python
8
+ import matplotlib.pyplot as plt
9
+ from matplotlib.patches import Rectangle
9
10
  import numpy as np
10
11
 
11
12
  mat = np.array([[3, 4, 6, 9, 0, 8],
@@ -14,54 +15,85 @@
14
15
  [0, 4, 3, 7, 1, 2],
15
16
  [4, 2, 6, 1, 0, 9],
16
17
  [7, 2, 1, 6, 2, 8]], dtype=float)
18
+ angle = 10 # x 軸の回転角度 (degree)
17
- assert mat.shape[0] % 2 == 0 and mat.shape[1] % 2 == 0
19
+ radius = np.array(mat.shape) // 2 # 半径
18
20
 
21
+ def create_rotation_matrix(angle):
19
- theta = 10
22
+ t = np.deg2rad(angle)
23
+ return np.array([[np.cos(t), -np.sin(t)],
24
+ [np.sin(t), np.cos(t)]])
25
+ R = create_rotation_matrix(-angle) # x 軸の回転方向とは逆の方向に回転する回転行列
20
26
  ```
21
27
 
22
28
  ```
29
+ # 各セルの4点の座標を作成する。
23
30
  cells = []
31
+ id_ = 0 # あとでどのセルが含まれているのか確認するための識別子 (デバッグ用)
24
32
  for (i, j), value in np.ndenumerate(mat):
25
- # 行列 (i, j) 成分を行列中心を原とする標準座標系の点 (x, y) に変換する
33
+ # セル左下の点 (x, y) を定義する
26
- # (x, y) = j - rows // 2, i - cols // 2
34
+ x, y = j - radius[1], radius[0] - i - 1
27
- x, y = j - mat.shape[1] // 2, i - mat.shape[0] // 2
28
- # セルを構成する点
35
+ # セルを構成する4を作成する。
29
36
  rect = np.array([[x, y], [x + 1, y], [x + 1, y + 1], [x, y + 1], [x, y]])
37
+ # セルを構成する4点を回転させる。
38
+ rect = rect.dot(R.T)
39
+
30
- cells.append([rect, value])
40
+ cells.append((id_, rect, value))
41
+ id_ += 1
31
42
  ```
32
43
 
44
+ 各区別 [x_i, x_{i + 1}] に含まれるセルを見つけて、その値の平均を計算する。
45
+
46
+ ```
47
+ edges = np.arange(-radius[1], radius[1] + 1)
48
+
49
+ for left, right in zip(edges, edges[1:]):
50
+ values = []
51
+ for id_, rect, value in cells:
52
+ if np.any((left <= rect[:, 0]) & (rect[:, 0] <= right)):
53
+ values.append((id_, value)) # セルの4隅の1点でも [left, right] に含まれる場合
54
+ values = sorted(values, key=lambda x: x[0]) # 見やすいように id でソートする。
55
+ mean = np.mean([x[1] for x in values]) # 平均
56
+ print('{} <= x <= {}:\n value: {}\n mean: {}'.format(
57
+ left, right, values, mean))
58
+ ```
59
+
60
+ ```
61
+ -3 <= x <= -2:
62
+ value: [(0, 3.0), (6, 2.0), (12, 4.0), (18, 0.0), (19, 4.0), (24, 4.0), (25, 2.0), (30, 7.0), (31, 2.0)]
63
+ mean: 3.111111111111111
64
+ -2 <= x <= -1:
65
+ value: [(0, 3.0), (1, 4.0), (6, 2.0), (7, 8.0), (12, 4.0), (13, 8.0), (18, 0.0), (19, 4.0), (20, 3.0), (25, 2.0), (26, 6.0), (31, 2.0), (32, 1.0)]
66
+ mean: 3.6153846153846154
67
+ -1 <= x <= 0:
68
+ value: [(1, 4.0), (2, 6.0), (7, 8.0), (8, 5.0), (13, 8.0), (14, 1.0), (15, 0.0), (19, 4.0), (20, 3.0), (21, 7.0), (26, 6.0), (27, 1.0), (32, 1.0), (33, 6.0)]
69
+ mean: 4.285714285714286
70
+ 0 <= x <= 1:
71
+ value: [(2, 6.0), (3, 9.0), (8, 5.0), (9, 0.0), (14, 1.0), (15, 0.0), (16, 3.0), (20, 3.0), (21, 7.0), (22, 1.0), (27, 1.0), (28, 0.0), (33, 6.0), (34, 2.0)]
72
+ mean: 3.142857142857143
73
+ 1 <= x <= 2:
74
+ value: [(3, 9.0), (4, 0.0), (9, 0.0), (10, 3.0), (15, 0.0), (16, 3.0), (17, 1.0), (22, 1.0), (23, 2.0), (28, 0.0), (29, 9.0), (34, 2.0), (35, 8.0)]
75
+ mean: 2.923076923076923
76
+ 2 <= x <= 3:
77
+ value: [(4, 0.0), (5, 8.0), (10, 3.0), (11, 5.0), (16, 3.0), (17, 1.0), (23, 2.0), (29, 9.0), (35, 8.0)]
78
+ mean: 4.333333333333333
79
+ ```
80
+
33
81
  ```python
34
82
  # デバッグ用
35
83
  ###################################################################
36
- from matplotlib.patches import Rectangle
37
- import matplotlib.pyplot as plt
38
84
  fig, ax = plt.subplots(figsize=(6, 6))
39
85
 
40
86
  # 各セルを描画する。
41
- for rect, value in cells:
87
+ for id_, rect, value in cells:
42
88
  ax.plot(rect[:, 0], rect[:, 1], c='gray', alpha=0.5) # セルの枠線
43
89
  cx, cy = (rect[0] + rect[2]) / 2 # セルの中心
90
+ s = '{}:{}'.format(id_, value)
44
- ax.text(cx, cy, value, ha='center', va='center') # 値
91
+ ax.text(cx, cy, s, ha='center', va='center', rotation=-angle) # 値
45
92
  ax.autoscale(False)
46
-
47
- # x 軸に垂直な直線を描画する。
48
- # theta だけ回転させた場合、x 軸の傾きは tan(theta), y 軸の傾きは tan(theta + 90) となることに注意すると
49
- for j in range(mat.shape[1]):
50
- x = j - mat.shape[1] // 2 + 0.5
51
- # (x', y') を通り、傾き m の直線 ===> (y - y') = m (x - x')
52
- xs = np.linspace(*ax.get_xlim(), 100)
53
- ys = (xs - x) * np.tan(np.radians(theta + 90))
54
- ax.plot(xs, ys, c='b', lw=1)
55
-
56
- # 回転後の x 軸、y 軸を描画する
93
+ # x 軸、y 軸を引く
94
+ ax.axhline(), ax.axvline()
95
+ # 垂直線を引く
57
- xs = np.linspace(*ax.get_xlim(), 100)
96
+ ax.vlines(edges, *ax.get_xlim(), alpha=0.5)
58
- ys = xs * np.tan(np.radians(theta))
59
- ax.plot(xs, ys, c='k', lw=3)
60
-
61
- ys = xs * np.tan(np.radians(theta + 90))
62
- ax.plot(xs, ys, c='k', lw=3)
63
97
  ```
64
98
 
65
- ![イメージ説明](e52a938e4633f9fea57ff1dc413a6e33.png)
99
+ ![イメージ説明](45ac21cb6f1209e2647976c8bc85f0ae.png)
66
-
67
- 青い直線が通るセルを調べてその値の平均をとる。

1

d

2019/03/05 05:53

投稿

tiitoi
tiitoi

スコア21960

answer CHANGED
@@ -16,18 +16,18 @@
16
16
  [7, 2, 1, 6, 2, 8]], dtype=float)
17
17
  assert mat.shape[0] % 2 == 0 and mat.shape[1] % 2 == 0
18
18
 
19
- theta = 30
19
+ theta = 10
20
20
  ```
21
21
 
22
22
  ```
23
23
  cells = []
24
- for (i, j), v in np.ndenumerate(mat):
24
+ for (i, j), value in np.ndenumerate(mat):
25
- # 行列の (i, j) 成分を行列の中心を原点とする標準座標系の点 (x, y) に変換する式 ===>
25
+ # 行列の (i, j) 成分を行列の中心を原点とする標準座標系の点 (x, y) に変換する式
26
26
  # (x, y) = j - rows // 2, i - cols // 2
27
27
  x, y = j - mat.shape[1] // 2, i - mat.shape[0] // 2
28
28
  # セルを構成する点
29
- r = np.array([[x, y], [x + 1, y], [x + 1, y + 1], [x, y + 1], [x, y]])
29
+ rect = np.array([[x, y], [x + 1, y], [x + 1, y + 1], [x, y + 1], [x, y]])
30
- cells.append([r, v])
30
+ cells.append([rect, value])
31
31
  ```
32
32
 
33
33
  ```python
@@ -38,17 +38,17 @@
38
38
  fig, ax = plt.subplots(figsize=(6, 6))
39
39
 
40
40
  # 各セルを描画する。
41
- for r, v in cells:
41
+ for rect, value in cells:
42
- ax.plot(r[:, 0], r[:, 1], c='gray', alpha=0.5) # セルの枠線
42
+ ax.plot(rect[:, 0], rect[:, 1], c='gray', alpha=0.5) # セルの枠線
43
- cx, cy = (r[0] + r[2]) / 2 # セルの中心
43
+ cx, cy = (rect[0] + rect[2]) / 2 # セルの中心
44
- ax.text(cx, cy, v, ha='center', va='center') # 値
44
+ ax.text(cx, cy, value, ha='center', va='center') # 値
45
45
  ax.autoscale(False)
46
46
 
47
47
  # x 軸に垂直な直線を描画する。
48
48
  # theta だけ回転させた場合、x 軸の傾きは tan(theta), y 軸の傾きは tan(theta + 90) となることに注意すると
49
- for j in range(mat.shape[1] + 1):
49
+ for j in range(mat.shape[1]):
50
+ x = j - mat.shape[1] // 2 + 0.5
50
51
  # (x', y') を通り、傾き m の直線 ===> (y - y') = m (x - x')
51
- x = j - mat.shape[1] // 2
52
52
  xs = np.linspace(*ax.get_xlim(), 100)
53
53
  ys = (xs - x) * np.tan(np.radians(theta + 90))
54
54
  ax.plot(xs, ys, c='b', lw=1)
@@ -62,6 +62,6 @@
62
62
  ax.plot(xs, ys, c='k', lw=3)
63
63
  ```
64
64
 
65
- ![イメージ説明](e84dc4262a832cd4515f21df8dbb7ca9.png)
65
+ ![イメージ説明](e52a938e4633f9fea57ff1dc413a6e33.png)
66
66
 
67
67
  青い直線が通るセルを調べてその値の平均をとる。