matplotlib: จัดรูปแบบค่าชดเชยแกนเป็นจำนวนเต็มหรือจำนวนเฉพาะ


93

ฉันมีรูป matplotlib ซึ่งฉันกำลังพล็อตข้อมูลที่มักเรียกว่านาโนวินาที (1e-9) บนแกน y ถ้าฉันมีข้อมูลที่มีค่าหลายสิบนาโนวินาทีเช่น 44e-9 ค่าบนแกนจะแสดงเป็น 4.4 โดยมี + 1e-8 เป็นค่าชดเชย มีการบังคับให้แกนแสดง 44 ด้วยออฟเซ็ต + 1e-9 หรือไม่?

เช่นเดียวกันกับแกน x ของฉันที่แกนแสดง + 5.54478e4 โดยที่ฉันอยากให้มันแสดงค่าออฟเซ็ตเป็น +55447 (จำนวนเต็มไม่มีทศนิยม - ค่าในที่นี้คือวัน)

ฉันได้ลองสองสามสิ่งดังนี้:

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

สำหรับแกน x แต่มันใช้ไม่ได้แม้ว่าฉันอาจจะใช้มันไม่ถูกต้องหรือตีความบางอย่างจากเอกสารผิดใครบางคนสามารถชี้ฉันไปในทิศทางที่ถูกต้องได้ไหม

ขอบคุณโจนาธาน

ภาพประกอบปัญหา


ฉันพยายามทำอะไรบางอย่างกับฟอร์แมต แต่ยังไม่พบวิธีแก้ปัญหาใด ๆ ... :

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

และ

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

จากบันทึกด้านข้างฉันสับสนจริงๆว่าวัตถุ 'offset number' อยู่ที่ไหน ... มันเป็นส่วนหนึ่งของเห็บหลัก / รองหรือไม่?


1
คุณลองแล้วset_unitsหรือยัง? matplotlib.sourceforge.net/api/… (ฉันไม่สามารถลองได้เพราะฉันไม่มี matplotlib ที่นี่)
Katriel

1
ฉันตรวจสอบฟังก์ชัน set_units และดูเหมือนว่าจะซับซ้อนเกินความจำเป็น (ต้องเขียน / เพิ่มโมดูลเพิ่มเติม ?? - basic_units?) จะต้องมีวิธีแก้ไขรูปแบบของเครื่องหมายถูก ฟังก์ชัน units / set_unit ดูเหมือนว่าจะมีมากขึ้นตามบรรทัดของการแปลงหน่วย ขอบคุณสำหรับเคล็ดลับนี้ทำให้ฉันไปสู่วิธีแก้ปัญหาอื่น ๆ ที่ฉันกำลังมองหาอยู่ตอนนี้
Jonathan

1
โปรดพิจารณาrcParamsปิดหากปิดโดยค่าเริ่มต้น: rcParams["axes.formatter.useoffset"] = Falseดังที่นี่: stackoverflow.com/questions/24171064/…
Ruggero Turra

คำตอบ:


100

ฉันมีปัญหาเดียวกันทุกประการและบรรทัดเหล่านี้แก้ไขปัญหาได้:

from matplotlib.ticker import ScalarFormatter

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

1
นี่คือคำตอบที่ง่ายและรวดเร็ว ขอขอบคุณ.
maxm

6
หนึ่งซับจะเป็น:ax.get_yaxis().get_major_formatter().set_useOffset(False)
Dataman

3
สำหรับ noobs อย่างฉันอย่าลืมfrom matplotlib.ticker import ScalarFormatterรหัสของ @Gonzalo ในการทำงานหรือเพียงแค่ใช้วิธีแก้ปัญหาของ
@Dataman

36

วิธีแก้ปัญหาที่ง่ายกว่ามากคือปรับแต่งป้ายกำกับ ใช้ตัวอย่างนี้:

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

ข้อความแสดงแทน

สังเกตว่าในกรณีแกน y ฉันคูณค่าด้วยการ1e9กล่าวถึงค่าคงที่นั้นในป้ายกำกับ y แล้ว


แก้ไข

อีกทางเลือกหนึ่งคือการปลอมตัวคูณเลขชี้กำลังด้วยการเพิ่มข้อความที่ด้านบนของพล็อตด้วยตนเอง:

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

แก้ไข 2

นอกจากนี้คุณสามารถจัดรูปแบบค่าออฟเซ็ตแกน x ในลักษณะเดียวกัน:

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)

ข้อความแสดงแทน


นั่นคือสิ่งที่ฉันทำในตอนแรก น่าเสียดายที่ฉันไม่พบวิธีง่ายๆในการตั้งค่า / แสดงตัวคูณแกน (นอกเหนือจากการใส่ไว้ในป้ายแกน y อย่างชัดเจนอย่างที่คุณทำ) หากคุณไม่คิดว่าจะไม่มีป้ายตัวคูณแกนนี่เป็นวิธีที่ง่ายกว่า ไม่ว่าจะด้วยวิธีใด +1 จากฉัน
Joe Kington

1
@ Joe Kington: คุณสามารถเพิ่มด้วยตนเองเป็นข้อความ ... ดูการแก้ไขด้านบน :)
Amro

เยี่ยมมาก! ผมจะลองใช้ป้ายกำกับสำหรับแกน x ฉันจะใช้พื้นของค่า x แรกจากนั้นลบออกจากค่า x ทุกค่าและเพิ่ม "+ minxval" เป็นป้ายกำกับ ฉันคิดไม่ออกว่าจะจัดรูปแบบออฟเซ็ต x-tick อย่างไร ฉันสบายดีกับขนาดของค่าชดเชยฉันแค่ต้องการให้มันแสดงเป็นค่าที่ไม่ใช่เลขชี้กำลัง
โจนาธาน

ว้าว. เป็นงานที่ยอดเยี่ยมในการแสดงให้เห็นว่าคุณสามารถควบคุม matplotlib ได้อย่างไรและปรับแต่งตามความต้องการของคุณและจริง ๆ และ pizazz บางอย่างในแผนการของคุณ
ฟิสิกส์ michael

คุณจะเปลี่ยนขนาดฟอนต์ของ 1e-9 ในรูปได้อย่างไร?
ข้อเสนอไม่สามารถปฏิเสธ

30

คุณต้องซับคลาสScalarFormatterที่จะทำสิ่งที่คุณต้อง ... เพียงแค่เพิ่มคงที่ที่คุณต้องการไปยังชุด_set_offset ScalarFormatter.orderOfMagnitudeน่าเสียดายที่การตั้งค่าด้วยตนเองorderOfMagnitudeจะไม่ทำอะไรเลยเนื่องจากจะรีเซ็ตเมื่อScalarFormatterอินสแตนซ์ถูกเรียกให้จัดรูปแบบป้ายกำกับแกน ไม่น่าจะซับซ้อนขนาดนี้ แต่ฉันหาวิธีที่ง่ายกว่านี้ไม่ได้ในการทำสิ่งที่คุณต้องการ ... นี่คือตัวอย่าง:

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

ซึ่งให้ผลตอบแทนดังนี้: ข้อความแสดงแทน

ในขณะที่การจัดรูปแบบเริ่มต้นจะมีลักษณะดังนี้: ข้อความแสดงแทน

หวังว่าจะช่วยได้เล็กน้อย!

แก้ไข: สำหรับสิ่งที่คุ้มค่าฉันไม่รู้ว่าป้ายออฟเซ็ตอยู่ที่ไหนเหมือนกัน ... มันจะง่ายกว่าเล็กน้อยที่จะตั้งค่าด้วยตนเอง แต่ฉันคิดไม่ออกว่าจะทำอย่างไร ... ฉันรู้สึก จะต้องมีวิธีที่ง่ายกว่านี้ทั้งหมด มันใช้งานได้!


ขอบคุณ! Subclassing ScalarFormatter ทำงานได้ดีมาก! แต่ฉันเดาว่าฉันไม่ได้ระบุอย่างชัดเจนว่าฉันต้องการอะไรสำหรับแกน x ฉันต้องการคงค่าชดเชยสำหรับแกน x แต่จัดรูปแบบค่าออฟเซ็ตเพื่อไม่ให้แสดงเป็นเลขชี้กำลัง
โจนาธาน

นี่เป็นวิธีเดียวที่ใช้ได้ผลสำหรับฉัน! ขอบคุณ :)
Ocean Scientist

11

คล้ายกับคำตอบของ Amro คุณสามารถใช้ 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()

5

โซลูชันของ Gonzalo เริ่มทำงานให้ฉันหลังจากเพิ่มset_scientific(False):

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


4

ฉันคิดว่าวิธีที่ดีกว่าคือการใช้ตัวจัดรูปแบบทิกเกอร์ นี่คือตัวอย่างสำหรับทั้ง xaxis และ yaxis:

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
นี้ไม่ได้ตอบคำถามซึ่งเป็นวิธีการระบุชดเชยและ / หรือปัจจัยที่ใช้ในทางวิทยาศาสตร์
สด

@nordev แม้ว่าคำตอบของฉันจะไม่ได้ตอบคำถามโดยเฉพาะ แต่ก็ยังให้คำใบ้ ข้อความคือคุณสามารถเลือกฟอร์แมตเตอร์อื่นและรับสิ่งที่คุณต้องการแทนวันที่จากตัวอย่างของฉัน ในโลกวิทยาศาสตร์วันจูเลียนเป็นบรรทัดฐานหรือคุณสามารถใช้วันที่ตามตัวอย่างของฉัน สิ่งที่ฉันพยายามแนะนำคือสามารถใช้แนวทางอื่นได้ บางครั้งอาจมีการถามคำถามเนื่องจากบุคคลนั้นไม่มีความคิดที่ดีขึ้นในขณะนี้ ทางเลือกอื่นไม่ควรทิ้งหรือปฏิบัติอย่างไม่เคารพ สรุปแล้วฉันไม่สมควรได้รับการโหวต -1
Bogdan

2

สำหรับส่วนที่สองโดยไม่ต้องรีเซ็ตเห็บทั้งหมดด้วยตนเองอีกครั้งนี่คือวิธีแก้ปัญหาของฉัน:

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)

เห็นได้ชัดว่าคุณสามารถตั้งค่าสตริงรูปแบบเป็นอะไรก็ได้ที่คุณต้องการ


น่าเสียดายที่ฉันยังไม่ได้ตรวจสอบวิธีตั้งค่าตัวคูณเป็นส่วนแรกของคำถามของคุณ
astrojuanlu
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.