94 votes

matplotlib : formatage des valeurs de décalage d'axe en nombres entiers ou spécifiques

J'ai une figure matplotlib dans laquelle je trace des données qui sont toujours désignées par des nanosecondes (1e-9). Sur l'axe des y, si j'ai des données qui sont des dizaines de nanosecondes, c'est-à-dire 44e-9, la valeur sur l'axe est 4,4 avec un décalage de +1e-8. Existe-t-il un moyen de forcer l'axe à afficher 44 avec un décalage de +1e-9 ?

Il en va de même pour mon axe des abscisses, qui affiche +5.54478e4, alors que je préférerais qu'il affiche un décalage de +55447 (nombre entier, sans décimale - la valeur est ici exprimée en jours).

J'ai essayé plusieurs choses comme ça :

p = axes.plot(x,y)
p.ticklabel_format(style='plain')

pour l'axe des x, mais cela ne fonctionne pas, bien que je l'utilise probablement de manière incorrecte ou que j'interprète mal quelque chose dans la documentation, quelqu'un peut-il m'indiquer la bonne direction ?

Merci, Jonathan

Problem illustration


J'ai essayé de faire quelque chose avec les formateurs mais je n'ai pas encore trouvé de solution... :

myyfmt = ScalarFormatter(useOffset=True)
myyfmt._set_offset(1e9)
axes.get_yaxis().set_major_formatter(myyfmt)

y

myxfmt = ScalarFormatter(useOffset=True)
myxfmt.set_portlimits((-9,5))
axes.get_xaxis().set_major_formatter(myxfmt)

Par ailleurs, je ne sais pas vraiment où se trouve l'objet "numéro d'offset"... fait-il partie des ticks majeurs et mineurs ?

1 votes

Avez-vous essayé set_units ? matplotlib.sourceforge.net/api/ (Je ne peux pas l'essayer car je n'ai pas matplotlib ici).

1 votes

J'ai vérifié la fonction set_units et cela semble bien plus compliqué que nécessaire (il faut écrire/ajouté un module supplémentaire??-basic_units ?). Il doit y avoir un moyen de modifier simplement le format du tick. La fonction units / set_unit semble être plus proche de la conversion d'unités. Merci pour le conseil, il m'a conduit à d'autres solutions que j'étudie maintenant !

1 votes

Veuillez considérer rcParams pour le désactiver par défaut : rcParams["axes.formatter.useoffset"] = False comme ici : stackoverflow.com/questions/24171064/

100voto

Gonzalo Points 442

J'avais exactement le même problème, et ces lignes ont réglé le problème :

from matplotlib.ticker import ScalarFormatter

y_formatter = ScalarFormatter(useOffset=False)
ax.yaxis.set_major_formatter(y_formatter)

1 votes

C'est la réponse rapide et facile. Merci.

6 votes

Une phrase pourrait être : ax.get_yaxis().get_major_formatter().set_useOffset(False)

3 votes

Pour les novices comme moi, n'oubliez pas les from matplotlib.ticker import ScalarFormatter pour que le code de @Gonzalo fonctionne ou utilisez simplement la solution de @Dataman ci-dessus.

35voto

Amro Points 72743

Une solution beaucoup plus simple consiste à personnaliser les étiquettes de coche. Prenez cet exemple :

from pylab import *

# Generate some random data...
x = linspace(55478, 55486, 100)
y = random(100) - 0.5
y = cumsum(y)
y -= y.min()
y *= 1e-8

# plot
plot(x,y)

# xticks
locs,labels = xticks()
xticks(locs, map(lambda x: "%g" % x, locs))

# ytikcs
locs,labels = yticks()
yticks(locs, map(lambda x: "%.1f" % x, locs*1e9))
ylabel('microseconds (1E-9)')

show()

alt text

Remarquez comment dans le cas de l'axe des y, j'ai multiplié les valeurs par 1e9 puis mentionné cette constante dans l'étiquette y


EDIT

Une autre option consiste à simuler le multiplicateur de l'exposant en ajoutant manuellement son texte en haut du graphique :

locs,labels = yticks()
yticks(locs, map(lambda x: "%.1f" % x, locs*1e9))
text(0.0, 1.01, '1e-9', fontsize=10, transform = gca().transAxes)

EDIT2

Vous pouvez également formater la valeur du décalage de l'axe des x de la même manière :

locs,labels = xticks()
xticks(locs, map(lambda x: "%g" % x, locs-min(locs)))
text(0.92, -0.07, "+%g" % min(locs), fontsize=10, transform = gca().transAxes)

alt text

0 votes

C'est exactement ce que j'ai fait, au début. Malheureusement, je n'ai pas trouvé de moyen facile de définir/afficher le multiplicateur d'axe (autre que de le mettre explicitement dans l'étiquette de l'axe des y, comme vous l'avez fait). Si cela ne vous dérange pas de ne pas avoir l'étiquette du multiplicateur d'axe, c'est le moyen le plus simple. Dans tous les cas, +1 de ma part.

1 votes

@Joe Kington : vous pouvez l'ajouter manuellement comme texte... voir l'édition ci-dessus :)

0 votes

Super ! Je vais essayer votre approche avec les étiquettes pour l'axe des x. Je vais prendre le plancher de la première valeur x, puis l'enlever de chaque valeur x et ajouter un "+minxval" comme étiquette. Je n'arrive pas à trouver comment formater autrement le décalage des x-tick. L'amplitude du décalage ne me pose pas de problème, j'ai juste besoin qu'il s'affiche comme une valeur non exponentielle.

32voto

Joe Kington Points 68089

Vous devez sous-classer ScalarFormatter pour faire ce dont vous avez besoin... _set_offset ajoute juste une constante, vous voulez mettre ScalarFormatter.orderOfMagnitude . Malheureusement, le réglage manuel orderOfMagnitude ne fera rien, puisqu'elle est réinitialisée lorsque la fonction ScalarFormatter est appelée pour formater les étiquettes des tics des axes. Cela ne devrait pas être aussi compliqué, mais je ne trouve pas de moyen plus simple de faire exactement ce que vous voulez... Voici un exemple :

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

class FixedOrderFormatter(ScalarFormatter):
    """Formats axis ticks using scientific notation with a constant order of 
    magnitude"""
    def __init__(self, order_of_mag=0, useOffset=True, useMathText=False):
        self._order_of_mag = order_of_mag
        ScalarFormatter.__init__(self, useOffset=useOffset, 
                                 useMathText=useMathText)
    def _set_orderOfMagnitude(self, range):
        """Over-riding this to avoid having orderOfMagnitude reset elsewhere"""
        self.orderOfMagnitude = self._order_of_mag

# Generate some random data...
x = np.linspace(55478, 55486, 100) 
y = np.random.random(100) - 0.5
y = np.cumsum(y)
y -= y.min()
y *= 1e-8

# Plot the data...
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(x, y, 'b-')

# Force the y-axis ticks to use 1e-9 as a base exponent 
ax.yaxis.set_major_formatter(FixedOrderFormatter(-9))

# Make the x-axis ticks formatted to 0 decimal places
ax.xaxis.set_major_formatter(FormatStrFormatter('%0.0f'))
plt.show()

Ce qui donne quelque chose comme : alt text

Alors que le formatage par défaut serait le suivant : alt text

J'espère que cela vous aidera un peu !

Edit : Pour ce que ça vaut, je ne sais pas non plus où se trouve le label offset... Il serait un peu plus facile de le régler manuellement, mais je n'ai pas trouvé comment faire... J'ai l'impression qu'il doit y avoir un moyen plus simple que tout cela. Mais ça marche !

0 votes

Merci ! La sous-classification du ScalarFormatter fonctionne très bien ! Mais je pense que je n'ai pas clairement indiqué ce que je voulais pour l'axe des x. Je voudrais garder le décalage pour l'axe des x, mais formater la valeur du décalage pour qu'elle ne soit pas affichée comme un exposant.

0 votes

C'est la seule méthode qui a fonctionné pour moi ! Merci :)

11voto

idrinkpabst Points 668

Comme pour la réponse d'Amro, vous pouvez utiliser FuncFormatter.

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

# Generate some random data...
x = np.linspace(55478, 55486, 100) 
y = np.random.random(100) - 0.5
y = np.cumsum(y)
y -= y.min()
y *= 1e-8

# Plot the data...
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(x, y, 'b-')

# Force the y-axis ticks to use 1e-9 as a base exponent 
ax.yaxis.set_major_formatter(FuncFormatter(lambda x, pos: ('%.1f')%(x*1e9)))
ax.set_ylabel('microseconds (1E-9)')

# Make the x-axis ticks formatted to 0 decimal places
ax.xaxis.set_major_formatter(FuncFormatter(lambda x, pos: '%.0f'%x))
plt.show()

4voto

Bogdan Points 58

Je pense qu'une manière plus élégante est d'utiliser le formateur de ticker. Voici un exemple pour l'axe des x et l'axe des y :

from pylab import *
from matplotlib.ticker import MultipleLocator, FormatStrFormatter

majorLocator   = MultipleLocator(20)
xFormatter = FormatStrFormatter('%d')
yFormatter = FormatStrFormatter('%.2f')
minorLocator   = MultipleLocator(5)

t = arange(0.0, 100.0, 0.1)
s = sin(0.1*pi*t)*exp(-t*0.01)

ax = subplot(111)
plot(t,s)

ax.xaxis.set_major_locator(majorLocator)
ax.xaxis.set_major_formatter(xFormatter)
ax.yaxis.set_major_formatter(yFormatter)

#for the minor ticks, use no labels; default NullFormatter
ax.xaxis.set_minor_locator(minorLocator)

1 votes

Cela ne répond pas à la question, qui est comment spécifier le décalage et/ou le facteur utilisé en notation scientifique .

0 votes

@nordev Même si ma réponse ne répond pas spécifiquement à la question, elle donne quand même un indice. Le message est que vous pouvez choisir un autre formateur et obtenir ce que vous voulez au lieu d'une date dans mon exemple. Dans le monde scientifique, le jour Julien est la norme, ou vous pouvez utiliser la date comme dans mon exemple. Ce que j'essayais de suggérer, c'est qu'une approche différente peut être adoptée. Parfois, une question peut être posée parce que la personne n'a pas de meilleure idée pour le moment. Les solutions alternatives ne doivent pas être écartées ou traitées avec manque de respect. Dans l'ensemble, je ne méritais pas le vote négatif.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X