python-3.xmatplotlibpdfpages

Captions for matshow()s in multiple-page pdf


I have been around this problem for quite a long time but I'm not able to find an answer.

So, I have a list with matrices which I want to plot (for the sake of this question I'm just having 2 random matrices:

list = [np.random.random((500, 500)), np.random.random((500, 500))]

I then want to plot each element of the list using matshow in a separate page of a pdf file:

with PdfPages('file.pdf') as pdf:
    plt.rc('figure', figsize=(3,3), dpi=40)
    for elem in list:
        plt.matshow(elem, fignum=1)
        plt.title("title")
        plt.colorbar()
        plt.text(0,640,"Caption")
        pdf.savefig()  # saves the current figure into a pdf page
        plt.close()

The result is the following: enter image description here

My problem is with the caption. You can see I put "Caption" in the edge of the document on purpose. This is because sometimes the actual captions I want to insert are too big to fit in one single pdf page.

So, how can I make each pdf page adjustable to the caption's content (that might vary in each page)? For example, would it be possible to set each page size to A4 or A3, and then plot/write everything in each page?

I've already tried setting up plt.figure(figsize=(X, X)) with a variable X size, but it just changes the resolution of the pdf I guess.


Solution

  • You may want to use the bbox_inches="tight" option when saving the file. This will adapt the figure size to its content. So it then suffices to place some text at position (0,0) in figure coordinates and align it to the top. This will then extent towards the bottom and outside the figure (so the figure when shown on screen would not contain that text), but with the bbox_inches="tight" option of savefig, the saved figure will become large enough to contain that text.
    The use of the textwrap package will then also allow to limit the text in horizontal direction.

    import numpy as np; np.random.seed(1)
    import textwrap 
    import matplotlib.pyplot as plt
    from matplotlib.backends.backend_pdf import PdfPages
    
    p = np.ones(12); p[0] = 7
    text2 = "".join(np.random.choice(list(" abcdefghijk"),p=p/p.sum(), size=1000))
    text2 = textwrap.fill(text2, width=80)
    texts = ["Caption: Example", "Caption 2: " + text2 ]
    
    lis = [np.random.random((500, 500)), np.random.random((500, 500))]
    
    with PdfPages('file.pdf') as pdf:
        for elem,text in zip(lis,texts):
            fig = plt.figure(dpi=100)
    
            grid_size = (3,1)
    
            plt.imshow(elem)
            plt.title("title")
            plt.colorbar()
    
            fig.text(0,0, text, va="top")
    
            plt.tight_layout()
            pdf.savefig(bbox_inches="tight")
            plt.close()
    

    enter image description here