简体   繁体   中英

Displaying first decimal digit in scientific notation in Matplotlib

I am currently generating different figures with a scientific notation for the y-axis leading to ticks like 2 or 6 on some plots, but 2.5 or 8.9 on some others. I would like to always have ticks with one decimal on the y-axis, even if it adds a zero. Here is an example

import matplotlib.pyplot as plt
import numpy as np

plt.plot(np.arange(1, 10), np.arange(1, 10)**5)
ax = plt.gca()
plt.ticklabel_format(axis='y', style='sci')
ax.yaxis.major.formatter.set_powerlimits((0,0))
plt.show()

图生成

What could I add to force to plot ticks 1.0, 2.0, etc. on the y-axis ?

The ScalarFormatter does not currently support custom formats for the ticks, such as setting numbers of decimals. However you can extend the class, so to force it to use a format that you specify. Here is an example:

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

class ScalarFormatterForceFormat(ScalarFormatter):
    def _set_format(self):  # Override function that finds format to use.
        self.format = "%1.1f"  # Give format here

plt.plot(np.arange(1, 10), np.arange(1, 10)**5)
ax = plt.gca()
yfmt = ScalarFormatterForceFormat()
yfmt.set_powerlimits((0,0))
gca().yaxis.set_major_formatter(yfmt)
plt.show()

Here is how it will look.

在此处输入图像描述

Since I did not manage to make the other answers work, probably because I am using subplots and axis, I create a function that simply goes around the problem of using the command plt.ticklabel_format(axis='y', style='sci') .

The function takes the thicklabels of the y axis and converts the values to scientific notation. It calculates the value and the sign of the exponent and then modifies the plot accordingly, using ax.annotate to place the exponent a the top left corner. The function takes as the arguments the ax that needs to be modified, so the figure needs to be declared with an axis ( ax ), and the number decimal digits to be displayed. The only unknown is the textsize of the annotate , which may be automatized as well. I added a couple of different plots to show the case with negative numbers or decimals.

import matplotlib.pyplot as plt
import numpy as np


def scientific_notation_y(ax, decimals=1):
    v = np.asarray(ax.get_yticks().tolist())
    v_abs = np.abs(v)
    v_max = np.max(v_abs)
    exp = 0

    if v_max >= 10:
        sign = '+'
        while v_max >= 10:
            exp = exp + 1
            v_max = v_max / 10
        v = v / 10**exp
    elif v_max <= 1:
        sign = '-'
        while v_max <= 1:
            exp = exp + 1
            v_max = v_max * 10
        v = v * 10**exp
    v = np.around(v, decimals)
    ax.annotate(r'1e' + sign + str(exp), xycoords='axes fraction',
                xy=(0, 0), xytext=(0, 1.01), size=14)
    ax.set_yticklabels(v)
    return

fig, ax = plt.subplots()
ax.plot(np.arange(0, 10), np.arange(0, 10)**5)
scientific_notation_y(ax, 1)
plt.show()

fig, ax = plt.subplots()
ax.plot(np.arange(0, 10), -np.arange(0, 10)**5)
scientific_notation_y(ax, 1)
plt.show()

fig, ax = plt.subplots()
ax.plot(np.arange(0, 10), -np.arange(0, 10)/100)
scientific_notation_y(ax, 1)
plt.show()

在此处输入图像描述

You can get the ticks and format it like you want.

plt.plot(np.arange(1, 10), np.arange(1, 10)**5)
ax = plt.gca()
plt.ticklabel_format(axis='y', style='sci')
ax.yaxis.major.formatter.set_powerlimits((0,0))

xx, locs = plt.xticks()
ll = ['%.1f' % a for a in xx]
plt.xticks(xx, ll)
plt.show()

格式化刻度

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM