SymPy Plotting Backends でグラフを描いて Matplotlib 流にオプション設定する

一旦 SymPy Plotting Backends で p = plot() などとしてプロットしたら,あとは ax = p.ax として ax に対して通常どおりの Matplotlib のオプション設定をしていけばよいという話。

SymPy は関数を symbolic expression のままでグラフにできるので,NumPy にたよらないという方針でやってみる。

SymPy Plotting Backends (SPB) での描画例

In [1]:
# 念のため,あらためて必要なものを import

from sympy import *
# 1文字変数の Symbol の定義が省略できる
from sympy.abc import *

# π
from sympy import pi
Pi = float(pi)

# SymPy Plotting Backends (SPB)
from spb import *

# ticks の設定用
import matplotlib.ticker as tck

# NumPy は import しない
# import numpy as np

# グラフを SVG で Notebook にインライン表示
%config InlineBackend.figure_formats = ['svg']

SymPy Plotting Backends (SPB) を import すると,外枠とグリッドが自動で描かれる。

In [2]:
plot(sin(x), (x, -pi, pi), ylabel="sin x");

xticks, yticks のカスタマイズ

$x$ 軸,$y$ 軸の目盛の刻み幅とラベルの設定例(NumPy にたよらずに)。np.linspace()np.arange() を使わずに xticks, yticks を設定するのに,Python の標準的なリスト作成機能を使う。たとえば…

In [3]:
[0.5*i for i in range(-2, 3)]
Out[3]:
[-1.0, -0.5, 0.0, 0.5, 1.0]
In [4]:
# いったん SymPy でプロットする(非表示)
p = plot(sin(x), (x, -pi, pi), ylabel="sin x", show=False)

ax = p.ax

# x 軸の目盛は 0.5π ごとに
ax.set_xticks([0.5*i*Pi for i in range(-2, 3)])
ax.set_xticklabels([('%g' % (0.5*i))+" $\pi$" for i in range(-2,3)])

# y の目盛を 0.5 ごとに
ax.set_yticks([0.5*i for i in range(-2, 3)]);

$1\, \pi$ とか $0\,\pi$ とか,今ひとつなので少し面倒だが一つずつ設定してみる。

In [5]:
p = plot(sin(x), (x, -pi, pi), ylabel="sin x", show=False)

ax = p.ax

# x 軸の目盛は 0.5π ごとに
ax.set_xticks([0.5*i*Pi for i in range(-2, 3)])
# x 軸の目盛のラベルを手動で設定
ax.set_xticklabels(["$-\pi$", "$-\pi/2$", "$0$", "$\pi/2$", "$\pi$"])

# y の目盛を 0.5 ごとに
ax.set_yticks([0.5*i for i in range(-2, 3)]);

grid の linestyle のカスタマイズ

グリッドを薄い灰色の細めの点線にして目立たなくさせる。

In [6]:
p = plot(sin(x), (x, -pi, pi), ylabel="sin x", show=False)

ax = p.ax
ax.set_xticks([0.5*i*Pi for i in range(-2, 3)])
ax.set_xticklabels(["$-\pi$", "$-\pi/2$", "$0$", "$\pi/2$", "$\pi$"])
ax.set_yticks([0.5*i for i in range(-2, 3)]);

# grid を細い点線で
ax.grid(True, which="major", color="lightgray", dashes=(3, 5), linewidth=0.5);

副目盛 minorticks の表示とカスタマイズ

主目盛は $0.5\,\pi$ ごとなので,その間に副目盛 (minorticks) もつける。

また,副目盛にもグリッドをつけると煩わしいので,グリッドは主目盛のみに。

In [7]:
p = plot(sin(x), (x, -pi, pi), ylabel="sin x", show=False)

ax = p.ax
ax.set_xticks([0.5*i*Pi for i in range(-2, 3)])
ax.set_xticklabels(["$-\pi$", "$-\pi/2$", "$0$", "$\pi/2$", "$\pi$"])
ax.set_yticks([0.5*i for i in range(-2, 3)]);
ax.grid(True, which="major", color="lightgray", dashes=(3, 5), linewidth=0.5)

# 副目盛も表示
ax.minorticks_on()
# 副目盛には grid をつけない
ax.grid(False, which="minor")

# 副目盛の刻み幅は自動でつくが,以下のようにカスタマイズ可
# x の副目盛は 0.1π ごとに
ax.set_xticks([0.1*i*Pi for i in range(-10, 11)], minor=True)
# y の副目盛は 0.1 ごとに
ax.set_yticks([0.1*i for i in range(-10, 11)], minor=True);

x 軸, y 軸の表示

$x$ 軸($y = 0$)と $y$ 軸($x = 0$)を axhline()axvline() を使って表示させる。通常のグリッドと区別するために黒色で。

In [8]:
p = plot(sin(x), (x, -pi, pi), ylabel="sin x", show=False)

ax = p.ax
ax.set_xticks([0.5*i*Pi for i in range(-2, 3)])
ax.set_xticklabels(["$-\pi$", "$-\pi/2$", "$0$", "$\pi/2$", "$\pi$"])
ax.set_yticks([0.5*i for i in range(-2, 3)]);
ax.grid(True, which="major", color="lightgray", dashes=(3, 5), linewidth=0.5)
ax.minorticks_on()
ax.grid(False, which="minor")
ax.set_xticks([0.1*i*Pi for i in range(-10, 11)], minor=True)
ax.set_yticks([0.1*i for i in range(-10, 11)], minor=True)

# x軸 y軸
ax.axhline(0, color='black', dashes=(3, 5), linewidth=0.5)
ax.axvline(0, color='black', dashes=(3, 5), linewidth=0.5);
p.save("spbax05.svg");

参考:Locater, Formatter を使った ticks のカスタマイズ

以下のように matplotlib.ticker を import し,MultipleLocator()FormatStrFormatter() を使って目盛・ラベルの設定ができる。

ただし,$x = 3.1415…$ のところに $\pi$ とラベルをつけるためには少し工夫がいる。以下では $x = 1$ のところに $\pi$ とラベルをつけている。$y = \sin \pi x$ としているので,実効的には $x = 1$ のときは $ y = \sin \pi$ の値になっているのだが…

In [9]:
import matplotlib.ticker as tck

# sin の引数に π をかけ,x の範囲を -1 から 1 に
p = plot(sin(pi*x), (x, -1, 1), ylabel="sin x", show=False)

ax = p.ax
ax.grid(True, which="major", color="lightgray", dashes=(3, 5), linewidth=0.5)
ax.axhline(0, color='black', dashes=(3, 5), linewidth=0.5)
ax.axvline(0, color='black', dashes=(3, 5), linewidth=0.5);

# x の主目盛を 0.5π ごとに
ax.xaxis.set_major_locator(tck.MultipleLocator(0.5))
ax.xaxis.set_major_formatter(tck.FormatStrFormatter('%g $\pi$'))
# y の主目盛を 0.5 ごとに
ax.yaxis.set_major_locator(tck.MultipleLocator(0.5));

# 副目盛も表示
ax.minorticks_on()
# x 軸の副目盛は 0.1 ごとに
ax.xaxis.set_minor_locator(tck.MultipleLocator(0.1))
# y 軸の副目盛は 0.1 ごとに
ax.yaxis.set_minor_locator(tck.MultipleLocator(0.1))
# 副目盛には grid をつけない
ax.grid(False, which="minor");