如何以pi的倍数设置轴刻度(Python)(matplotlib)

7ajki6be  于 2023-01-31  发布在  Python
关注(0)|答案(7)|浏览(148)

我想用Python做一个绘图,让x范围以π的倍数显示刻度。
有没有一种好方法可以做到这一点,而不是手动?
我在考虑使用matplotlib,但其他选项也可以。
编辑3:EL_DON的解决方案对我来说是这样的:

import matplotlib.ticker as tck
import matplotlib.pyplot as plt
import numpy as np

f,ax=plt.subplots(figsize=(20,10))
x=np.linspace(-10*np.pi, 10*np.pi,1000)
y=np.sin(x)

ax.plot(x/np.pi,y)

ax.xaxis.set_major_formatter(tck.FormatStrFormatter('%g $\pi$'))
ax.xaxis.set_major_locator(tck.MultipleLocator(base=1.0))

plt.style.use("ggplot")

plt.show()

给出:

编辑2(已在编辑3中解决!):EL_DON的答案似乎不适合我:

import matplotlib.ticker as tck
import matplotlib.pyplot as plt
import numpy as np

f,ax=plt.subplots(figsize=(20,10))
x=np.linspace(-10*np.pi, 10*np.pi)
y=np.sin(x)

ax.plot(x/np.pi,y)

ax.xaxis.set_major_formatter(tck.FormatStrFormatter('%g $\pi$'))
ax.xaxis.set_major_locator(tck.MultipleLocator(base=1.0))

plt.style.use("ggplot")

plt.show()

给了我

这看起来真的不对

0kjbasz6

0kjbasz61#

这是受Python Data Science Handbook的启发,虽然Sage尝试做without explicit parameters
编辑:我已经将其概括为允许您提供分母、单位值和单位的LaTeX标签作为可选参数。如果您觉得有帮助,可以包含一个类定义。

import numpy as np
import matplotlib.pyplot as plt

def multiple_formatter(denominator=2, number=np.pi, latex='\pi'):
    def gcd(a, b):
        while b:
            a, b = b, a%b
        return a
    def _multiple_formatter(x, pos):
        den = denominator
        num = np.int(np.rint(den*x/number))
        com = gcd(num,den)
        (num,den) = (int(num/com),int(den/com))
        if den==1:
            if num==0:
                return r'$0$'
            if num==1:
                return r'$%s$'%latex
            elif num==-1:
                return r'$-%s$'%latex
            else:
                return r'$%s%s$'%(num,latex)
        else:
            if num==1:
                return r'$\frac{%s}{%s}$'%(latex,den)
            elif num==-1:
                return r'$\frac{-%s}{%s}$'%(latex,den)
            else:
                return r'$\frac{%s%s}{%s}$'%(num,latex,den)
    return _multiple_formatter
​
class Multiple:
    def __init__(self, denominator=2, number=np.pi, latex='\pi'):
        self.denominator = denominator
        self.number = number
        self.latex = latex
​
    def locator(self):
        return plt.MultipleLocator(self.number / self.denominator)
​
    def formatter(self):
        return plt.FuncFormatter(multiple_formatter(self.denominator, self.number, self.latex))

这可以非常简单地使用,没有任何参数:

x = np.linspace(-np.pi, 3*np.pi,500)
plt.plot(x, np.cos(x))
plt.title(r'Multiples of $\pi$')
ax = plt.gca()
ax.grid(True)
ax.set_aspect(1.0)
ax.axhline(0, color='black', lw=2)
ax.axvline(0, color='black', lw=2)
ax.xaxis.set_major_locator(plt.MultipleLocator(np.pi / 2))
ax.xaxis.set_minor_locator(plt.MultipleLocator(np.pi / 12))
ax.xaxis.set_major_formatter(plt.FuncFormatter(multiple_formatter()))
plt.show()

也可以用更复杂的方式使用:

tau = np.pi*2
den = 60
major = Multiple(den, tau, r'\tau')
minor = Multiple(den*4, tau, r'\tau')
x = np.linspace(-tau/60, tau*8/60,500)
plt.plot(x, np.exp(-x)*np.cos(60*x))
plt.title(r'Multiples of $\tau$')
ax = plt.gca()
ax.grid(True)
ax.axhline(0, color='black', lw=2)
ax.axvline(0, color='black', lw=2)
ax.xaxis.set_major_locator(major.locator())
ax.xaxis.set_minor_locator(minor.locator())
ax.xaxis.set_major_formatter(major.formatter())
plt.show()

bxfogqkk

bxfogqkk2#

f,ax=plt.subplots(1)
x=linspace(0,3*pi,1001)
y=sin(x)
ax.plot(x/pi,y)
ax.xaxis.set_major_formatter(FormatStrFormatter('%g $\pi$'))
ax.xaxis.set_major_locator(matplotlib.ticker.MultipleLocator(base=1.0))

我使用了以下答案中的信息:

xxls0lw8

xxls0lw83#

如果要避免在plot命令中将x除以pi,可以使用FuncFormatter而不是FormatStrFormatter对this answer进行微调:

import numpy as np
from matplotlib import pyplot as plt
from matplotlib.ticker import FuncFormatter, MultipleLocator

fig,ax = plt.subplots()

x = np.linspace(-5*np.pi,5*np.pi,100)
y = np.sin(x)/x
ax.plot(x,y)
#ax.xaxis.set_major_formatter(FormatStrFormatter('%g $\pi$'))
ax.xaxis.set_major_formatter(FuncFormatter(
   lambda val,pos: '{:.0g}$\pi$'.format(val/np.pi) if val !=0 else '0'
))
ax.xaxis.set_major_locator(MultipleLocator(base=np.pi))

plt.show()

给出了以下图像:

qgzx9mmu

qgzx9mmu4#

π分数的解:

import numpy as np
import matplotlib.pyplot as plt

from matplotlib import rc
rc('text', usetex=True) # Use LaTeX font

import seaborn as sns
sns.set(color_codes=True)

1.绘制函数:

fig, ax = plt.subplots(1)
x = np.linspace(0, 2*np.pi, 1001)
y = np.cos(x)
ax.plot(x, y)
plt.xlim(0, 2*np.pi)

1.修改栅格的范围,使其与pi值相对应:

ax.set_xticks(np.arange(0, 2*np.pi+0.01, np.pi/4))

1.更改轴标签:

labels = ['$0$', r'$\pi/4$', r'$\pi/2$', r'$3\pi/4$', r'$\pi$',
          r'$5\pi/4$', r'$3\pi/2$', r'$7\pi/4$', r'$2\pi$']
ax.set_xticklabels(labels)

pnwntuvh

pnwntuvh5#

import numpy as np
import matplotlib.pyplot as plt
x=np.linspace(0,3*np.pi,1001)
plt.ylim(-3,3)
plt.xlim(0, 4*np.pi)
plt.plot(x, np.sin(x))
tick_pos= [0, np.pi , 2*np.pi]
labels = ['0', '$\pi$', '$2\pi$']
plt.xticks(tick_pos, labels)

x7yiwoj4

x7yiwoj46#

我创建了一个PyPi Package,它创建了类似ScottCentoni的答案的格式化程序和定位器示例。

"""Show a simple example of using MultiplePi."""

import matplotlib.pyplot as plt
import numpy as np

from matplot_fmt_pi import MultiplePi

fig = plt.figure(figsize=(4*np.pi, 2.4))
axes = fig.add_subplot(111)
x = np.linspace(-2*np.pi, 2*np.pi, 512)
axes.plot(x, np.sin(x))

axes.grid(True)
axes.axhline(0, color='black', lw=2)
axes.axvline(0, color='black', lw=2)
axes.set_title("MultiplePi formatting")

pi_manager = MultiplePi(2)
axes.xaxis.set_major_locator(pi_manager.locator())
axes.xaxis.set_major_formatter(pi_manager.formatter())

plt.tight_layout()
plt.savefig("./pi_graph.png", dpi=120)
ilmyapht

ilmyapht7#

下面是一个将浮点数转换为π分数的版本,只需使用您最喜欢的格式化程序,然后使用函数convert_to_pi_fractions(ax, axis='x')将它生成的浮点数值转换为π分数,函数convert_to_pi_fractions(ax, axis='x')指定必须转换的脊柱(或both),您将得到:

由此得出:

from fractions import Fraction
import numpy as np
from numpy import pi
import matplotlib.pyplot as plt
import matplotlib.ticker as tck

def convert_to_pi_fractions(ax, axis='x'):
    assert axis in ('x', 'y', 'both')
    if axis in ('x', 'both'):
        vals, labels = process_ticks(ax.get_xticks())
        if len(vals) > 0: ax.set_xticks(vals, labels)
    if axis in ('y', 'both'):
        vals, labels = process_ticks(ax.get_yticks())
        if len(vals) > 0: ax.set_yticks(vals, labels)

def process_ticks(ticks):
    vals = []
    labels = []
    for tick in ticks:
        frac = Fraction(tick/pi)
        if frac.numerator < 10 and frac.numerator < 10:
            if frac.numerator == 0: label = '0'
            elif frac.denominator == 1:
                if frac.numerator == 1: label = '$\pi$'
                elif frac.numerator == -1: label = '-$\pi$'
                else: label = f'{frac.numerator} $\pi$'
            elif frac.numerator == -1: label = f'-$\pi$/{frac.denominator}'
            elif frac.numerator == 1: label = f'$\pi$/{frac.denominator}'
            else: label = f'{frac.numerator}$\pi$/{frac.denominator}'
            vals.append(tick)
            labels.append(label)
    return vals, labels

# Generate data
w_fr = np.linspace(-0.5*pi, 3.1*pi, 60)
H_func = lambda h, w: np.sum(h * np.exp(-1j * w[:, None] * np.arange(len(h))), axis=1)
r_fr = H_func([1, -1], w_fr)

# Prepare figure
fig, ax = plt.subplots(figsize=(10, 4), layout='constrained')
ax.grid()
ax.set_title('Frequency response')
ax.set_xlabel('normalized radian frequency')
ax.xaxis.set_major_locator(tck.MultipleLocator(base=pi/2))
g_c, p_c = 'C0', 'C1'

# Plot gain
ax.set_ylabel('amplitude', c=g_c)
ax.plot(w_fr, abs(r_fr), label='gain', c=g_c)
ax.tick_params(axis='y', labelcolor=g_c)

# Plot phase shift
ax1 = ax.twinx()
ax1.set_ylabel('phase shift', c=p_c)
ax1.yaxis.set_major_locator(tck.MultipleLocator(base=pi/4))

ax1.plot(w_fr, np.unwrap(np.angle(r_fr), period=2*pi), label='phase shift', c=p_c)
ax1.tick_params(axis='y', labelcolor=p_c)

# Convert floats to pi fractions
convert_to_pi_fractions(ax)
convert_to_pi_fractions(ax1, axis='y')

相关问题