pyplotで中学数学のグラフを書く(その２)

<h2>前書き</h2>
投稿済みの記事[pyplotで中学数学のグラフを書く](https://qiita.com/mookouchi/items/b4ff00440d0f4101e8f6)の続き。

前回の最後の時点から再開します。

コードの再掲

```python:figure3.py
import matplotlib
import matplotlib.pyplot as plt
import numpy as np

# 日本語化
matplotlib.rc('font', family='BIZ UDGothic')

# データの作成
# 横軸(X軸)
x = np.arange(-10., 10., 0.01)
# 縦軸(Y軸)
y1 = 2 * x
y2 = 3 * x + 10

# データの描画
plt.plot(x, y1, x, y2)

# 軸のラベル
plt.xlabel('X軸')
plt.ylabel('Y軸')

# 格子の表示
plt.grid(True)

# 表示
plt.show()
```
実行結果がこちら。
![python_figure3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/667657/600112a7-ad66-a078-9c99-25c7c4ee448d.png)

今回は以下の内容を作っていきます。

- 縦横比が1:1になっていない。
- 始点、終点でグラフが切れている。(そのようなグラフもあるのですが、-∞<x<∞のグラフを最初に学ぶので、そのように「見える」方が良い。)
- 原点(座標[0,0])がわかりにくい。

<h2>環境</h2>

- Windows10 build 18363.959
- Python 3.8.5
- matplotlib 3.3.0
- numpy 1.19.1

<h2>原点をわかりやすくする</h2>
ともあれ、原点がわかりやすい方がグラフとしては見やすいと思います。

```python:figure4.py
# 横軸(horizon)ゼロの太線化
plt.axhline(0, linewidth=2, color="gray")

# 縦軸(Vertical)ゼロの太線化
plt.axvline(0, linewidth=2, color="gray")
```
- 今回は`plt.grid`の下に追加します。
- `axhline`は水平線(Horizon)を、指定した値の位置に描く処理です。今回は、"0"の位置に太さ"2"、色"gray"で設定しています。
- `axvline`は垂直線(Vertical)を、指定した値の位置に描く処理です。今回は、"0"の位置に太さ"2"、色"gray"で設定しています。

実行すると、
![python_figure4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/667657/34c45729-d292-2926-3ad0-6f424aef55d7.png)
と、いい感じで原点(座標(0, 0))が見やすくなったと思います。

<h2>原点を中央にする(描画範囲を設定する)</h2>
引き続き、次は原点を中央にしたいと思いますが、単純に「上下左右の描画範囲(大きさ)が同じなら、原点は中央になる」という考えで、`plt.axis`を使用して設定してみます。

```python:figure5.py
# 表示範囲の設定
plt.axis([-22, 22, -22, 22])
```

- 今回は`plt.xlabel`の上に追加します。
- 描画範囲はX軸の左端"-22"から右端"22"とY軸の下端"-22"から上端"22"としています。今回似たような値を使って分かりにくいので、ちょっとずつ値を変えて、描画がどのように変わるのか試してみるのも良いと思います。
- 設定値は切りのいい値でも良いと思いますが、描画の端と格子が重なるのも個人的に好みでない為、格子線が描かれる(と考えられる)値より少し大きい値を指定しています。

![python_figure5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/667657/b0b0459a-5bb9-97a7-c985-aed76d1f1d65.png)
いい感じで、原点が中央に来たと思います。

さて、この状態でオレンジのグラフは上端が途切れているように見えますが、描画ウインドウの下端にあるアイコン![pyplot_icon.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/667657/f83998ec-f97f-18fb-4711-e7eb286c130c.png)をオンにしてグラフ内をドラッグすると描画範囲を動かせるので、少し上の方まで見えるようにずらしてみます。
![python_figure5-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/667657/5b603dc0-23f2-da74-5620-f6538b010544.png)
データの端まできちんと描画されています。
つまり、「データ上では描画していても描画範囲を指定したことで見えない部分がでてくる」という事なので、逆に「描画範囲外までデータを設定すれば、見かけ上`-∞<x<∞`のグラフが描けそう」と言えます。

で、あれば元のデータを増やせば良さそうなので、`x`を設定しているところでデータの範囲を広げます。

```python:figure6.py
# 横軸(X軸)
# x = np.arange(-10., 10., 0.01)
x = np.arange(-25., 25., 0.01)
```
![python_figure6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/667657/66ba6b35-4131-5485-2813-22078685b775.png)
青いグラフも描画範囲内の端から端まで表示されるようになりました。
先ほどの様に、![pyplot_icon.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/667657/f83998ec-f97f-18fb-4711-e7eb286c130c.png)を使って描画をずらすとデータの端まで、描画されていることがわかります。
![python_figure6-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/667657/2217abb6-71a9-0dcf-ead9-2391d94e1939.png)

<h2>縦横比を1:1にする</h2>
軸の表示範囲を`plt.axis`で設定した際に、格子が正方形からやや長方形になってしまったので、手当てしていきます。

```python:figure7.py
# 表示の縦横比を揃える
ax = plt.axes(label='xxx')
ax.set_aspect('equal')
```
- `plt.axis`の上に記述します。
- `set_aspect`では数値の指定もできます。(y/x)
    - 例えば"3/4"だと横4、縦3(昔のブラウン管テレビ)の比率、"9/16"だと横16、縦9(最近のワイド画面)の比率になります。

![python_figure7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/667657/1fdf4e6d-071e-df37-bfc3-aa3dd46f9282.png)
四隅の部分を見る限りでは、縦横比が1:1になりました。
ただ、X軸の目盛りが減ってしまい、格子としては長方形になってしまっています。
そこで、目盛りをX,Y両方の軸に対して設定します。

```python:figure7.py
plt.xticks(np.arange(-25, 25, 5))
plt.yticks(np.arange(-25, 25, 5))
```
- `plt.axis`より上に記述します。今回は`ax.set_aspect`と`plt.plot`の間に記述します。
- `-25 <= x < 25`、`-25 <= y < 25`で両軸とも5刻みで目盛りを設定しています。

![python_figure7-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/667657/f3dfe862-94d2-7ae2-e037-5fccf803bba5.png)

なお、`xticks`、`yticks`を使うと、指定箇所以外の目盛りが消えてしまうので、注意が必要です。
![python_figure7-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/667657/ef6a8a2c-89be-3737-844c-4c1dc266947e.png)

<h2>二次関数グラフを追加する</h2>
さて、中学数学らしく、二次関数と三角関数からsin(正弦)のグラフをそれぞれ追加してみます。

```python:figure8.py
y3 = x ** 2
y4 = np.sin(x)
```
- sin関数はnumpyにあるものを使います。

作成したデータを`plt.plot`に、追加します。

```python:figure8.py
plt.plot(x, y1, x, y2, x, y3, x, y4)
```
![python_figure8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/667657/d0bee0ef-5463-54fb-3e3d-edb5faa38e4c.png)
最初のグラフと比べるとたいぶ「いい感じ」になりました。

<h2>後書き</h2>
ここまでできれば、見栄えがだいぶ整うので、あとはy1～y4に与える式をいろいろと変えたり、xの刻み幅を変えたりして、どんなグラフになるか試すのも面白いと思います。
※matplotlib.pyplotは今回の使い方では、座標データを順にプロットし、点と点の間を直線で補間しています。
また、グラフが増えたので「凡例」があっても良さそうです。

私が学生の頃(？年前)は、グラフと言えば手書きが基本だったので、こういったツールで「自分でいろいろ試せる」環境が整っている昨今がうらやましい限りですが、昔を思い出しつつ、今になっていろいろやってみるのもいい感じに思いました。

最後に、最終版のコードを手直し(前半に体裁の設定、後半にグラフの描画)したものを掲載しておきます。

```python:figure.py
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
import math

# 日本語化
matplotlib.rc('font', family='BIZ UDGothic')

# グラフの体裁を整える。
# 表示の縦横比を揃える
ax = plt.axes(label='xxx')
ax.set_aspect('equal')

# 目盛りを整える
# X軸
plt.xticks(np.arange(-25, 25, 5))
# Y軸
plt.yticks(np.arange(-25, 25, 5))

# 表示範囲の設定
plt.axis([-22, 22, -22, 22])

# 軸のラベル
plt.xlabel('X軸')
plt.ylabel('Y軸')

# 格子の表示
plt.grid(True)

# 横軸(horizon)ゼロの太線化
plt.axhline(0, linewidth=2, color="gray")

# 縦軸(Vertical)ゼロの太線化
plt.axvline(0, linewidth=2, color="gray")

# データの作成
# 横軸(X軸)
x = np.arange(-25., 25., 0.01)
# 縦軸(Y軸)
y1 = 2 * x
y2 = 3 * x + 10
y3 = x ** 2
y4 = np.sin(x)

# データの描画
plt.plot(x, y1, x, y2, x, y3, x, y4)

# 表示
plt.show()
```