Creating multiple graphs per page using matplotlib

48652
2
08-20-2017 04:40 PM

Creating multiple graphs per page using matplotlib

A while ago I uploaded a document Using Python and matplotlib to create profile graphs  and recently there was a question about how to create a PDF with multiple graphs on a single page. In this case I am taking it a little step further and will create a multi page PDF file that will contain 6 graphs on each page base on a combination of suggestions made at this page: matplotlib - Python saving multiple figures into one PDF file - Stack Overflow .

This is what I came up with:

  • It will create subplots to put multiple figures on the same page and the backend_pdf to create a multi pages PDF
  • I create some random data (you will have to point to the real data is needed for the graphs). In my case I created a nested list with 5000 lists and each list contains d, z and zv as in the example
  • The function chunks will be able to divide the list in chunks, in my case chunks of 600, since I want to create 6 graphs per page and each graph contains 100 data points.
  • Each chunk of 600 items is divided in chunks of 100 items to create the graphs for each page

When using subplots, it is important to specify the correct value for rows, cols and plot number. On line 22 you can see the number "321". This represents 3 rows, 2 columns and plot number is 1 (the first one). For every chunk of 100 data points a graph is created and each graph should have its correct plot number, which is why the plot number is incremented for each chunk of 100 data points (line 42).

The chunk size "600" on line 21 in combination with the smaller chunks created on line 24 generate 6 graphs, which correspond to the value 321, where 3 * 2 + results in 6 graphs.

import matplotlib.backends.backend_pdf
import matplotlib.pyplot as plt
import random

def chunks(l, n):
    """Yield successive n-sized chunks from l."""
    for i in range(0, len(l), n):
        yield l[i:i + n]

# settings
out_pdf = r'C:\GeoNet\Profiles2PDF\test3.pdf'

# some random data
data = []
for i in range(0, 5000):
    data.append([i, float(i + random.randrange(-50, 50))/100, 5])

pdf = matplotlib.backends.backend_pdf.PdfPages(out_pdf)
cnt = 0
figs = plt.figure()
for data_chunk in chunks(data, 600):
    plot_num = 321
    fig = plt.figure(figsize=(10, 10)) # inches
    for sub_chunk in chunks(data_chunk, 100):
        cnt += 1
        d = [a[0] for a in sub_chunk]
        z = [a[1] for a in sub_chunk]
        zv = [a[2] for a in sub_chunk]

        print plot_num
        plt.subplot(plot_num)
        # plot profile, define styles
        plt.plot(d,z,'r',linewidth=0.75)
        plt.plot(d,z,'ro',alpha=0.3, markersize=3)
        plt.plot(d,zv,'k--',linewidth=0.5)
        plt.xlabel('Distance from start')
        plt.ylabel('Elevation')
        plt.title('Profile {0} using Python matplotlib'.format(cnt))

        # change font size
        plt.rcParams.update({'font.size': 8})
        plot_num += 1

    pdf.savefig(fig)

pdf.close()

See below an extract from the resulting PDF file:

In case you want to implement this for elevation data and chunks of 100 meter from a line, you can use Polyline::segmentAlongLine to get the chunks for each graph and Polyline::positionAlongLine to get each individual point on each segment.

Comments

Very helpfull, thanks!

Hi! Unfortunately is the code only available as one line of code. I would really like to try out your code. What should one give in the function for l and n?

Version history
Last update:
‎12-12-2021 03:44 AM
Updated by: