7 декабря 2011 г.

Matplotlib и "FloatingPointError: underflow encountered in multiply"

Случилось мне столкнуться с мистической ошибкой при использовании matplotlib - библиотеки для рисования графиков и визуализации различных математических результатов, имеющей крайне Matlab Like API =)

Ошибка поставляется вместе с тучным traceback-ом, указывающим в итоге на
File "/usr/lib/python2.6/site-packages/numpy/ma/core.py", line 772, in __call__ 
return umath.absolute(a) * self.tolerance >= umath.absolute(b)
Тобишь ошибочка гдето внутрях ядра numpy, который библиотека юзает для своих целей.

Мистика заключается в том, что получить эту ошибку мне удалось только в связке версий 1.0.1 и 1.6.1 для matplotlib и numpy соответственно и только на python-е версии 2.6.5.
В моём случае всё это дело сверху покрывается ещё одной чудесной библиотекой для работы с графами - NetworkX.
def graph_draw(G, name):
    """Draw graph"""
    import matplotlib.pyplot as plt;
    import networkx as nx;
    plt.figure();
    nx.draw(G,
            node_color=[random.random() for i in G.nodes()],
            node_size=[x[1]['size'] for x in G.nodes(data=True)]);
    plt.savefig('graph');
Данный код в большинстве случаев рисует заданный граф с разноцветными вершинами и сохраняет оный в файл.
Параметр node_color, исходя из доки, может быть представлен в виде списка чисел с плавающей точкой в диапазоне [0,1]. Именно он и вызывает нашу ошибку.
В доке networkX о нём сказано следующее: 
Can be a single color format string, or a sequence of colors with the same length as nodelist. If numeric values are specified they will be mapped to colors using the cmap and vmin,vmax parameters. See matplotlib.scatter for more details.
Тобишь всё вроде должно быть в порядке.
Для успокоения идём в доку matplotlib (нас очевидно интересует параметр цвета)
c can be a single color format string, or a sequence of color specifications of length N, or a sequence of N numbers to be mapped to colors using the cmap and norm specified via kwargs (see below). Note that c should not be a single numeric RGB or RGBA sequence because that is indistinguishable from an array of values to be colormapped. c can be a 2-D array in which the rows are RGB or RGBA, however.
И тут всё нормально и в пределах возможностей. В общем мистика.

Ну а дальше копать я пока не собрался =)

Как быстрое решение, в моём случае помогла смена формата цветовой гаммы на другой, а именно список кортежей.
def graph_draw(G, name):
    """Draw graph"""
    import matplotlib.pyplot as plt;
    import networkx as nx;
    plt.figure();
    nx.draw(G,
            node_color=[(random.random(),random.random(),random.random()) for i in G.nodes()],
            node_size=[x[1]['size'] for x in G.nodes(data=True)]);
    plt.savefig('graph');

Комментариев нет: