I have the following code, plotting a function on a grid, where the function happens to have a very large integer value:
import matplotlib.pyplot as plt
from matplotlib.ticker import ScalarFormatter, FuncFormatter
import numpy as np # thanks to user @simon pointing out I had forgotten this
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()
Running this in GoogleColab, it runs perfectly fine and gives the nice plot

However, if I bump up counts[0][0] = 1000000000000000000000 say, then I get the following error:
---------------------------------------------------------------------------
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
I would like very much to be able to plot functions that take very large integer values with exact precision (so rounding/using floats would not be good). Is this possible?
EDIT: someone was understandably confused by this seemingly useless level of precision in a plot; I clarified that what's actually important for me is actually being able to read the exact value off the colorbar labels (for number theory applications, I need an exact count for the number of points on some varieties mod p). So I'm ok with the plot being slightly off, but I do really want the colorbar labels to be exact.
New answer
(For my original answer, see the section below.)
Based on the question's update, from which it became clear that the essential information that should be retained is the precise integer values on the colorbar tick labels, here is my updated answer. Its crucial idea is:
Here is the corresponding code:
In older versions of Matplotlib, you might need to adjust the last three lines as follows:
And here is the resulting plot:
Original answer
Short answer
I currently do not see a way to exactly pass huge integers to
imshow(), due to the inner workings of Matplotlib relying on Numpy arrays for holding the image data. If you can live with approximate values, useLong answer
The reason for the error that you see is that your nested list of image data is internally converted to a Numpy array by Matplotlib before displaying it. In Matplotlib's current version, this happens in
cbook.safe_masked_invalid(), which is called by_ImageBase._normalize_image_array(), which is called by_ImageBase.set_data(), which is called byAxes.imshow().The chain of problems here is the following:
Huge integers (i.e. integers that cannot be represented by Numpy's
int_data type, I assume) are converted to Numpy'sobjectdata type by default. This happens for your data withcounts[0][0] = 100000000000000000000, but not withcounts[0][0] = 1000000000. You can easily check the corresponding Numpy behavior as follows:In Matplotlib, as already mentioned, this happens in
cbook.safe_masked_invalid(); more precisely, it happens in the linex = np.array(x, subok=True, copy=copy), wherexrefers to your nested listcounts.After that,
_ImageBase._normalize_image_array()checks whether the resulting array's data type is eitheruint8or whether it can be cast to thefloatdata type. Neither is true for Numpy'sobjectdata type, so the error is raised.To avoid this chain of problems, the only possibility that I see is converting your data to float values or to a float array yourself, once the values become too big, before passing them to
imshow().