Lưu số liệu Matplotlib tương tác


119

Có cách nào để lưu một hình Matplotlib để nó có thể được mở lại và khôi phục tương tác điển hình không? (Giống như định dạng .fig trong MATLAB?)

Tôi thấy mình chạy các tập lệnh giống nhau nhiều lần để tạo ra những số liệu tương tác này. Hoặc tôi đang gửi cho đồng nghiệp của mình nhiều tệp PNG tĩnh để hiển thị các khía cạnh khác nhau của một âm mưu. Tôi muốn gửi đối tượng figure và để chúng tự tương tác với nó.

Câu trả lời:


30

Đây sẽ là một tính năng tuyệt vời, nhưng AFAIK nó không được triển khai trong Matplotlib và có thể sẽ khó tự thực hiện do cách lưu trữ số liệu.

Tôi khuyên bạn nên (a) xử lý riêng dữ liệu khỏi việc tạo hình (lưu dữ liệu với một tên duy nhất) và viết tập lệnh tạo hình (tải một tệp cụ thể của dữ liệu đã lưu) và chỉnh sửa khi bạn thấy phù hợp hoặc (b ) lưu dưới định dạng PDF / SVG / PostScript và chỉnh sửa trong một số trình chỉnh sửa hình ưa thích như Adobe Illustrator (hoặc Inkscape ).

CHỈNH SỬA bài đăng Mùa thu 2012 : Như những người khác đã chỉ ra bên dưới (mặc dù đề cập ở đây vì đây là câu trả lời được chấp nhận), Matplotlib kể từ phiên bản 1.2 cho phép bạn chọn các số liệu. Như ghi chú phát hành trạng thái , đây là một tính năng thử nghiệm và không hỗ trợ lưu hình trong một phiên bản matplotlib và mở trong một phiên bản khác. Nói chung cũng không an toàn khi khôi phục lại dây dưa từ một nguồn không đáng tin cậy.

Đối với việc chia sẻ / chỉnh sửa lô sau (yêu cầu xử lý dữ liệu quan trọng trước và có thể cần được điều chỉnh vài tháng sau, nói trong quá trình đánh giá đồng cấp cho một ấn phẩm khoa học), tôi vẫn khuyên quy trình làm việc của (1) có một tập lệnh xử lý dữ liệu trước khi tạo ra một âm mưu lưu dữ liệu đã xử lý (đi vào cốt truyện của bạn) vào một tệp và (2) có một tập lệnh tạo cốt truyện riêng biệt (bạn điều chỉnh khi cần thiết) để tạo lại cốt truyện. Bằng cách này đối với mỗi cốt truyện, bạn có thể nhanh chóng chạy một tập lệnh và tạo lại nó (và nhanh chóng sao chép cài đặt cốt truyện của bạn với dữ liệu mới). Điều đó nói rằng, việc chọn một con số có thể thuận tiện cho việc phân tích dữ liệu ngắn hạn / tương tác / khám phá.


2
Hơi ngạc nhiên là điều này không được triển khai .. Nhưng được rồi, tôi sẽ lưu dữ liệu đã xử lý vào một tệp trung gian và gửi tệp đó và tập lệnh để lập mưu cho đồng nghiệp. Cảm ơn.
Matt

2
Tôi nghi ngờ việc triển khai là khó, đó là lý do tại sao nó hoạt động rất kém một MATLAB. Quay lại khi tôi sử dụng nó, các số liệu được sử dụng để làm hỏng MATLAB và thậm chí các phiên bản hơi khác nhau không thể đọc các tệp .fig khác.
Adrian Ratnapala

6
picklehiện hoạt động trên các hình MPL, vì vậy điều này có thể được thực hiện và có vẻ hoạt động hợp lý - gần giống như tệp hình Matlab ".fig". Xem câu trả lời của tôi bên dưới (bây giờ?) Để biết ví dụ về cách thực hiện.
Demis

@Demis: như ptomato đã chỉ ra trong câu trả lời của anh ấy bên dưới, nó đã tồn tại vào thời điểm đó.
strpeter

@strpeter - Số liệu của Matlab không thể thu thập được trong năm 2010 như được chỉ ra trong nhận xét này . Tính năng thử nghiệm đã được thêm vào với matplotlib 1.2 được phát hành vào mùa thu năm 2012 . Như đã lưu ý ở đó, bạn không nên mong đợi nó hoạt động giữa các phiên bản matplotlib và bạn không nên mở dưa chua đến từ một nguồn không đáng tin cậy.
dr jimbob

63

Tôi chỉ tìm ra cách để làm điều này. "Hỗ trợ dưa chua thử nghiệm" mà @pelson đề cập hoạt động khá tốt.

Thử cái này:

# Plot something
import matplotlib.pyplot as plt
fig,ax = plt.subplots()
ax.plot([1,2,3],[10,-10,30])

Sau khi điều chỉnh tương tác của bạn, hãy lưu đối tượng figure dưới dạng tệp nhị phân:

import pickle
pickle.dump(fig, open('FigureObject.fig.pickle', 'wb')) # This is for Python 3 - py2 may need `file` instead of `open`

Sau đó, hãy mở hình và các chỉnh sửa sẽ được lưu và tương tác GUI sẽ xuất hiện:

import pickle
figx = pickle.load(open('FigureObject.fig.pickle', 'rb'))

figx.show() # Show the figure, edit it, etc.!

Bạn thậm chí có thể trích xuất dữ liệu từ các ô:

data = figx.axes[0].lines[0].get_data()

(Nó hoạt động cho dòng, pcolor & imshow - pcolormesh hoạt động với một số thủ thuật để tái tạo lại dữ liệu đã làm phẳng .)

Tôi đã nhận được mẹo tuyệt vời từ Lưu số liệu Matplotlib bằng Pickle .


Tôi tin rằng điều này không hiệu quả với các thay đổi phiên bản, v.v. và không tương thích chéo giữa py2.x & py3.x. Ngoài ra, tôi nghĩ rằng pickletài liệu nói rằng chúng ta cần thiết lập môi trường tương tự như khi đối tượng được chọn (lưu), nhưng tôi thấy bạn không cần phải làm như vậy import matplotlib.pyplot as pltkhi giải nén (tải) - nó lưu các câu lệnh nhập trong tệp đã chọn .
Demis

5
Bạn nên xem xét việc đóng các tệp đã mở: ví dụwith open('FigureObject.fig.pickle', 'rb') as file: figx = pickle.load(file)
strpeter

1
Tôi chỉ nhận được: 'AttributeError: 'Hình' đối tượng không có thuộc tính '_cachedRenderer''
user2673238

Nếu bạn không muốn tập lệnh tiếp tục và có thể kết thúc ngay sau đó figx.show(), bạn nên gọi plt.show()thay vào đó, lệnh này đang chặn.
maechler

38

Tính đến Matplotlib 1.2, bây giờ chúng tôi có thử nghiệm dưa hỗ trợ. Hãy thử và xem liệu nó có hoạt động tốt cho trường hợp của bạn không. Nếu bạn có bất kỳ vấn đề nào, vui lòng cho chúng tôi biết trong danh sách gửi thư Matplotlib hoặc bằng cách mở một vấn đề trên github.com/matplotlib/matplotlib .


2
Bất kỳ lý do gì mà tính năng hữu ích này có thể được thêm vào chính "Lưu dưới dạng" của figure. Có lẽ đang thêm .pkl?
thoáng qua

Ý kiến ​​hay @dashy. Tôi sẽ ủng hộ điều đó nếu bạn muốn triển khai nó?
pelson

1
Điều này chỉ hoạt động trên một tập hợp con các phụ trợ? Khi tôi cố gắng chọn một con số đơn giản trong OSX, tôi nhận được PicklingError: Can't pickle <type '_macosx.GraphicsContext'>: it's not found as _macosx.GraphicsContext.
chu kỳ

Điều trên PicklingErrorchỉ xảy ra nếu bạn gọi plt.show()trước khi làm dưa muối. Vì vậy, chỉ cần đặt plt.show()sau pickle.dump().
salomonvh

Trên py3.5 của tôi trên MacOS 10.11, thứ tự fig.show()dường như không quan trọng - có thể lỗi đó đã được sửa. Tôi có thể ngâm trước / sau show()mà không có vấn đề gì.
Demis

7

Tại sao không chỉ gửi tập lệnh Python? Các tệp .fig của MATLAB yêu cầu người nhận phải có MATLAB để hiển thị chúng, vì vậy điều đó tương đương với việc gửi một tập lệnh Python yêu cầu Matplotlib hiển thị.

Ngoài ra (tuyên bố từ chối trách nhiệm: Tôi chưa thử cái này), bạn có thể thử chọn con số:

import pickle
output = open('interactive figure.pickle', 'wb')
pickle.dump(gcf(), output)
output.close()

3
Thật không may, số liệu matplotlib không thể chọn được, vì vậy cách tiếp cận đó sẽ không hiệu quả. Đằng sau hậu trường, có quá nhiều phần mở rộng C không hỗ trợ quá trình gắp. Tôi hoàn toàn đồng ý về việc chỉ gửi tập lệnh + dữ liệu, mặc dù ... Tôi đoán tôi chưa bao giờ thực sự thấy điểm .fig's được lưu của matlab, vì vậy tôi chưa bao giờ sử dụng chúng. Theo kinh nghiệm của tôi, gửi cho ai đó mã và dữ liệu độc lập về lâu dài là điều dễ dàng nhất. Tuy nhiên, sẽ rất tốt nếu figure của matplotlib đối tượng ở nơi có thể nhặt được.
Joe Kington

1
Ngay cả dữ liệu được xử lý trước của chúng tôi cũng hơi lớn và quy trình vẽ biểu đồ phức tạp. Có vẻ như đây là cách duy nhất. cảm ơn.
Matt

1
Các số liệu hiện nay rõ ràng là có thể chọn được - nó hoạt động khá tốt! Ví dụ bên dưới.
Demis

Lợi ích của pickle là bạn không phải điều chỉnh theo chương trình tất cả các khoảng cách / vị trí của figure / subplot. Bạn có thể sử dụng GUI của cốt truyện MPL để làm cho hình vẽ trông đẹp mắt, v.v., sau đó lưu MyPlot.fig.pickletệp - giữ lại khả năng sau này để điều chỉnh cách trình bày cốt truyện nếu cần. Đây cũng là điều tuyệt vời về .figcác tệp của Matlab . Đặc biệt hữu ích khi bạn cần thay đổi kích thước / tỷ lệ co của hình (để chèn vào bản trình bày / giấy tờ).
Demis

1

Câu hỏi hay. Đây là văn bản tài liệu từ pylab.save:

pylab không còn cung cấp chức năng lưu, mặc dù chức năng pylab cũ vẫn có sẵn dưới dạng matplotlib.mlab.save (bạn vẫn có thể gọi nó trong pylab là "mlab.save"). Tuy nhiên, đối với các tệp văn bản thuần túy, chúng tôi khuyên bạn nên dùng numpy.savetxt. Để lưu mảng numpy, chúng tôi đề xuất numpy.save và numpy.load tương tự của nó, có sẵn trong pylab dưới dạng np.save và np.load.


Thao tác này lưu dữ liệu từ đối tượng pylab, nhưng không cho phép bạn tạo lại hình.
dr jimbob

Chính xác. Tôi phải làm rõ rằng câu trả lời không phải là một khuyến nghị để sử dụng pylab.save. Trên thực tế, từ văn bản doc, có vẻ như người ta không nên sử dụng nó.
Steve Tjoa

Có phương pháp bên ngoài nào để gửi Hình 3D không? Thậm chí có thể có một GUI đơn giản để exe ..
CromeX

0

Tôi đã tìm ra một cách tương đối đơn giản (nhưng hơi khác thường) để lưu các số liệu matplotlib của mình. Nó hoạt động như thế này:

import libscript

import matplotlib.pyplot as plt
import numpy as np

t = np.arange(0.0, 2.0, 0.01)
s = 1 + np.sin(2*np.pi*t)

#<plot>
plt.plot(t, s)
plt.xlabel('time (s)')
plt.ylabel('voltage (mV)')
plt.title('About as simple as it gets, folks')
plt.grid(True)
plt.show()
#</plot>

save_plot(fileName='plot_01.py',obj=sys.argv[0],sel='plot',ctx=libscript.get_ctx(ctx_global=globals(),ctx_local=locals()))

với chức năng save_plotđược định nghĩa như thế này (phiên bản đơn giản để hiểu logic):

def save_plot(fileName='',obj=None,sel='',ctx={}):
    """
    Save of matplolib plot to a stand alone python script containing all the data and configuration instructions to regenerate the interactive matplotlib figure.

    Parameters
    ----------
    fileName : [string] Path of the python script file to be created.
    obj : [object] Function or python object containing the lines of code to create and configure the plot to be saved.
    sel : [string] Name of the tag enclosing the lines of code to create and configure the plot to be saved.
    ctx : [dict] Dictionary containing the execution context. Values for variables not defined in the lines of code for the plot will be fetched from the context.

    Returns
    -------
    Return ``'done'`` once the plot has been saved to a python script file. This file contains all the input data and configuration to re-create the original interactive matplotlib figure.
    """
    import os
    import libscript

    N_indent=4

    src=libscript.get_src(obj=obj,sel=sel)
    src=libscript.prepend_ctx(src=src,ctx=ctx,debug=False)
    src='\n'.join([' '*N_indent+line for line in src.split('\n')])

    if(os.path.isfile(fileName)): os.remove(fileName)
    with open(fileName,'w') as f:
        f.write('import sys\n')
        f.write('sys.dont_write_bytecode=True\n')
        f.write('def main():\n')
        f.write(src+'\n')

        f.write('if(__name__=="__main__"):\n')
        f.write(' '*N_indent+'main()\n')

return 'done'

hoặc xác định chức năng save_plotnhư thế này (phiên bản tốt hơn sử dụng nén zip để tạo ra các tệp hình nhẹ hơn):

def save_plot(fileName='',obj=None,sel='',ctx={}):

    import os
    import json
    import zlib
    import base64
    import libscript

    N_indent=4
    level=9#0 to 9, default: 6
    src=libscript.get_src(obj=obj,sel=sel)
    obj=libscript.load_obj(src=src,ctx=ctx,debug=False)
    bin=base64.b64encode(zlib.compress(json.dumps(obj),level))

    if(os.path.isfile(fileName)): os.remove(fileName)
    with open(fileName,'w') as f:
        f.write('import sys\n')
        f.write('sys.dont_write_bytecode=True\n')
        f.write('def main():\n')
        f.write(' '*N_indent+'import base64\n')
        f.write(' '*N_indent+'import zlib\n')
        f.write(' '*N_indent+'import json\n')
        f.write(' '*N_indent+'import libscript\n')
        f.write(' '*N_indent+'bin="'+str(bin)+'"\n')
        f.write(' '*N_indent+'obj=json.loads(zlib.decompress(base64.b64decode(bin)))\n')
        f.write(' '*N_indent+'libscript.exec_obj(obj=obj,tempfile=False)\n')

        f.write('if(__name__=="__main__"):\n')
        f.write(' '*N_indent+'main()\n')

return 'done'

Điều này làm cho việc sử dụng một mô-đun libscriptcủa riêng tôi, chủ yếu dựa vào các mô-đun inspectast. Tôi có thể cố gắng chia sẻ nó trên Github nếu sự quan tâm được bày tỏ (trước tiên nó sẽ yêu cầu một số dọn dẹp và tôi bắt đầu với Github).

Ý tưởng đằng sau save_plotchức năng và libscriptmô-đun này là tìm nạp các hướng dẫn python tạo hình (sử dụng mô-đun inspect), phân tích chúng (sử dụng mô-đun ast) để trích xuất tất cả các biến, chức năng và mô-đun nhập nó dựa vào, trích xuất chúng từ ngữ cảnh thực thi và tuần tự hóa chúng như hướng dẫn python (mã cho các biến sẽ giống như t=[0.0,2.0,0.01]... và mã cho các mô-đun sẽ giống nhưimport matplotlib.pyplot as plt ...) được thêm vào trước các hướng dẫn hình. Các hướng dẫn python kết quả được lưu dưới dạng tập lệnh python mà việc thực thi sẽ xây dựng lại hình matplotlib ban đầu.

Như bạn có thể tưởng tượng, điều này hoạt động tốt cho hầu hết (nếu không phải tất cả) số liệu matplotlib.

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.