2016-08-14 4 views
2

저는 파이썬으로 새로운입니다 matplotlib 및 서브 플로트의 PdfPages를 사용하여 그림으로 PDF에 많은 양의 데이터를 저장하려고합니다. 문제는 코드가 같은 간다 내가 해결하는 방법을 잘 모릅니다 blottleneck을 발견한다는 것입니다 :파이썬은 PDF로 다중 서브 플로트 숫자를 저장합니다

import matplotlib.pyplot as plt 
from matplotlib.backends.backend_pdf import PdfPages 

with PdfPages('myfigures.pdf') as pdf: 
for i in range(1000): 
    f,axarr = plt.subplots(2, 3) 
    plt.subplots(2, 3) 
    axarr[0, 0].plot(x1, y1) 
    axarr[1, 0].plot(x2, y2) 

    pdf.savefig(f) 
    plt.close('all') 

는 매우 많은 시간이 소요 각 루프 그림을 만들기 그러나 나는 루프 외부로 각을 취소 나던 것을 넣어 경우 음모. 내가 clear() 또는 clf()와 같은 다른 옵션을 시도했거나 여러 개의 다른 인물을 만들 때 끝났습니다. 다른 방법으로이 방법을 추가하여 아이디어가 더 빨리 처리되도록하는 방법에 대한 아이디어가 있습니까?

답변

5

단일 pdf 내에 여러 페이지 출력으로 여러 개의 서브 그림을 포함하려면 가장 최근의 서브 그림 추가가 현재 페이지의 subplot-array에서 사용 가능한 공간을 모두 초과 한 것을 감지 한 후 바로 새 페이지를 작성하기 만하면됩니다 형세. 2x3이다 레이아웃

import matplotlib 
import matplotlib.pyplot as plt 
import numpy as np 
import sys 
import timeit 
from matplotlib.backends.backend_pdf import PdfPages 
matplotlib.rcParams.update({'font.size': 6}) 

# Dimensions for any n-rows x m-cols array of subplots/pg. 
n, m = 4, 5 

# Don't forget to indent after the with statement 
with PdfPages('auto_subplotting.pdf') as pdf: 

    # Let's time the execution required to create and save 
    # each full page of subplots to the pdf 
    start_time = timeit.default_timer() 

    # Before beginning the iteration through all the data, 
    # initialize the layout for the plots and create a 
    # representation of the subplots that can be easily 
    # iterated over for knowing when to create the next page 
    # (and also for custom settings like partial axes labels) 
    f, axarr = plt.subplots(n, m, sharex='col', sharey='row') 
    arr_ij = [(x,y) for x,y in np.ndindex(axarr.shape)] 
    subplots = [axarr[index] for index in arr_ij] 

    # To conserve needed plotting real estate, 
    # only label the bottom row and leftmost subplots 
    # as determined automatically using n and m 
    splot_index = 0 
    for s,splot in enumerate(subplots): 
     splot.set_ylim(0,.15) 
     splot.set_xlim(0,50) 
     last_row = (n*m-s < m+1) 
     first_in_row = (s % m == 0) 
     if last_row: 
      splot.set_xlabel("X-axis label") 
     if first_in_row: 
      splot.set_ylabel("Y-axis label") 

    # Iterate through each sample in the data 
    for sample in range(33): 

     # As a stand-in for real data, let's just make numpy take 100 random draws 
     # from a poisson distribution centered around say ~25 and then display 
     # the outcome as a histogram 
     scaled_y = np.random.randint(20,30) 
     random_data = np.random.poisson(scaled_y, 100) 
     subplots[splot_index].hist(random_data, bins=12, normed=True, 
            fc=(0,0,0,0), lw=0.75, ec='b') 

     # Keep subplotting through the samples in the data and increment 
     # a counter each time. The page will be full once the count is equal 
     # to the product of the user-set dimensions (i.e. n * m) 
     splot_index += 1 

     # We can basically repeat the same exact code block used for the 
     # first layout initialization, but with the addition of 4 new lines: 
     # 2 for saving the just-finished page to the pdf, 1 for the 
     # page's execution time, & 1 more to reset the subplot index 
     if splot_index == n*m: 
      pdf.savefig() 
      plt.close(f) 
      print(timeit.default_timer()-start_time) 
      start_time = timeit.default_timer() 
      f, axarr = plt.subplots(n, m, sharex='col', sharey='row') 
      arr_ij = [(x,y) for x,y in np.ndindex(axarr.shape)] 
      subplots = [axarr[index] for index in arr_ij] 
      splot_index = 0 
      for s,splot in enumerate(subplots): 
       splot.set_ylim(0,.15) 
       splot.set_xlim(0,50) 
       last_row = ((n*m)-s < m+1) 
       first_in_row = (s % m == 0) 
       if last_row: 
        splot.set_xlabel("X-axis label") 
       if first_in_row: 
        splot.set_ylabel("Y-axis label") 

    # Done!  
    # But don't forget the last page 
    pdf.savefig() 
    plt.close(f) 

단지 N에 대한 선언 변경 코드 블록의 시작 부분에 따라 (M) : 여기 페이지 당 줄거리의 수를 제어하는 ​​치수를 쉽게 변경할 수를 할 수있는 방법이다.

당신이 프레임을 축 두 번째 페이지에서 볼 수 있습니다 훨씬 더 컴팩트 한 레이아웃의 예를 들어, 33 개 샘플 위의 4 × 행렬은 다음과 같은 두 페이지 출력을 준위한 플롯을 만들려면 전체 레이아웃을 위해 만들어졌지만 마지막 7 개는 비어 있습니다 (4x5 x 2 = 40 - 33 = 7).

timeit의 인쇄 된 출력은 첫 번째 페이지 작성시 1.81540203094 초입니다.


참고 다중 처리 아마도 new_page 함수를 생성함으로써 간략화한다; 코드를 그대로 반복하지 않는 것이 좋습니다. 특히 사용자가 플롯을 사용자 정의하기 시작하면 모든 변경 사항을 반영하고 동일한 내용을 두 번 입력하지 않아도되는 경우가 있습니다. seaborn을 기반으로하는 더 맞춤형 미학과 아래에 표시된 것과 같은 사용 가능한 matplotlib 매개 변수를 사용하는 것도 좋습니다.

는 & 일부 사용자 정의 부가 적 줄거리 스타일에 대한 new_page 기능을 추가

from __future__ import print_function 
import matplotlib.pyplot as plt 
import numpy as np 
import random 
import seaborn as sns 
import timeit 
from matplotlib.backends.backend_pdf import PdfPages 

# this erases labels for any blank plots on the last page 
sns.set(font_scale=0.0) 
n, m = 4, 6 
datasize = 37 
ctheme = ['k', 'gray', 'magenta', 'fuchsia', '#be03fd', '#1e488f', 
      (0.44313725490196076, 0.44313725490196076, 0.88627450980392153), 
      '#75bbfd', 'teal', 'lime', 'g', (0.6666674, 0.6666663, 0.29078014184397138), 
      'y', '#f1da7a', 'tan','orange', 'maroon', 'r'] 
colors = sns.blend_palette(ctheme, datasize) 
fz = 7 # labels fontsize 

def new_page(n, m): 
    global splot_index 
    splot_index = 0 
    fig, axarr = plt.subplots(n, m, sharey='row') 
    plt.subplots_adjust(hspace=0.5, wspace=0.15) 
    arr_ij = [(x,y) for x,y in np.ndindex(axarr.shape)] 
    subplots = [axarr[index] for index in arr_ij] 
    for s,splot in enumerate(subplots): 
     splot.grid(b=True, which='major', color='gray', linestyle='-', 
        alpha=0.25, zorder=1, lw=0.5) 
     splot.set_ylim(0,.15) 
     splot.set_xlim(0,50) 
     last_row = (n*m-s < m+1) 
     first_in_row = (s % m == 0) 
     if last_row: 
      splot.set_xlabel("X-axis label", labelpad=8, fontsize=fz) 
     if first_in_row: 
      splot.set_ylabel("Y-axis label", labelpad=8, fontsize=fz) 
    return(fig, subplots) 


with PdfPages('auto_subplotting_colors.pdf') as pdf: 
    start_time = timeit.default_timer() 
    fig, subplots = new_page(n, m) 

    for sample in xrange(datasize): 
     splot = subplots[splot_index] 
     splot_index += 1 
     scaled_y = np.random.randint(20,30) 
     random_data = np.random.poisson(scaled_y, 100) 
     splot.hist(random_data, bins=12, normed=True, zorder=2, alpha=0.99, 
        fc='white', lw=0.75, ec=colors.pop()) 
     splot.set_title("Sample {}".format(sample+1), fontsize=fz) 
     # tick fontsize & spacing 
     splot.xaxis.set_tick_params(pad=4, labelsize=6) 
     splot.yaxis.set_tick_params(pad=4, labelsize=6) 

     # make new page: 
     if splot_index == n*m: 
      pdf.savefig() 
      plt.close(fig) 
      print(timeit.default_timer()-start_time) 
      start_time = timeit.default_timer() 
      fig, subplots = new_page(n, m) 

    if splot_index > 0: 
     pdf.savefig() 
     plt.close(f) 


는 첫 페이지 2.51897096634초했다이 시간 :

+0

와우, 좀 과잉 하지만 당신을 아주 많이 thak, 그것이 멋지 작품, 내가 코드에서 온다면 물어 봐도 될까요? 오메 좀 웹 페이지? 매우 흥미 롭습니다. – Victor

+0

아무런 문제가 없습니다. 철저히 조사되기를 원합니다. 실제로는 직장에서 항상 이것을 사용하여 나에게도 좋은 회상이었습니다. thx 나는 일종의 비정형 포맷을 필요로하는 dna 시퀀싱 결과를 분석하기위한 코드를 생각해 냈으며 좀 더 맞춤/덜 명백하게 기본 matplotlib 스타일로 표현 가능한 수치를 원했습니다. – johnxcollins

관련 문제