matplotlib: eksen ofset değerlerini tam sayılara veya belirli bir sayıya biçimlendirin


93

Her zaman nanosaniye (1e-9) olarak adlandırılan verileri çizdiğim bir matplotlib rakamım var. Y ekseninde, onlarca nanosaniye olan veriye sahipsem, yani. 44e-9, eksen üzerindeki değer ofset olarak + 1e-8 ile 4.4 olarak gösterilir. Ekseni + 1e-9 ofsetiyle 44'ü göstermeye zorlamanın bir yolu var mı?

Aynısı, eksenin + 5.54478e4'ü gösterdiği x eksenim için de geçerlidir, burada +55447'lik bir ofset göstermeyi tercih ederim (tam sayı, ondalık yok - buradaki değer gün cinsindendir).

Bunun gibi birkaç şeyi denedim:

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

x ekseni için, ancak bu işe yaramıyor, muhtemelen yanlış kullanıyorum veya belgelerden bir şeyi yanlış yorumluyorum, birisi beni doğru yöne yönlendirebilir mi?

Teşekkürler Jonathan

Sorun illüstrasyon


Biçimlendiricilerle bir şeyler yapmayı denedim ama henüz bir çözüm bulamadım ...:

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

ve

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

Bir yan not olarak, aslında 'ofset numarası' nesnesinin gerçekte nerede bulunduğu konusunda kafam karıştı ... büyük / küçük kenelerin bir parçası mı?



1
Set_units işlevini kontrol ettim ve gereğinden çok daha karmaşık görünüyor (ek bir modül yazmak / eklemek mi gerekiyor ?? - basic_units?). Sadece kene formatını düzenlemenin bir yolu olmalı. Units / set_unit işlevi, birim dönüştürme çizgileri boyunca daha çok görünmektedir. Yine de ipucu için teşekkürler, beni şu anda aradığım başka çözümlere götürdü!
Jonathan

1
lütfen rcParamsvarsayılan rcParams["axes.formatter.useoffset"] = Falseolarak devre dışı bırakmayı düşünün : burada olduğu gibi: stackoverflow.com/questions/24171064/…
Ruggero Turra

Yanıtlar:


100

Tam olarak aynı sorunu yaşadım ve şu satırlar sorunu çözdü:

from matplotlib.ticker import ScalarFormatter

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

1
Bu hızlı ve kolay cevaptır. Teşekkür ederim.
maxm

6
Tek ax.get_yaxis().get_major_formatter().set_useOffset(False)
hatlı uçuş

3
benim gibi from matplotlib.ticker import ScalarFormatterçaylaklar için @Gonzalo'nun kodunu unutma ya da yukarıdaki
@Dataman

36

Çok daha kolay bir çözüm, kene etiketlerini basitçe özelleştirmektir. Bu örneği ele alalım:

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()

alternatif metin

Y ekseni durumunda, değerleri çarpıp 1e9daha sonra y etiketinde sabitten bahsettiğime dikkat edin.


DÜZENLE

Başka bir seçenek de üs çarpanı metnini grafiğin üstüne elle ekleyerek taklit etmektir:

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

DÜZENLE2

Ayrıca x ekseni ofset değerini aynı şekilde biçimlendirebilirsiniz:

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)

alternatif metin


İlk başta ben de öyle yaptım. Ne yazık ki, eksen çarpanını ayarlamanın / göstermenin kolay bir yolunu bulamadım (sizin yaptığınız gibi bunu açıkça y ekseni etiketine koymak dışında). Eksen çarpanı etiketini almamayı düşünüyorsanız, bu daha basit bir yoldur. Her iki durumda da benden +1.
Joe Kington

1
@Joe Kington: bunu manuel olarak metin olarak ekleyebilirsiniz ... yukarıdaki düzenlemeye bakın :)
Amro

Harika! Yaklaşımınızı x ekseni için etiketlerle deneyeceğim. İlk x değerinin tabanını alacağım, ardından bunu her x değerinden kaldıracağım ve etiket olarak bir "+ minxval" ekleyeceğim. X-tick ofsetini başka nasıl biçimlendireceğimi bulamıyorum. Ofsetin büyüklüğü konusunda iyiyim, sadece üstel olmayan bir değer olarak görüntülenmesi gerekiyor.
Jonathan

Vay. Matplotlib'i gerçekten nasıl kontrol edebileceğinizi ve ihtiyaçlarınıza göre nasıl değiştirebileceğinizi ve olay örgülerinize gerçekten ve biraz canlılık katabileceğinizi göstermede harika bir iş çıkardınız.
physicsmichael

Şekilde 1e-9'un yazı tipi boyutunu nasıl değiştirirsiniz?
bir teklif

30

İhtiyacınız ScalarFormatterolan şeyi yapmak için alt sınıfa ihtiyacınız var ... _set_offsetsadece bir sabit ekler, ayarlamak istediğiniz ScalarFormatter.orderOfMagnitude. Maalesef, örnek eksen onay etiketlerini biçimlendirmek için çağrıldığında orderOfMagnitudesıfırlandığı için manuel olarak ayarlama hiçbir şey yapmaz ScalarFormatter. Bu kadar karmaşık olmamalı, ancak tam olarak istediğiniz şeyi yapmanın daha kolay bir yolunu bulamıyorum ... İşte bir örnek:

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()

Aşağıdakilere benzer bir şey veren: alternatif metin

Oysa varsayılan biçimlendirme şöyle görünür: alternatif metin

Umarım bu biraz yardımcı olur!

Düzenleme: Değeri ne olursa olsun, ofset etiketinin nerede olduğunu da bilmiyorum ... Sadece manuel olarak ayarlamak biraz daha kolay olurdu, ama nasıl yapılacağını bulamadım ... tüm bunlardan daha kolay bir yol olması gerektiğini. Yine de çalışıyor!


Teşekkürler! ScalarFormatter'ın alt sınıflara ayrılması harika çalışıyor! Ama sanırım x ekseni için ne istediğimi açıkça belirtmedim. X ekseni için ofseti korumak istiyorum, ancak ofsetin değerini üs olarak gösterilmeyecek şekilde biçimlendirmek istiyorum.
Jonathan

Benim için işe yarayan tek yöntem bu! Teşekkürler :)
Ocean Scientist

11

Amro'nun cevabına benzer şekilde, FuncFormatter'ı kullanabilirsiniz.

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()

5

Gonzalo'nun çözümü, şunları ekledikten sonra benim için çalışmaya başladı set_scientific(False):

ax=gca()
fmt=matplotlib.ticker.ScalarFormatter(useOffset=False)
fmt.set_scientific(False)
ax.xaxis.set_major_formatter(fmt)


4

Bence daha zarif bir yol, şerit formatlayıcıyı kullanmaktır. İşte hem xaxis hem de yaxis için bir örnek:

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
Bu, bilimsel gösterimde kullanılan ofsetin ve / veya faktörün nasıl belirleneceği sorusuna cevap vermez .
2013

@nordev Cevabım soruyu tam olarak cevaplamasa da yine de bir ipucu veriyor. Mesaj, benim örneğimden bir tarih yerine başka bir formatlayıcı seçip istediğinizi elde edebileceğinizdir. Bilim dünyasında Jülyen günü normdur veya benim örneğimdeki gibi tarihi kullanabilirsiniz. Önermeye çalıştığım şey, farklı bir yaklaşımın benimsenebileceğidir. Bazen kişinin o anda daha iyi bir fikri olmadığı için soru sorulabilir. Alternatif çözümler atılmamalı veya saygısız davranılmamalıdır. Sonuçta -1 oyu hak etmedim.
Bogdan

2

İkinci kısım için, tüm işaretleri tekrar manuel olarak sıfırlamadan, bu benim çözümümdü:

class CustomScalarFormatter(ScalarFormatter):
    def format_data(self, value):
        if self._useLocale:
            s = locale.format_string('%1.2g', (value,))
        else:
            s = '%1.2g' % value
        s = self._formatSciNotation(s)
        return self.fix_minus(s)
xmajorformatter = CustomScalarFormatter()  # default useOffset=True
axes.get_xaxis().set_major_formatter(xmajorformatter)

tabii ki biçim dizesini istediğiniz gibi ayarlayabilirsiniz.


Maalesef, çarpanı sorunun ilk bölümü olarak nasıl ayarlayacağımı araştırmadım.
astrojuanlu
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.