matplotlib和Log10Transform中的可选数字

时间:2012-11-28 02:47:02

标签: matplotlib scale pickle

你可能已经知道,在matplotlib 1.2.0中有一个新的实验性功能,这些数字是可选的(它们可以用pickle模块保存)。

但是,当使用logscale时,它不起作用,例如

import matplotlib.pyplot as plt
import numpy as np
import pickle
ax = plt.subplot(111)
x = np.linspace(0, 10)
y = np.exp(x)
plt.plot(x, y)
ax.set_yscale('log')
pickle.dump(ax, file('myplot.pickle', 'w'))

结果:

PicklingError: Can't pickle <class 'matplotlib.scale.Log10Transform'>: attribute lookup matplotlib.scale.Log10Transform failed

有人知道任何解决方案/解决方法吗?

1 个答案:

答案 0 :(得分:4)

我已经在matplotlib的github issue tracker上打开了这个错误报告。它是一个相当容易的修复,可以在matplotlib存储库端实现(只是不要将Log10Transform类嵌套在LogScale类中),但这并没有真正帮助你能够使用它mpl 1.2.0 ......

有一个解决方案让你在1.2.0中为你工作,但我警告你 - 它不漂亮!

根据我对pickling question的回答,可以挑选嵌套类(如Log10Transform所示)。我们需要做的就是告诉Log10Transform如何“reduce”本身:

import matplotlib.scale

class _NestedClassGetter(object):
    """
    When called with the containing class as the first argument, 
    the name of the nested class as the second argument,
    and the state of the object as the third argument,
    returns an instance of the nested class.

    """
    def __call__(self, containing_class, class_name, state):
        nested_class = getattr(containing_class, class_name)
        # return an instance of a nested_class. Some more intelligence could be
        # applied for class construction if necessary.
        c = nested_class.__new__(nested_class)
        c.__setstate__(state)
        return c

def _reduce(self):
    # return a class which can return this class when called with the 
    # appropriate tuple of arguments
    cls_name = matplotlib.scale.LogScale.Log10Transform.__name__
    call_args = (matplotlib.scale.LogScale, cls_name, self.__getstate__())
    return (_NestedClassGetter(), call_args)

matplotlib.scale.LogScale.Log10Transform.__reduce__ = _reduce 

您可能还决定对其他基于日志的转换/类执行此操作,但是对于您的示例,您现在可以选择(并成功地取消)示例图:

import matplotlib.pyplot as plt
import numpy as np
import pickle


ax = plt.subplot(111)
x = np.linspace(0, 10)
y = np.exp(x)
plt.plot(x, y)
ax.set_yscale('log')

pickle.dump(ax, file('myplot.pickle', 'w'))
plt.savefig('pickle_log.pre.png')
plt.close()

pickle.load(file('myplot.pickle', 'r'))
plt.savefig('pickle_log.post.png')

我将继续为mpl 1.3.x修复此问题,以便将来不需要这个讨厌的解决方法:-)。

HTH,