matplotlib: định dạng giá trị độ lệch trục thành số nguyên hoặc số cụ thể


92

Tôi có một hình matplotlib mà tôi đang vẽ dữ liệu luôn được gọi là nano giây (1e-9). Trên trục y, tức là nếu tôi có dữ liệu hàng chục nano giây. 44e-9, giá trị trên trục hiển thị là 4,4 với + 1e-8 làm phần bù. Có cách nào để buộc trục hiển thị 44 với độ lệch + 1e-9 không?

Điều tương tự cũng xảy ra với trục x của tôi, nơi trục hiển thị + 5.54478e4, trong đó tôi muốn nó hiển thị mức bù là +55447 (số nguyên, không có số thập phân - giá trị ở đây tính bằng ngày).

Tôi đã thử một vài thứ như sau:

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

cho trục x, nhưng điều này không hoạt động, mặc dù có thể tôi đang sử dụng nó không chính xác hoặc hiểu sai điều gì đó từ tài liệu, ai đó có thể chỉ cho tôi hướng chính xác không?

Cảm ơn, Jonathan

Minh họa vấn đề


Tôi đã thử làm điều gì đó với bộ định dạng nhưng vẫn chưa tìm thấy giải pháp nào ...:

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)

Một lưu ý nhỏ, tôi thực sự bối rối không biết đối tượng 'số bù đắp' thực sự nằm ở đâu ... nó có phải là một phần của dấu tích chính / phụ không?


1
Bạn đã thử set_unitschưa? matplotlib.sourceforge.net/api/… (Tôi không thể thử vì tôi không có matplotlib ở đây.)
Katriel

1
Tôi đã kiểm tra hàm set_units và nó có vẻ phức tạp hơn mức cần thiết (phải viết / thêm một mô-đun bổ sung ?? - basic_units?). Phải có một cách để chỉnh sửa định dạng của dấu tích. Hàm đơn vị / set_unit có vẻ giống như hàm này dọc theo dòng chuyển đổi đơn vị. Cảm ơn vì mẹo này, nó đã dẫn tôi đến một số giải pháp khác mà tôi đang tìm kiếm bây giờ!
Jonathan

1
xin vui lòng xem xét rcParamsđể biến nếu tắt theo mặc định: rcParams["axes.formatter.useoffset"] = Falsenhư ở đây: stackoverflow.com/questions/24171064/...
Ruggero Turra

Câu trả lời:


100

Tôi đã gặp chính xác vấn đề tương tự và những dòng này đã khắc phục sự cố:

from matplotlib.ticker import ScalarFormatter

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

1
Đây là câu trả lời nhanh chóng và dễ dàng. Cảm ơn bạn.
tối đa

6
Một lớp lót sẽ là:ax.get_yaxis().get_major_formatter().set_useOffset(False)
Dataman

3
cho noobs như tôi dont quên from matplotlib.ticker import ScalarFormattercho @Gonzalo 's mã để làm việc hoặc chỉ đơn giản là sử dụng @Dataman' s giải pháp trên
champost

36

Một giải pháp dễ dàng hơn nhiều là chỉ cần tùy chỉnh các nhãn đánh dấu. Lấy ví dụ sau:

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

văn bản thay thế

Lưu ý rằng trong trường hợp trục y, tôi nhân các giá trị với nhau 1e9rồi đề cập đến hằng số đó trong nhãn y


BIÊN TẬP

Một tùy chọn khác là giả mạo hệ số mũ bằng cách thêm thủ công văn bản của nó vào đầu âm mưu:

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

Ngoài ra, bạn có thể định dạng giá trị độ lệch trục x theo cách tương tự:

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)

văn bản thay thế


Đó chính xác là những gì tôi đã làm, lúc đầu. Thật không may, tôi không thể tìm thấy cách dễ dàng để đặt / hiển thị hệ số nhân trục (ngoài việc đặt nó vào nhãn trục y một cách rõ ràng như bạn đã làm.). Nếu bạn không phiền khi không có nhãn hệ số trục, đây là cách đơn giản hơn. Dù bằng cách nào, hãy +1 từ tôi.
Joe Kington

1
@Joe Kington: bạn có thể thêm nó theo cách thủ công dưới dạng văn bản ... xem chỉnh sửa ở trên :)
Amro

Tuyệt quá! Tôi sẽ thử cách tiếp cận của bạn với các nhãn cho trục x. Tôi sẽ lấy giá trị sàn của giá trị x đầu tiên, sau đó xóa nó khỏi mọi giá trị x và thêm "+ minxval" làm nhãn. Tôi không thể tìm ra cách khác để định dạng độ lệch dấu x. Tôi ổn với độ lớn của phần bù, tôi chỉ cần nó hiển thị dưới dạng giá trị không theo cấp số nhân.
Jonathan

Chà. Công việc tuyệt vời trong việc chỉ ra cách bạn thực sự có thể kiểm soát matplotlib và điều chỉnh nó theo nhu cầu của bạn và thực sự và một số pizazz cho âm mưu của bạn.
Physicsmichael

Làm thế nào để bạn thay đổi kích thước phông chữ của 1e-9 trong hình?
một đề nghị không thể từ chối

30

Bạn phải phân lớp ScalarFormatterđể làm những gì bạn cần ... _set_offsetchỉ cần thêm một hằng số, bạn muốn thiết lập ScalarFormatter.orderOfMagnitude. Thật không may, cài đặt thủ công orderOfMagnitudesẽ không làm được gì, vì nó được đặt lại khi ScalarFormatterphiên bản được gọi để định dạng các nhãn đánh dấu trục. Nó không nên phức tạp như vậy, nhưng tôi không thể tìm thấy một cách dễ dàng hơn để làm chính xác những gì bạn muốn ... Đây là một ví dụ:

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

Điều này mang lại một cái gì đó như: văn bản thay thế

Trong khi đó, định dạng mặc định sẽ như sau: văn bản thay thế

Hi vọng nó giúp được chút ít!

Chỉnh sửa: Đối với giá trị của nó là gì, tôi cũng không biết nhãn bù đắp nằm ở đâu ... Sẽ dễ dàng hơn một chút nếu chỉ đặt nó theo cách thủ công, nhưng tôi không thể tìm ra cách làm như vậy ... Tôi có cảm giác rằng phải có một cách dễ dàng hơn tất cả những điều này. Nó hoạt động, mặc dù!


Cảm ơn! Phân lớp ScalarFormatter hoạt động rất tốt! Nhưng tôi đoán tôi đã không trình bày rõ ràng những gì tôi muốn cho trục x. Tôi muốn giữ phần bù cho trục x, nhưng định dạng giá trị của phần bù để nó không được hiển thị dưới dạng số mũ.
Jonathan

Đây là phương pháp duy nhất hiệu quả với tôi! Cảm ơn :)
Nhà khoa học đại dương

11

Tương tự như câu trả lời của Amro, bạn có thể sử dụng 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

Giải pháp của Gonzalo bắt đầu hiệu quả với tôi sau khi thêm set_scientific(False):

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

5

Như đã được chỉ ra trong các nhận xét và trong câu trả lời này , phần bù có thể được tắt trên toàn cầu, bằng cách thực hiện như sau:

matplotlib.rcParams['axes.formatter.useoffset'] = False

4

Tôi nghĩ rằng một cách thanh lịch hơn là sử dụng trình định dạng mã cổ phiếu. Đây là một ví dụ cho cả xaxis và 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
Điều này không trả lời được câu hỏi, đó là làm thế nào để xác định phần bù và / hoặc hệ số được sử dụng trong ký hiệu khoa học .
sodd

@nordev Ngay cả khi câu trả lời của tôi không trả lời cụ thể câu hỏi, nó vẫn đưa ra một gợi ý. Thông báo là bạn có thể chọn một định dạng khác và lấy những gì bạn muốn thay vì một ngày từ ví dụ của tôi. Trong thế giới khoa học, ngày Julian là chuẩn mực, hoặc bạn có thể sử dụng ngày như trong ví dụ của tôi. Điều tôi đang cố gắng đề xuất là có thể thực hiện một cách tiếp cận khác. Đôi khi một câu hỏi có thể được đặt ra bởi vì người đó không có ý tưởng tốt hơn vào lúc này. Các giải pháp thay thế không được bỏ đi hoặc đối xử thiếu tôn trọng. Nói chung, tôi không xứng đáng với -1 phiếu bầu.
Bogdan

2

Đối với phần thứ hai, mà không cần thiết lập lại tất cả các tick theo cách thủ công, đây là giải pháp của tôi:

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)

rõ ràng bạn có thể đặt chuỗi định dạng thành bất kỳ thứ gì bạn muốn.


Rất tiếc, tôi chưa tìm hiểu cách đặt hệ số như phần đầu tiên của câu hỏi của bạn.
astrojuanlu
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.