imshow 绘制非常大的整数,但“dtype 对象无法转换为浮点数”

问题描述 投票:0回答:2

我有以下代码,在网格上绘制一个函数,其中该函数恰好有一个非常大的整数值:

import matplotlib.pyplot as plt
from matplotlib.ticker import ScalarFormatter, FuncFormatter

p = 13
counts = [[0 for x in range(p)] for y in range(p)]
counts[0][0] = 1000000000
unique_counts = np.unique(counts)
plt.imshow(counts, cmap='viridis', origin='lower', extent=[0, p-1, 0, p-1])
cbar = plt.colorbar(ticks=unique_counts, format=ScalarFormatter(useOffset=False))
cbar.ax.yaxis.set_major_formatter(FuncFormatter(lambda x, _: format(int(x), ',')))  # Format tick labels with commas
plt.show()

在 GoogleColab 中运行它,它运行得非常好,并且给出了漂亮的图

但是,如果我向上

counts[0][0] = 1000000000000000000000
说,那么我会收到以下错误:

---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

<ipython-input-12-0ec4c2551685> in <cell line: 8>()
      6 counts[0][0] = 100000000000000000000
      7 unique_counts = np.unique(counts)
----> 8 plt.imshow(counts, cmap='viridis', origin='lower', extent=[0, p-1, 0, p-1])
      9 cbar = plt.colorbar(ticks=unique_counts, format=ScalarFormatter(useOffset=False))
     10 cbar.ax.yaxis.set_major_formatter(FuncFormatter(lambda x, _: format(int(x), ',')))  # Format tick labels with commas

3 frames

/usr/local/lib/python3.10/dist-packages/matplotlib/image.py in set_data(self, A)
    699         if (self._A.dtype != np.uint8 and
    700                 not np.can_cast(self._A.dtype, float, "same_kind")):
--> 701             raise TypeError("Image data of dtype {} cannot be converted to "
    702                             "float".format(self._A.dtype))
    703 

TypeError: Image data of dtype object cannot be converted to float

我非常希望能够以精确的精度绘制采用非常大的整数值的函数(因此舍入/使用浮点数不会很好)。这可能吗?

python matplotlib precision floating-accuracy imshow
2个回答
2
投票

简短回答

我目前没有找到一种方法来精确地将大整数传递给

imshow()
,因为Matplotlib的内部工作原理依赖于Numpy数组来保存图像数据。如果您可以接受近似值,请使用

counts[0][0] = float(100000000000000000000)

长答案

您看到错误的原因是您的图像数据的嵌套列表在显示之前由 Matplotlib 在内部转换为 Numpy 数组。在 Matplotlib 的当前版本中,这种情况发生在

cbook.safe_masked_invalid()
中,由
‎_ImageBase._normalize_image_array()
调用,
_ImageBase.set_data()
调用,
Axes.imshow()
调用。

这里的问题链如下:

  1. 大整数(即我认为无法用 Numpy 的

    int_
    数据类型表示的整数)默认会转换为 Numpy 的
    object
    数据类型。对于使用
    counts[0][0] = 100000000000000000000
    的数据会发生这种情况,但使用
    counts[0][0] = 1000000000
    时不会发生这种情况。您可以轻松检查相应的 Numpy 行为,如下所示:

    str(np.array([100000000000000000000]).dtype)
    # >>> 'object'
    str(np.array([1000000000]).dtype)
    # >>> 'int64'
    

    在 Matplotlib 中,正如已经提到的,这发生在

    cbook.safe_masked_invalid()
    ;更准确地说,它发生在
    x = np.array(x, subok=True, copy=copy)
    行中,其中
    x
    指的是您的嵌套列表
    counts

  2. 之后,

    _ImageBase._normalize_image_array()
    检查结果数组的数据类型是否为
    uint8
    ,或者是否可以转换为
    float
    数据类型。对于 Numpy 的
    object
    数据类型来说,这两者都不是正确的,因此会引发错误。

为了避免这一系列问题,我看到的唯一可能性是,一旦值变得太大,就将数据转换为浮点值或浮点数组,然后再将它们传递给

imshow()


0
投票

Float 在处理大整数时存在问题。以下代码对我有用,我希望这是您想要的结果。 用科学记数法表示的可读数字总是比拥有极大的数字要好一些。

import matplotlib.pyplot as plt
from matplotlib.ticker import ScalarFormatter
import numpy as np

p = 13
counts = [[0 for x in range(p)] for y in range(p)]
counts[0][0] = 100000000000000000000000

# Convert counts to a NumPy array
counts_array = np.array(counts, dtype=float)

# Create the plot
plt.imshow(counts_array, cmap='viridis', origin='lower', extent=[0, p-1, 0, p-1])
cbar = plt.colorbar()

cbar.set_ticks([np.min(counts_array), np.max(counts_array)])
cbar.ax.yaxis.set_major_formatter(ScalarFormatter(useOffset=False, useMathText=True))
cbar.update_ticks()

plt.show()
© www.soinside.com 2019 - 2024. All rights reserved.