初等関数のグラフを描く際,$y=\tan x$ や $y=1/x$ などの不連続点を無造作に線でつなぐケースがあったので,不連続点を無造作につなげないようなグラフの描き方をまとめてみた。
- 参考:gnuplot で初等関数のグラフを描く
- gnuplot では不連続点を不用意に繋げない,特に問題なくグラフを描いてくれる。
- 参考:Maxima で初等関数のグラフを描く
- Maxima は gnuplot をバックエンドとしているので,特に問題なくグラフを描いてくれる。
- 参考:Matplotlib で初等関数のグラフを描く
- Matplotlib では,不連続点を無造作につないでグラフにしてしまうので,以下に対処法をまとめてみた。
- 参考:SymPy Plotting Backends で初等関数のグラフを描く
- バックエンドが Matplotlib であるので,不連続点をつないでグラフにしてしまう場合がある。以下に対処法をまとめた。
gnuplot 編
$y = \tan x$ のグラフ
$y \rightarrow +\infty$ から $y \rightarrow -\infty$ に不連続に変化する箇所があっても,gnuplot では特に問題なく plot してくれる。
# なめらかな曲線のために
set samples 200
# x軸 y軸を描く
set zeroaxis
# グリッド(格子)を描く
set grid
#
set xtics ("-2π" -2*pi, "-3π/2" -1.5*pi, "-π" -pi, "-π/2" -0.5*pi, "0" 0, \
"2π" 2*pi, "3π/2" 1.5*pi, "π" pi, "π/2" 0.5*pi)
set xlabel "x"
set ylabel "tan(x)"
set title "gnuplot で tan(x)"
plot [-2*pi:2*pi][-10:10] tan(x) lc 'blue' lw 2 notitle
$y = x^{-1}$ のグラフ
$x = 0$ で $ y \rightarrow -\infty$ から $y \rightarrow +\infty$ に不連続に変化するが,gnuplot では特に問題なく plot してくれる。
reset
# なめらかな曲線のために
set samples 200
# x軸 y軸を描く
set zeroaxis
# グリッド(格子)を描く
set grid
#
set xtics 1
set xlabel "x"
set ylabel "1/x"
set title "gnuplot で 1/x"
plot [-5:5][-10:10] x**(-1) lc 'red' lw 2 notitle
Maxima 編
plot2d()
で $ y = \tan x$ のグラフ
特に問題なくグラフを描いてくれる。
plot2d(
tan(x), [x, -2*%pi, 2*%pi],
[style, [lines, 2, blue]],
[y, -10, 10], grid2d,
[title, "Maxima plot2d() で tan(x)"],
[xtics, %pi/2], [gnuplot_preamble, "set format x '%3.1P π';"]
)$
draw2d()
で $y = \tan x$ のグラフ
特に問題なくグラフを描いてくれる。
draw2d(
line_width = 2, color = "blue",
explicit(tan(x), x, -2*%pi, 2*%pi),
xrange = [-2*%pi, 2*%pi], yrange = [-10, 10],
xaxis = true, yaxis = true,
title = "Maxima draw2d() で tan(x)",
xlabel = "x", ylabel = "tan(x)",
grid = true,
xtics = %pi/2, user_preamble = "set format x '%3.1P π'"
)$
plot2d()
で $y = x^{-1}$ のグラフ
ちょっと警告が出るが,まぁ問題なくグラフを描いてくれる。
plot2d(
1/x, [x, -5, 5], [style, [lines, 2, red]],
[y, -10, 10], grid2d, [title, "Maxima plot2d() で 1/x"],
[xtics, 1]
)$
draw2d()
で $y = x^{-1}$ のグラフ
特に問題なくグラフを描いてくれる。
draw2d(
line_width = 2, color = "red",
explicit(1/x, x, -5, 5),
xrange = [-5, 5], yrange = [-10, 10],
xaxis = true, yaxis = true,
title = "Maxima draw2d() で 1/x",
xlabel = "x", ylabel = "1/x",
grid = true, xtics = 1
)$
Matplotlib 編
モジュールの import
import matplotlib.pyplot as plt
import numpy as np
# 以下はグラフを SVG で Notebook にインライン表示させる設定
%config InlineBackend.figure_formats = ['svg']
# グラフのサイズ,mathtext のフォント設定
plt.rcParams["figure.figsize"] = (6, 4)
plt.rcParams['mathtext.fontset'] = 'cm'
$y = \tan x$ のグラフ
普通に $y = \tan x$ を plt.plot()
すると,以下のグラフのように,$y \rightarrow \infty$ から $y \rightarrow -\infty$ となる不連続なところもつないでグラフにしてしまう。
x = np.linspace(-2*np.pi, 2*np.pi, 1000)
plt.plot(x, np.tan(x), color = 'blue')
# 横軸縦軸の表示範囲
plt.xlim(-2*np.pi, 2*np.pi)
plt.ylim(-10, 10);
np.nan
を使った対処法とオプション設定例
不連続な箇所は無理に線でつながずにグラフにする例。たとえば,y
の絶対値がある程度以上の大きい値なら,その点はグラフに描かないように「欠損値」np.nan
(Not A Number) に置き換える。
x = np.linspace(-2*np.pi, 2*np.pi, 1000)
y = np.tan(x)
# y の絶対値がある程度以上なら「欠損値」np.nan とする例
y[abs(y) > 100] = np.nan
plt.plot(x, y, color = 'blue')
# 横軸縦軸の表示範囲
plt.xlim(-2*np.pi, 2*np.pi)
plt.ylim(-10, 10)
# グリッド(格子線)
plt.grid(linestyle='dotted')
plt.xlabel('$x$', fontsize=12)
plt.ylabel(r'$\tan x$', fontsize=12)
plt.title('Matplotlib で $\\tan x$', fontsize=14)
plt.xticks([-2*np.pi,-1.5*np.pi,-np.pi,-0.5*np.pi, 0,
2*np.pi, 1.5*np.pi, np.pi, 0.5*np.pi],
['$-2\pi$','$-3\pi/2$','$-\pi$','$-\pi/2$','$0$',
'$2\pi$', '$3\pi/2$', '$\pi$', '$\pi/2$'], fontsize=12)
# x軸 y軸
plt.axhline(0, color='black', dashes=(5, 5), linewidth=0.5)
plt.axvline(0, color='black', dashes=(5, 5), linewidth=0.5);
$y = x^{-1}$ のグラフ
$y = x^{-1}$ を普通に plt.plot()
すると,$\displaystyle \lim_{x\rightarrow -0} \frac{1}{x} \rightarrow -\infty$ と $\displaystyle \lim_{x\rightarrow +0} \frac{1}{x} \rightarrow +\infty$ の不連続点をつないでグラフにしてしまう。
x = np.linspace(-5, 5, 1000)
plt.plot(x, x**(-1), color = 'red')
# 横軸縦軸の表示範囲
plt.xlim(-5, 5)
plt.ylim(-10, 10);
np.nan
を使った対処法とオプション設定例
不連続な箇所は無理に線でつながずにグラフにする例。例えば,$y = x^{-1}$ は $x=0$ 以外では単調減少関数なので,$y$ の値が増加するようなら,その点はグラフに描かないように「欠損値」np.nan
に置き換える。
x = np.linspace(-5, 5, 1000)
y = x**(-1)
# y が増加したら「欠損値」np.nan とする例
y[1:][np.diff(y) > 0] = np.nan
plt.plot(x, y, color = 'red')
# 横軸縦軸の表示範囲
plt.xlim(-5, 5)
plt.ylim(-10, 10)
# x の目盛を 1 刻みに。linspace を使う例。
plt.xticks(np.linspace(-5, 5, 11))
# グリッド(格子線)
plt.grid(linestyle='dotted')
plt.xlabel('$x$', fontsize=12)
plt.ylabel(r'$1/x$', fontsize=12)
plt.title('Matplotlib で $1/x$', fontsize=14)
# x軸 y軸
plt.axhline(0, color='black', dashes=(5, 5), linewidth=0.5)
plt.axvline(0, color='black', dashes=(5, 5), linewidth=0.5);
補足説明:np.nan
に置き換える方法
ある条件を満たす配列の要素の値を np.nan
に置き換える方法の補足説明。
以下のように,6個の要素をもつ配列 y
を考える。
y = np.array([1., 2., 5., -30., -1., 3.])
np.diff()
は各要素間の差を表す階差数列を生成する。たとえば y
の差分は…
np.diff(y)
と,5個の成分をもつ配列を生成するが,これは以下の計算をしていることになる。
for i in range(1,len(y)):
print('%7.0f' % (y[i]-y[i-1]), end='')
np.diff(y)
が負の値かどうかを判定するには…
np.diff(y) < 0
y
の値のうち,np.diff(y) < 0
となる値を抽出するには,len(np.diff(y)) = len(y)-1
であることに注意して…
y[1:][np.diff(y)<0]
または,
y[:-1][np.diff(y)<0]
y
の要素のうち,np.diff(y) < 0
となる値を「欠損値」np.nan
にするには…
y = np.array([1., 2., 5., -30., -1., 3.])
# 置き換え前
print('置き換え前')
for i in y:
print('%5.0f' % i, end='')
print('')
y[1:][np.diff(y) < 0] = np.nan
# 置き換え後
print('置き換え後')
for i in y:
print('%5.0f' % i, end='')
print('')
同様にして,y
の要素のうち,絶対値が $5$ 以上,つまり abs(y) >= 5
となる値を「欠損値」np.nan
に置き換えるには…
y = np.array([1., 2., 5., -30., -1., 3.])
# 置き換え前
print('置き換え前')
for i in y:
print('%5.0f' % i, end='')
print('')
y[abs(y) >= 5] = np.nan
# 置き換え後
print('置き換え後')
for i in y:
print('%5.0f' % i, end='')
print('')
SymPy Plotting Backends 編
モジュールの import
from sympy.abc import *
from sympy import *
# SymPy Plotting Backends (SPB)
from spb import *
Pi = float(pi)
# グラフを SVG で Notebook にインライン表示
%config InlineBackend.figure_formats = ['svg']
# グラフを描くためではなくデフォルト設定のため
import matplotlib.pyplot as plt
plt.rcParams['mathtext.fontset'] = 'cm'
$y = \tan x$ のグラフ
普通に $y = \tan x$ を plot()
すると,(バックエンドが Matplotlib であることから)以下のグラフのように,$y \rightarrow \infty$ から $y \rightarrow -\infty$ となる不連続なところもつないでグラフにしてしまう。
plot(tan(x),(x, -2*pi, 2*pi), {"color":"blue"},
xlim = (-2*pi, 2*pi), ylim=(-10, 10));
detect_poles=True
で対処
detect_poles=True
オプションをつけて,さらに n
の値を大きめにすると,以下のようになる。
plot(tan(x),(x, -2*pi, 2*pi), {"color":"blue"},
xlim = (-2*pi, 2*pi), ylim=(-10, 10),
detect_poles=True, n=1e05);
Matplotlib 風のオプション設定
p = plot(tan(x),(x, -2*pi, 2*pi), {"color":"blue"},
detect_poles=True, n=1e05, show = False)
fig, ax = p.fig, p.ax
# fig.tight_layout()
# 横軸縦軸の表示範囲
ax.set_xlim(-2*Pi, 2*Pi)
ax.set_ylim(-10, 10)
# グリッド(格子線)
ax.grid(linestyle='dotted')
ax.set_xlabel('$x$', fontsize=12)
ax.set_ylabel(r'$\tan x$', fontsize=12)
ax.set_title('SymPy Plotting Backends で $\\tan x$', fontsize=14)
ax.set_xticks([-2*Pi,-1.5*Pi,-Pi,-0.5*Pi, 0,
2*Pi, 1.5*Pi, Pi, 0.5*Pi],
['$-2\pi$','$-3\pi/2$','$-\pi$','$-\pi/2$','$0$',
'$ 2\pi$','$ 3\pi/2$','$ \pi$','$ \pi/2$'], fontsize=12)
# x軸 y軸
ax.axhline(0, color='black', dashes=(5, 5), linewidth=0.5)
ax.axvline(0, color='black', dashes=(5, 5), linewidth=0.5);
$y = x^{-1}$ のグラフ
$y = x^{-1}$ を普通に plot()
すると,$\displaystyle \lim_{x\rightarrow -0} \frac{1}{x} \rightarrow -\infty$ と $\displaystyle \lim_{x\rightarrow +0} \frac{1}{x} \rightarrow +\infty$ の不連続点をつないでグラフにしてしまうなぁ。
plot(x**(-1), (x, -5, 5), {'color':'red'},
xlim = (-5, 5), ylim=(-10, 10));
detect_poles=True
で対処
detect_poles=True
オプションをつけて,さらに n
の値を大きめにすると,以下のようになる。
plot(x**(-1), (x, -5, 5), {'color':'red'},
xlim = (-5, 5), ylim=(-10, 10),
detect_poles=True, n=1e04);
exclude
オプションで対処
$x=0$ は除くことにして exclude = [0]
オプションを使う例。xlabel
などのオプションは plot()
内で設定できる。
plot(x**(-1), (x, -5, 5), {'color':'red'},
xlim = (-5, 5), ylim=(-10, 10),
exclude = [0],
xlabel = '$x$', ylabel = '$1/x$',
title = 'SymPy Plotting Backends で $1/x$');