python - graficos - Escala de registro de Matplotlib Marque el formato del número de etiqueta
matplotlib python 3 (4)
Con matplotlib
cuando se especifica una escala logarítmica para un eje, el método predeterminado para etiquetar ese eje es con números que son 10 a una potencia, por ejemplo. 10 ^ 6. ¿Hay alguna manera fácil de cambiar todas estas etiquetas para que sean su representación numérica completa? p.ej. 1, 10, 100, etc.
Tenga en cuenta que no sé cuál será el rango de potencias y quiero admitir un rango arbitrario (negativos incluidos).
Claro, solo cambia el formateador.
Por ejemplo, si tenemos esta trama:
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.axis([1, 10000, 1, 100000])
ax.loglog()
plt.show()
Puede establecer las etiquetas de tic tac de forma manual, pero luego las ubicaciones de tic y las etiquetas se corregirán cuando haga zoom / pan / etc. Por lo tanto, es mejor cambiar el formateador:
from matplotlib.ticker import ScalarFormatter
for axis in [ax.xaxis, ax.yaxis]:
axis.set_major_formatter(ScalarFormatter())
Descubrí que utilizar ScalarFormatter
es excelente si todos los valores de tilde son mayores o iguales que 1. Sin embargo, si tiene un tic en un número <1
, ScalarFormatter
imprime la etiqueta de tilde como 0
.
He usado esta función lambda
con FuncFormatter
para establecer los números >= 1
en su valor entero, y los números <1
en su valor decimal, con el número mínimo de decimales requerido (es decir 0.1, 0.01, 0.001
, etc.). Supone que solo está configurando ticks en los valores 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)))
Para mayor claridad, aquí está la función lambda escrita de una manera más detallada, pero también más comprensible:
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))
Encontré Tom''s respuestas de Joe''s y Tom''s muy útiles, pero hay muchos detalles útiles en los comentarios sobre esas respuestas. Aquí hay un resumen de los dos escenarios:
Rangos superiores a 1
Aquí está el código de ejemplo como Joe, pero con un rango más alto:
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.axis([1, 10000, 1, 1000000])
ax.loglog()
plt.show()
Eso muestra una trama como esta, usando notación científica:
Como en la respuesta de Joe, uso un ScalarFormatter
, pero también lo llamo set_scientific(False)
. Eso es necesario cuando la báscula sube a 1000000 o más.
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()
Rangos por debajo de 1
Como en la respuesta de Tom, esto es lo que sucede cuando el rango va por debajo de 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()
Eso muestra los primeros dos tics en el eje x como ceros.
El cambio a FuncFormatter
encarga de eso. Una vez más, tuve problemas con los números 1000000 o superior, pero al agregar una precisión a la cadena de formato lo resolvió.
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()
con respecto a estas preguntas
¿Qué pasa si quiero cambiar los números a, 1, 5, 10, 20?
- aloha 10 de julio de 15 a 13:26Me gustaría agregar ticks entre medio, como 50,200, etc., ¿Cómo puedo hacer eso? Intenté, set_xticks [50.0,200.0] ¡pero eso no parece funcionar! - ThePredator 3 de agosto de 15 a 12:54
Pero con ax.axis ([1, 100, 1, 100]), ScalarFormatter da 1.0, 10.0, ... que no es lo que deseo. Quiero que den enteros ... - CPBL 7 de diciembre de 15 a 20:22
puedes resolver esos problemas de esta manera con el formateador 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])
en mi aplicación estoy usando este esquema de formato, que creo que resuelve la mayoría de los problemas relacionados con el formato escalar de registro; lo mismo podría hacerse para el formato de datos> 1.0 o eje 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)
para comentarios sobre "force autoscale" ver: Python matplotlib logarítmico autoscale
cuyos rendimientos:
luego para crear una máquina de uso general:
# 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)
#####################################################
rendimientos: