2015-06-30 16 views
13

Tôi có tệp chứa các sự kiện đã ghi nhật ký. Mỗi mục có một thời gian và độ trễ. Tôi quan tâm đến âm mưu phân phối tích lũy chức năng của các độ trễ. Tôi quan tâm nhất đến độ trễ đuôi nên tôi muốn âm mưu có trục y lôgarit. Tôi quan tâm đến độ trễ ở các phần trăm sau: thứ 90, 99, 99,9, 99,99 và 99,999. Đây là mã của tôi cho đến nay mà tạo ra một âm mưu CDF thường xuyên:Lôgarit lôgarit của hàm phân phối lũy tích trong matplotlib

# retrieve event times and latencies from the file 
times, latencies = read_in_data_from_file('myfile.csv') 
# compute the CDF 
cdfx = numpy.sort(latencies) 
cdfy = numpy.linspace(1/len(latencies), 1.0, len(latencies)) 
# plot the CDF 
plt.plot(cdfx, cdfy) 
plt.show() 

Regular CDF Plot

Tôi biết những gì tôi muốn âm mưu như thế nào, nhưng tôi đã phải vật lộn để có được nó. Tôi muốn nó trông như thế này (tôi không tạo ra âm mưu này):

Logarithmic CDF Plot

Làm cho logarit trục x là đơn giản. Trục y là trục cho tôi vấn đề. Sử dụng set_yscale('log') không hoạt động vì nó muốn sử dụng quyền hạn của 10. Tôi thực sự muốn trục y có cùng một dấu ticklabels như cốt truyện này.

Làm cách nào để lấy dữ liệu của mình vào ô lôgarit như thế này?

EDIT:

Nếu tôi đặt yscale để 'đăng nhập', và ylim tới [0,1, 1], tôi nhận được cốt truyện sau:

enter image description here

Vấn đề là một điển hình lô tỷ lệ log trên một tập dữ liệu từ 0 đến 1 sẽ tập trung vào các giá trị gần bằng không. Thay vào đó, tôi muốn tập trung vào các giá trị gần với 1.

+2

Bạn đang gặp vấn đề gì với 'set_yscale ('symlog')'? – mziccard

+0

Đặt vị trí nhãn cũng là một câu chuyện hoàn toàn khác. Tôi cho rằng bạn có thể làm cho loga bậc thang trên trục y (nó hoạt động, nếu bạn có số 0 hoặc số liệu là sai) và sau đó điều chỉnh các nhãn. –

+1

Ý của bạn là gì khi bạn nói rằng trục y * * không hoạt động "*? Bạn có thể cho chúng tôi xem không? Nó không phải là toán học có thể đại diện cho 0 trên một quy mô đăng nhập, vì vậy giá trị đầu tiên sẽ phải được che giấu hoặc cắt bớt thành một số dương rất nhỏ. Bạn có thể điều khiển hành vi này bằng cách chuyển '' mask'' hoặc ''clip'' thành tham số' nonposy = 'thành' ax.set_yscale() '. –

Trả lời

14

Về cơ bản bạn cần phải áp dụng việc chuyển đổi sau đây để Y giá trị của bạn: -log10(1-y). Điều này áp đặt giới hạn duy nhất là y < 1, vì vậy bạn sẽ có thể có giá trị âm trên ô được chuyển đổi.

Dưới đây là một sửa đổi example từ matplotlib tài liệu cho thấy làm thế nào để kết hợp biến đổi tùy vào "quy mô":

import numpy as np 
from numpy import ma 
from matplotlib import scale as mscale 
from matplotlib import transforms as mtransforms 
from matplotlib.ticker import FixedFormatter, FixedLocator 


class CloseToOne(mscale.ScaleBase): 
    name = 'close_to_one' 

    def __init__(self, axis, **kwargs): 
     mscale.ScaleBase.__init__(self) 
     self.nines = kwargs.get('nines', 5) 

    def get_transform(self): 
     return self.Transform(self.nines) 

    def set_default_locators_and_formatters(self, axis): 
     axis.set_major_locator(FixedLocator(
       np.array([1-10**(-k) for k in range(1+self.nines)]))) 
     axis.set_major_formatter(FixedFormatter(
       [str(1-10**(-k)) for k in range(1+self.nines)])) 


    def limit_range_for_scale(self, vmin, vmax, minpos): 
     return vmin, min(1 - 10**(-self.nines), vmax) 

    class Transform(mtransforms.Transform): 
     input_dims = 1 
     output_dims = 1 
     is_separable = True 

     def __init__(self, nines): 
      mtransforms.Transform.__init__(self) 
      self.nines = nines 

     def transform_non_affine(self, a): 
      masked = ma.masked_where(a > 1-10**(-1-self.nines), a) 
      if masked.mask.any(): 
       return -ma.log10(1-a) 
      else: 
       return -np.log10(1-a) 

     def inverted(self): 
      return CloseToOne.InvertedTransform(self.nines) 

    class InvertedTransform(mtransforms.Transform): 
     input_dims = 1 
     output_dims = 1 
     is_separable = True 

     def __init__(self, nines): 
      mtransforms.Transform.__init__(self) 
      self.nines = nines 

     def transform_non_affine(self, a): 
      return 1. - 10**(-a) 

     def inverted(self): 
      return CloseToOne.Transform(self.nines) 

mscale.register_scale(CloseToOne) 

if __name__ == '__main__': 
    import pylab 
    pylab.figure(figsize=(20, 9)) 
    t = np.arange(-0.5, 1, 0.00001) 
    pylab.subplot(121) 
    pylab.plot(t) 
    pylab.subplot(122) 
    pylab.plot(t) 
    pylab.yscale('close_to_one') 

    pylab.grid(True) 
    pylab.show() 

normal and transformed plot

Lưu ý rằng bạn có thể kiểm soát số 9 của thông qua một đối số từ khóa:

pylab.figure() 
pylab.plot(t) 
pylab.yscale('close_to_one', nines=3) 
pylab.grid(True) 

plot with 3 nine's

+0

câu trả lời hay. Điều này thật đúng với gì mà tôi đã tìm kiếm. Tất cả mọi thứ hoạt động như mong đợi ngoại trừ một điều ... Khi tôi cố gắng sử dụng scatter() thay vì cốt truyện(), nó không hoạt động (không có gì xuất hiện). Tôi cần phải làm gì để có được scatter() để làm việc? – nic

+0

@nic Làm thế nào để bạn gọi là 'phân tán()'? Mọi thứ hoạt động tốt cho tôi nếu tôi chỉ thay thế các lệnh 'plot()' bằng: 'pylab.scatter (t, t)'. –

+0

bạn nói đúng. Tôi đã có một vấn đề ở nơi khác. Cảm ơn một lần nữa cho câu trả lời của bạn. Nó cũng có giá trị +100 – nic

1

Ok, đây không phải là mã rõ ràng nhất, nhưng tôi không thể nhìn thấy nó. Có lẽ những gì tôi thực sự yêu cầu không phải là một CDF logarit, nhưng tôi sẽ đợi một nhà thống kê cho tôi biết nếu không. Dù sao, đây là những gì tôi đã đưa ra:

# retrieve event times and latencies from the file 
times, latencies = read_in_data_from_file('myfile.csv') 
cdfx = numpy.sort(latencies) 
cdfy = numpy.linspace(1/len(latencies), 1.0, len(latencies)) 

# find the logarithmic CDF and ylabels 
logcdfy = [-math.log10(1.0 - (float(idx)/len(latencies))) 
      for idx in range(len(latencies))] 
labels = ['', '90', '99', '99.9', '99.99', '99.999', '99.9999', '99.99999'] 
labels = labels[0:math.ceil(max(logcdfy))+1] 

# plot the logarithmic CDF 
fig = plt.figure() 
axes = fig.add_subplot(1, 1, 1) 
axes.scatter(cdfx, logcdfy, s=4, linewidths=0) 
axes.set_xlim(min(latencies), max(latencies) * 1.01) 
axes.set_ylim(0, math.ceil(max(logcdfy))) 
axes.set_yticklabels(labels) 
plt.show() 

Phần lộn xộn là nơi tôi thay đổi yticklabels. Biến số logcdfy sẽ giữ giá trị trong khoảng từ 0 đến 10 và trong ví dụ của tôi là từ 0 đến 6. Trong mã này, tôi trao đổi nhãn bằng phần trăm. Chức năng plot cũng có thể được sử dụng nhưng tôi thích cách hàm scatter hiển thị các ngoại lệ ở đuôi. Ngoài ra, tôi chọn không tạo trục x trên thang đo log vì dữ liệu cụ thể của tôi có đường thẳng tốt mà không có nó.

enter image description here

+2

Bạn đang đặt nhãn, nhưng không phải là các dấu, theo cách đó số được hiển thị (nhãn) không tương ứng với giá trị của dấu tick !!! Và tại sao bạn không chỉ sử dụng tùy chọn chia tỷ lệ logarit mặc định của matplotlib? – hitzg

+0

@hitzg, tôi đồng ý với nhận xét của bạn. Nó làm phiền tôi rằng các nhãn không khớp với dữ liệu thực tế. Tôi đã cố gắng và cố gắng và cố gắng, nhưng không thể tìm ra cách để có được âm mưu để trông giống như cốt truyện tôi cần mà không có hack này. Tôi sẽ rất biết ơn nếu bạn có thể chỉ cho tôi cách làm thế nào! Tỷ lệ logarit mặc định của matplotlib không nhấn mạnh phần dữ liệu mà tôi quan tâm, đó là phần trăm đuôi. – nic

Các vấn đề liên quan