matplotlib 重载绘图函数

用户171780

我不知道我想做的到底是怎么称呼的。我也是 Python 的新用户。基本上我创建了一个非常简单的类,用于表示形式的测量数量

在此处输入图片说明

并自动进行错误传播。这是定义:

from math import sqrt
from math import log10
from math import fabs
from math import floor
from math import ceil
from math import pi

class magnitude:
    def __init__(self, val, err):
        self.val = val
        self.err = err

    def __str__(self):
        "Prints the magnitude in the format v.vvvv(v+-e) being 'v' the relevant digits of the magnitude value and '+-e' the most significant digit of the error."
        if self.err == 0 or self.val == 0:
            return str(self.val)
        if self.err >= fabs(self.val):
            return '{:.0e} +- {:.0e}'.format(self.val, self.err) + ' (Infinite uncertainty!)'
        else:
            temp = '{:.' + str(ceil(log10(fabs(self.val*(1+pi*1e-3))) - ceil(log10(self.err*(1+pi*1e-3))) )) + 'e}' # Calculates number of digits for the representative part. The adition of 'pi*1e-3' is to add some noise and avoid error values of '1', '10', '100', ..., because they are not well printed.
            temp = temp.format(self.val)
            temp = temp[:-4] # Remove last 4 chars.
            return temp + '(+-' + str(int(self.err*10**(ceil(-log10(self.err))))) + ')' + '{:.0e}'.format(fabs(self.val))[1:] + ' ({:d} ppm)'.format(int(self.err/fabs(self.val)*1e6))
    # --------------------
    def __add__(self, other):
        if type(other) == int or type(other) == float:
            other = magnitude(other, 0)
        return magnitude(self.val + other.val, sqrt(self.err**2 + other.err**2))
    def __radd__(self, other):
        if type(other) == int or type(other) == float:
            other = magnitude(other, 0)
        return magnitude(self.val + other.val, sqrt(self.err**2 + other.err**2))
    # --------------------
    def __sub__(self, other):
        if type(other) == int or type(other) == float:
            other = magnitude(other, 0)
        return magnitude(self.val - other.val, sqrt(self.err**2 + other.err**2))
    def __rsub__(self, other):
        if type(other) == int or type(other) == float:
            other = magnitude(other, 0)
        return magnitude(-self.val + other.val, sqrt(self.err**2 + other.err**2))
    # --------------------
    def __mul__(self, other):
        if type(other) == int or type(other) == float:
            other = magnitude(other, 0)
        return magnitude(self.val*other.val, sqrt(self.val**2*other.err**2 + self   .err**2*other.val**2))
    def __rmul__(self, other):
        if type(other) == int or type(other) == float:
            other = magnitude(other, 0)
        return magnitude(self.val*other.val, sqrt(self.val**2*other.err**2 + self   .err**2*other.val**2))
    # --------------------
    def __truediv__(self, other):
        if type(other) == int or type(other) == float:
            other = magnitude(other, 0)
        return magnitude(self.val/other.val, sqrt(self.err**2/other.val**2 + self.val**2/other.val**2*other.err**2))
    def __rtruediv__(self, other):
        if type(other) == int or type(other) == float:
            other = magnitude(other, 0)
        return magnitude(other.val/self.val, sqrt(other.err**2/self.val**2 + other.val**2/self.val**2*self.err**2))

现在我想要的是重载 matplotlib 绘图函数,以告诉它应该如何绘制它,即幅度.val 值的粗线和围绕它的两条细线,距离为幅度.err。

我该怎么做?

用户171780

感谢 Yngve Moe 的回答,我已经设法编写了这个函数

def plot_yerr_filled(x=None, y=None, axis=plt, color=(0,0,0), alpha=0.25, *args, **kwargs):
    """Creates a 'filled error bar' plot. All keyword arguments in matplotlib functions are accepted.

    Parameters
    ----------
    x : Array like (list of float, int, etc. or numpy.array or list of magnitude) of exact 'x' values (i.e. with no error, if 'x' is a list of 'magnitude' type objects, errors are discarded).
    y : Array like (list) of 'magnitude' type elements containing the 'y' values and the 'yerr' associated error.
    axis: matplotlib.axes (optional) in which to plot the data.
    color: tuple (r,g,b) defining the color.
    alpha: float between 0 and 1 indicating the transparency of the filled error bar.
    """

    for i in range(0, len(x)): # Validation of x
        if isinstance(x[i], magnitude):
            x[i] = x[i].val
    for i in range(len(y)): # Validation of y
        if not isinstance(y[i], magnitude):
            raise ValueError('y[' + str(i) + '] is not of type "magnitude"')

    y_val = [y[i].val for i in range(len(y))]
    y_err = [y[i].err for i in range(len(y))]
    axis.fill_between(np.array(x), np.array(y_val)-np.array(y_err), np.array(y_val) + np.array(y_err), alpha=alpha, edgecolor=color, facecolor=color )
    lines = axis.plot(np.array(x), np.array(y_val), color=color, *args, **kwargs)
    return lines

这正是我想要的。这里我举个例子

import pymagpy as mg
import matplotlib.pyplot as plt
plt.rc('axes', axisbelow=True) # This is for plotting data in front of the grid.
plt.rcParams.update({'font.size': 8}) # Changes the default font size for the plots.
import numpy as np

x = mg.magnitude(1, 0.1)
y = mg.magnitude(-6798, 6)
z = mg.magnitude(1e-30, .00002872982778297289e-30)

print(x)
print(y)
print(z)
print(x+y/z*2-z/x*y) # Automatically calculates the error propagation.

x_values = []
y_values = []
z_values = []
for k in range(10):
    x_values.append(mg.magnitude(k, k**2))
    y_values.append(mg.magnitude(k**2, k))
    z_values.append(mg.magnitude(np.sqrt(300*k)+1, k/(k-2.2)+5))

FIG_WIDTH = 130e-3 # Figure width in meters (size of the chart+axis_ticks, not counting legend, title, etc.).
FIG_RATIO = [1, 0.8] # XY ratio aspect of figures.
f, (ax1, ax2) = plt.subplots(2, sharex=True, figsize=(FIG_WIDTH*FIG_RATIO[0]/25.4e-3, FIG_WIDTH*FIG_RATIO[1]/25.4e-3)) # Create the figure for plotting.
f.subplots_adjust(hspace=0.1) # Fine-tune figure; make subplots close to each other and hide x ticks for all but bottom plot.
mg.plot_yerr_filled(x_values, y_values, color=(1,0,0), alpha=.1, axis=ax1, label='Y', marker='.')
mg.plot_yerr_filled(x_values, z_values, color=(0,0,1), axis=ax1, label='Z', marker='o', linestyle='')
ax1.set_ylabel('y axis')
ax1.grid(b=True, which='major', color='#aaaaaa', linestyle='-', linewidth=0.5) # Configure the grid in a more fachera way.
ax1.grid(b=True, which='minor', color='#dddddd', linestyle='-', linewidth=0.25) # Configure the grid in a more fachera way.
ax1.minorticks_on() # Enables minor ticks without text, only the ticks.
ax1.legend(loc='best', fancybox=True, framealpha=0.7, ncol=1, fontsize=8)
mg.plot_yerr_filled(x_values, [(a*b)/(a+b) for a,b in zip(y_values, z_values)], axis=ax2, label='(Y*Z)/(Y+Z)', marker='.', linestyle='--')
ax2.set_xlabel('x axis')
ax2.set_ylabel('y axis')
ax2.grid(b=True, which='major', color='#aaaaaa', linestyle='-', linewidth=0.5) # Configure the grid in a more fachera way.
ax2.grid(b=True, which='minor', color='#dddddd', linestyle='-', linewidth=0.25) # Configure the grid in a more fachera way.
ax2.minorticks_on() # Enables minor ticks without text, only the ticks.
ax2.legend(loc='best', fancybox=True, framealpha=0.7, ncol=1, fontsize=8)
plt.savefig('example.pdf', bbox_inches='tight')
plt.show()

产生这个情节:

在此处输入图片说明

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

matplotlib中的条件函数绘图

来自分类Dev

matplotlib绘图函数忽略一行

来自分类Dev

matplotlib通过函数设置绘图属性

来自分类Dev

如何强制matplotlib在函数结束之前进行绘图

来自分类Dev

如何强制matplotlib在函数结束之前进行绘图

来自分类Dev

防止 matplotlib 函数 psd() 绘图 - 或更快的替代方法

来自分类Dev

使用 matplotlib 修改 scipy stats.probplot 绘图函数

来自分类Dev

绘图决策边界matplotlib

来自分类Dev

matplotlib:获取绘图的轴比

来自分类Dev

一维绘图matplotlib

来自分类Dev

使用matplotlib循环绘图

来自分类Dev

在matplotlib中内联绘图

来自分类Dev

matplotlib绘图问题

来自分类Dev

Matplotlib特定轴绘图

来自分类Dev

使用matplotlib循环绘图

来自分类Dev

循环中的 matplotlib 绘图

来自分类Dev

Matplotlib 绘图到 QtGraphicsView

来自分类Dev

matplotlib 的绘图风格

来自分类Dev

缓慢的 matplotlib 绘图

来自分类Dev

Python Matplotlib在绘图时崩溃

来自分类Dev

Pandas或Matplotlib中的绘图图

来自分类Dev

matplotlib文本仅在绘图区域

来自分类Dev

Python的Matplotlib绘图顺序错误

来自分类Dev

matplotlib直方图上的意外绘图

来自分类Dev

无法使用Matplotlib进行绘图

来自分类Dev

Matplotlib:EPS绘图质量下降

来自分类Dev

Python Matplotlib在绘图时崩溃

来自分类Dev

Matplotlib:全局“关闭”进行绘图?

来自分类Dev

matplotlib 绘图没有出现