Possible to round numbers to the hundreds, thousands, etc. using Python 3's number formatting

Viewed 2219

Specific Issue

I am trying to print out the numbers on top of the cells in a seaborn heatmap. For instance, something like:

ax = sns.heatmap(flights, annot=True, fmt=",")

(This is taken directly from seaborn's documentation, adjusted to be Python 3-friendly. So if you import seaborn, you can run the same example out of the box.)


This generates a fairly respectable figure like the one below:

heatmap, not quite ideal

However, I would like to see the numbers rounded to the nearest hundreds. In other words, I want to see numbers like 171 written as 200, and 315 written as 300, etc.


Ideas

Under the hood, seaborn is really just matplotlib. I can use matplotlib's text methods.

matplotlib's text relies upon Python 3's text formatting, which has convenient ways to round to the right of the decimal, by doing things like .2 to round to the hundred***ths***, but I cannot find anything to round in the other direction.


I could simply round the numbers before I push them to the plot, but that will actually alter the plot data itself, which I'd rather avoid. Therefore, I would like to leaving the underlying numbers that I pass to the plot unaltered, while still being able to print things nicely.


As far as I know, the only way to do this is to find a clever way to format things. Is there a way?

Thanks!

Update

I dug further into seaborn's code, trying to understand why La Rooy's clever solution below did not work for me.

The relevant line within the seaborn code is:

val = ("{:" + self.fmt + "}").format(val)

However, for this to work, I would need to be able to alter my pandas dataframe column, which means that I'd need to be able to adjust the column of nd.array elements.

It seems that there is not yet any underlying .__format__ method for a numpy array, but there is an effort to create one.

So, I'm for the moment going to chase this issue no further, and hope that once things sort themselves out, I'll be able to take La Rooy's solution and things should "work".

Once that happens, the solution would be:

>>> class rndarray(np.ndarray):
...     def __format__(self, spec):
...         return np.ndarray.__format__(int(round(self, -2)), spec)
... 
>>> df['<col_of_interest>'] = map(rndarray, df['<col_of_interest.'])

or, if that didn't work, then:

>>> df['<col_of_interest>'].values = map(rndarray, df['<col_of_interest.'].values)
2 Answers
Related