Подтвердить что ты не робот

Форматирование метки метки метки метки Matplotlib

С matplotlib, когда масштаб шкалы задан для оси, метод по умолчанию, обозначающий эту ось, имеет число, равное 10, например, например. 10 ^ 6. Есть ли простой способ изменить все эти ярлыки как их полное числовое представление? например. 1, 10, 100 и т.д.

Обратите внимание, что я не знаю, какой диапазон полномочий будет и хочет поддерживать произвольный диапазон (включая негативы).

4b9b3361

Ответ 1

Конечно, просто измените форматирование.

Например, если у нас есть этот сюжет:

import matplotlib.pyplot as plt

fig, ax = plt.subplots()
ax.axis([1, 10000, 1, 100000])
ax.loglog()

plt.show()

enter image description here

Вы можете установить метки галочек вручную, но тогда места галочек и метки будут фиксироваться при масштабировании/панорамировании/и т.д. Поэтому лучше всего изменить форматер. По умолчанию в логарифмической шкале используется LogFormatter, который будет форматировать значения в научной нотации. Чтобы изменить форматирование по умолчанию для линейных осей (ScalarFormatter), используйте, например,

from matplotlib.ticker import ScalarFormatter
for axis in [ax.xaxis, ax.yaxis]:
    axis.set_major_formatter(ScalarFormatter())

enter image description here

Ответ 2

Я обнаружил, что использование ScalarFormatter прекрасно, если все значения тиков больше или равны 1. Однако, если у вас есть тик с номером <1, ScalarFormatter печатает метку тика как 0.

enter image description here

Мы можем использовать FuncFormatter из модуля matplotlib ticker, чтобы решить эту проблему. Самый простой способ сделать это - использовать функцию lambda и спецификатор формата g (спасибо @lenz в комментариях).

import matplotlib.ticker as ticker

ax.yaxis.set_major_formatter(ticker.FuncFormatter(lambda y, _: '{:g}'.format(y)))

Обратите внимание, что в своем исходном ответе я не использовал формат g, вместо этого я придумал эту функцию lambda с FuncFormatter, чтобы установить числа >= 1 в их целочисленные значения, а числа <1 в их десятичное значение с минимальным количеством требуемых десятичных знаков (т.е. 0.1, 0.01, 0.001 и т.д.). Предполагается, что вы устанавливаете галочки только на значения base10.

import matplotlib.ticker as ticker
import numpy as np

ax.yaxis.set_major_formatter(ticker.FuncFormatter(lambda y,pos: ('{{:.{:1d}f}}'.format(int(np.maximum(-np.log10(y),0)))).format(y)))

enter image description here

Для ясности, здесь эта лямбда-функция написана более многословно, но также более понятно:

def myLogFormat(y,pos):
    # Find the number of decimal places required
    decimalplaces = int(np.maximum(-np.log10(y),0))     # =0 for numbers >=1
    # Insert that number into a format string
    formatstring = '{{:.{:1d}f}}'.format(decimalplaces)
    # Return the formatted tick label
    return formatstring.format(y)

ax.yaxis.set_major_formatter(ticker.FuncFormatter(myLogFormat))

Ответ 3

Я нашел ответы Джо и Тома очень полезными, но в комментариях к этим ответам есть много полезных деталей. Вот краткое изложение двух сценариев:

Диапазоны выше 1

Вот пример кода, как у Джо, но с более высоким диапазоном:

import matplotlib.pyplot as plt

fig, ax = plt.subplots()
ax.axis([1, 10000, 1, 1000000])
ax.loglog()

plt.show()

Это показывает сюжет, подобный этому, используя научную запись: Default plot with scientific notation

Как и в ответе Джо, я использую ScalarFormatter, но я также называю set_scientific(False). Это необходимо, когда шкала поднимается до 1000000 или выше.

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

fig, ax = plt.subplots()
ax.axis([1, 10000, 1, 1000000])
ax.loglog()
for axis in [ax.xaxis, ax.yaxis]:
    formatter = ScalarFormatter()
    formatter.set_scientific(False)
    axis.set_major_formatter(formatter)

plt.show()

Plot with integer ticks

Диапазоны ниже 1

Как и в ответе Тома, вот что происходит, когда диапазон опускается ниже 1:

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

fig, ax = plt.subplots()
ax.axis([0.01, 10000, 1, 1000000])
ax.loglog()
for axis in [ax.xaxis, ax.yaxis]:
    formatter = ScalarFormatter()
    formatter.set_scientific(False)
    axis.set_major_formatter(formatter)

plt.show()

Это отображает первые два тика на оси х как нули.

Plot with ticks labelled as zero

Переключение на FuncFormatter обрабатывает это. Опять же, у меня были проблемы с числами 1000000 или выше, но добавление точности к строке формата решило эту проблему.

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

fig, ax = plt.subplots()
ax.axis([0.01, 10000, 1, 1000000])
ax.loglog()
for axis in [ax.xaxis, ax.yaxis]:
    formatter = FuncFormatter(lambda y, _: '{:.16g}'.format(y))
    axis.set_major_formatter(formatter)

plt.show()

enter image description here

Ответ 4

относительно этих вопросов

What if я wanted to change the numbers to, 1, 5, 10, 20?
– aloha Jul 10 '15 at 13:26

Я хотел бы добавить галочки между ними, например, 50 200 и т.д., как я могу сделать это? Я попытался, set_xticks [50.0,200.0], но это, похоже, не работает! - ThePredator 3 августа '15 в 12:54

Но с ax.axis([1, 100, 1, 100]) ScalarFormatter выдает 1.0, 10.0,... что не то, что я хочу. Я хочу, чтобы это дать целые числа... - CPBL 7 декабря 15 в 20:22

вы можете решить эту проблему следующим образом с помощью MINOR:

ax.yaxis.set_minor_formatter(matplotlib.ticker.ScalarFormatter())
ax.yaxis.set_minor_formatter(matplotlib.ticker.FormatStrFormatter("%.8f"))
ax.set_yticks([0.00000025, 0.00000015, 0.00000035])

в моем приложении я использую эту схему форматирования, которая, я думаю, решает большинство проблем, связанных со скалярным форматированием журнала; то же самое можно сделать для данных> 1.0 или форматирования по оси x:

plt.ylabel('LOGARITHMIC PRICE SCALE')
plt.yscale('log')
ax.yaxis.set_major_formatter(matplotlib.ticker.ScalarFormatter())
ax.yaxis.set_major_formatter(matplotlib.ticker.FormatStrFormatter("%.8f"))
ax.yaxis.set_minor_formatter(matplotlib.ticker.ScalarFormatter())
ax.yaxis.set_minor_formatter(matplotlib.ticker.FormatStrFormatter("%.8f"))
#####################################################
#force 'autoscale'
#####################################################
yd = [] #matrix of y values from all lines on plot
for n in range(len(plt.gca().get_lines())):
        line = plt.gca().get_lines()[n]
        yd.append((line.get_ydata()).tolist())
yd = [item for sublist in yd for item in sublist]
ymin, ymax = np.min(yd), np.max(yd)
ax.set_ylim([0.9*ymin, 1.1*ymax])
#####################################################
z = []
for i in [0.0000001, 0.00000015, 0.00000025, 0.00000035,
          0.000001, 0.0000015, 0.0000025, 0.0000035,
          0.00001,  0.000015, 0.000025, 0.000035,
          0.0001, 0.00015, 0.00025, 0.00035,
          0.001, 0.0015, 0.0025, 0.0035,
          0.01, 0.015, 0.025, 0.035,
          0.1, 0.15, 0.25, 0.35]:

    if ymin<i<ymax:
        z.append(i)
        ax.set_yticks(z)                

для комментариев по поводу "принудительного автомасштабирования" см.: Python matplotlib - логарифмическое автоматическое масштабирование

что дает:

enter image description here

затем для создания машины общего пользования:

# user controls
#####################################################
sub_ticks = [10,11,12,14,16,18,22,25,35,45] # fill these midpoints
sub_range = [-8,8] # from 100000000 to 0.000000001
format = "%.8f" # standard float string formatting

# set scalar and string format floats
#####################################################
ax.yaxis.set_major_formatter(matplotlib.ticker.ScalarFormatter())
ax.yaxis.set_major_formatter(matplotlib.ticker.FormatStrFormatter(format))
ax.yaxis.set_minor_formatter(matplotlib.ticker.ScalarFormatter())
ax.yaxis.set_minor_formatter(matplotlib.ticker.FormatStrFormatter(format))

#force 'autoscale'
#####################################################
yd = [] #matrix of y values from all lines on plot
for n in range(len(plt.gca().get_lines())):
        line = plt.gca().get_lines()[n]
        yd.append((line.get_ydata()).tolist())
yd = [item for sublist in yd for item in sublist]
ymin, ymax = np.min(yd), np.max(yd)
ax.set_ylim([0.9*ymin, 1.1*ymax])

# add sub minor ticks
#####################################################
set_sub_formatter=[]
for i in sub_ticks:
    for j in range(sub_range[0],sub_range[1]):
        set_sub_formatter.append(i*10**j)
k = []
for l in set_sub_formatter:
    if ymin<l<ymax:
        k.append(l)
ax.set_yticks(k)
#####################################################

выходы:

enter image description here