Plot a live index graph using matplotlib - python - python-2.7
I'm trying to plot a lines graph using matplotlib - python.
The graph should look like below image:
I used patches.PathPatch to graph the image above, with specific vertices and codes, but I'm facing some technical issues when trying to plot live data above what the desired graph. For each reading, the graph gets regenerated (I get total of 8 figures for 8 unique readings). How do I stop this from happening? I just need the image above to be my background graph (as index graph), and live data to be plotted above that graph.... Also, any way to simplify below code? Any help would be greatly appreciated
import matplotlib.pyplot as plt
from matplotlib.path import Path
import matplotlib.patches as patches
import serial # import Serial Library
import numpy # Import numpy
from drawnow import *
tempF= []
pressure=[]
arduinoData = serial.Serial('/dev/cu.AdafruitEZ-Link64b9-SPP', 9600) #Creating our serial object named arduinoData
plt.ion() #Tell matplotlib you want interactive mode to plot live data
cnt=0
fig = plt.figure()
ax = fig.add_subplot(111)
def makeFig(): #Create a function that makes our desired plot
codes = [Path.MOVETO,
Path.LINETO,
Path.LINETO,
Path.LINETO,
Path.CLOSEPOLY,
Path.MOVETO,
Path.LINETO,
Path.LINETO,
Path.LINETO,
Path.CLOSEPOLY,
Path.MOVETO,
Path.LINETO,
Path.LINETO,
Path.LINETO,
Path.CLOSEPOLY,
Path.MOVETO,
Path.LINETO,
Path.LINETO,
Path.LINETO,
Path.CLOSEPOLY,
Path.MOVETO,
Path.LINETO,
Path.LINETO,
Path.LINETO,
Path.CLOSEPOLY,
Path.MOVETO,
Path.LINETO,
Path.LINETO,
Path.LINETO,
Path.CLOSEPOLY,
Path.MOVETO,
Path.LINETO,
Path.LINETO,
Path.LINETO,
Path.CLOSEPOLY,
]
verts1 = [
(0, 0), # left, bottom
(0, 23), # left, top
(1, 18), # right, top
(1, 0), # right, bottom
(0, 0), # ignored
(1, 0), # left, bottom
(1, 18), # left, top
(2, 16), # right, top
(2, 0), # right, bottom
(1, 0), # ignored
(2, 0), # left, bottom
(2, 16), # left, top
(3, 15), # right, top
(3, 0), # right, bottom
(2, 0), # ignored
(3, 0), # left, bottom
(3, 15), # left, top
(4, 14), # right, top
(4, 0), # right, bottom
(3, 0), # ignored
(4, 0), # left, bottom
(4, 14), # left, top
(5, 13), # right, top
(5, 0), # right, bottom
(4, 0), # ignored
(5, 0), # left, bottom
(5, 13), # left, top
(6, 12), # right, top
(6, 0), # right, bottom
(5, 0), # ignored
(6, 0), # left, bottom
(6, 12), # left, top
(7, 10), # right, top
(7, 0), # right, bottom
(6, 0), # ignored
]
verts2 = [
(0, 23), # left, bottom
(0, 45), # left, top
(1, 39), # right, top
(1, 18), # right, bottom
(0, 23), # ignored
(1, 18), # left, bottom
(1, 39), # left, top
(2, 38), # right, top
(2, 16), # right, bottom
(1, 18), # ignored
(2, 16), # left, bottom
(2, 38), # left, top
(3, 34), # right, top
(3, 15), # right, bottom
(2, 16), # ignored
(3, 15), # left, bottom
(3, 34), # left, top
(4, 30), # right, top
(4, 14), # right, bottom
(3, 15), # ignored
(4, 14), # left, bottom
(4, 30), # left, top
(5, 23), # right, top
(5, 13), # right, bottom
(4, 14), # ignored
(5, 13), # left, bottom
(5, 23), # left, top
(6, 19), # right, top
(6, 12), # right, bottom
(5, 13), # ignored
(6, 12), # left, bottom
(6, 19), # left, top
(7, 16), # right, top
(7, 10), # right, bottom
(6, 12), # ignored
]
verts3 = [
(0, 45), # left, bottom
(0, 50), # left, top
(1, 50), # right, top
(1, 39), # right, bottom
(0, 45), # ignored
(1, 39), # left, bottom
(1, 50), # left, top
(2, 50), # right, top
(2, 38), # right, bottom
(1, 39), # ignored
(2, 38), # left, bottom
(2, 50), # left, top
(3, 50), # right, top
(3, 34), # right, bottom
(2, 38), # ignored
(3, 34), # left, bottom
(3, 50), # left, top
(4, 46), # right, top
(4, 30), # right, bottom
(3, 34), # ignored
(4, 30), # left, bottom
(4, 46), # left, top
(5, 32), # right, top
(5, 23), # right, bottom
(4, 30), # ignored
(5, 23), # left, bottom
(5, 32), # left, top
(6, 28), # right, top
(6, 19), # right, bottom
(5, 23), # ignored
(6, 19), # left, bottom
(6, 28), # left, top
(7, 24), # right, top
(7, 16), # right, bottom
(6, 19), # ignored
]
verts4 = [
(0, 50), # left, bottom
(0, 60), # left, top
(1, 60), # right, top
(1, 50), # right, bottom
(0, 50), # ignored
(1, 50), # left, bottom
(1, 60), # left, top
(2, 60), # right, top
(2, 50), # right, bottom
(1, 50), # ignored
(2, 50), # left, bottom
(2, 60), # left, top
(3, 60), # right, top
(3, 50), # right, bottom
(2, 50), # ignored
(3, 50), # left, bottom
(3, 60), # left, top
(4, 60), # right, top
(4, 46), # right, bottom
(3, 50), # ignored
(4, 46), # left, bottom
(4, 60), # left, top
(5, 60), # right, top
(5, 32), # right, bottom
(4, 46), # ignored
(5, 32), # left, bottom
(5, 60), # left, top
(6, 60), # right, top
(6, 28), # right, bottom
(5, 32), # ignored
(6, 28), # left, bottom
(6, 60), # left, top
(7, 60), # right, top
(7, 24), # right, bottom
(6, 19), # ignored
]
path = Path(verts1, codes)
path2 = Path(verts2, codes)
path3 = Path(verts3, codes)
path4 = Path(verts4, codes)
patch = patches.PathPatch(path, facecolor='green', alpha=0.8)
patch2 = patches.PathPatch(path2, facecolor='orange', alpha=0.8)
patch3 = patches.PathPatch(path3, facecolor='red', alpha=0.8)
patch4 = patches.PathPatch(path4, facecolor='purple', alpha=0.8)
#ax.axhline(5, linestyle='--', color='k') # horizontal lines
#ax.axvline(0, linestyle='--', color='k') # vertical lines
ax.add_patch(patch)
ax.add_patch(patch2)
ax.add_patch(patch3)
ax.add_patch(patch4)
ax.set_xlim(0,7)
ax.set_ylim(0,60)
plt.grid()
plt.show()
plt.plot(tempF, 'ro-', label='sensor 1') #plot the temperature
plt.legend(loc='upper left') #plot the legend
plt.plot(pressure, 'bo-', label='sensor 2') #plot the temperature
plt.legend(loc='upper left')
while True: # While loop that loops forever
while (arduinoData.inWaiting()==0): #Wait here until there is data
pass #do nothing
arduinoString = arduinoData.readline() #read the line of text from the serial port
dataArray = arduinoString.split(',') #Split it into an array called dataArray
print dataArray[0]
print dataArray[1]
temp = float( dataArray[0]) #Convert first element to floating number and put in temp
P = float( dataArray[1]) #Convert second element to floating number and put in P
tempF.append(temp) #Build our tempF array by appending temp readings
pressure.append(P) #Building our pressure array by appending P readings
drawnow(makeFig) #Call drawnow to update our live graph
plt.pause(.000001) #Pause Briefly. Important to keep drawnow from crashing
cnt=cnt+1
if(cnt>150): #If you have 50 or more points, delete the first one from the array
tempF.pop(0) #This allows us to just see the last 50 data points
pressure.pop(0)
Using how your input is currently styled:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)
path1 = pd.DataFrame([(0,0),(0,23),(1,18),(1,0),(0,0),(1,0),(1,18),(2,16),(2,0),(1,0),(2,0),(2,16),(3,15),(3,0),(2,0),(3,0),(3,15),(4,14),(4,0),(3,0),(4,0),(4,14),(5,13),(5,0),(4,0),(5,0),(5,13),(6,12),(6,0),(5,0),(6,0),(6,12),(7,10),(7,0),(6,0),])
path2 = pd.DataFrame([(0,23),(0,45),(1,39),(1,18),(0,23),(1,18),(1,39),(2,38),(2,16),(1,18),(2,16),(2,38),(3,34),(3,15),(2,16),(3,15),(3,34),(4,30),(4,14),(3,15),(4,14),(4,30),(5,23),(5,13),(4,14),(5,13),(5,23),(6,19),(6,12),(5,13),(6,12),(6,19),(7,16),(7,10),(6,12),])
path3 = pd.DataFrame([(0,45),(0,50),(1,50),(1,39),(0,45),(1,39),(1,50),(2,50),(2,38),(1,39),(2,38),(2,50),(3,50),(3,34),(2,38),(3,34),(3,50),(4,46),(4,30),(3,34),(4,30),(4,46),(5,32),(5,23),(4,30),(5,23),(5,32),(6,28),(6,19),(5,23),(6,19),(6,28),(7,24),(7,16),(6,19),])
path4 = pd.DataFrame([(0,50),(0,60),(1,60),(1,50),(0,50),(1,50),(1,60),(2,60),(2,50),(1,50),(2,50),(2,60),(3,60),(3,50),(2,50),(3,50),(3,60),(4,60),(4,46),(3,50),(4,46),(4,60),(5,60),(5,32),(4,46),(5,32),(5,60),(6,60),(6,28),(5,32),(6,28),(6,60),(7,60),(7,24),(6,19),])
p1y = list(path1[1][1::5])
p1y.append(path1[1][32])
p2y = list(path2[1][1::5])
p2y.append(path2[1][32])
p3y = list(path3[1][1::5])
p3y.append(path3[1][32])
p4y = list(path4[1][1::5])
p4y.append(path4[1][32])
xline = np.array(range(len(p1y)))
ax.fill_between(xline, np.zeros(len(p1y)), p1y, facecolor='green', alpha=0.8)
ax.fill_between(xline, p1y, p2y, facecolor='orange', alpha=0.8)
ax.fill_between(xline, p2y, p3y, facecolor='red', alpha=0.8)
ax.fill_between(xline, p3y, p4y, facecolor='purple', alpha=0.8)
ax.set_xlim(0,7)
ax.set_ylim(0,60)
plt.grid()
plt.show()
However, if you can simplify your incoming verts data:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)
path1 = [23, 18, 16, 15, 14, 13, 12, 10]
path2 = [45, 39, 38, 34, 30, 23, 19, 16]
path3 = [50, 50, 50, 50, 46, 32, 28, 24]
path4 = [60, 60, 60, 60, 60, 60, 60, 60]
xline = np.array(range(len(path1)))
ax.fill_between(xline, np.zeros(len(path1)), path1, facecolor='green', alpha=0.8)
ax.fill_between(xline, path1, path2, facecolor='orange', alpha=0.8)
ax.fill_between(xline, path2, path3, facecolor='red', alpha=0.8)
ax.fill_between(xline, path3, path4, facecolor='purple', alpha=0.8)
ax.set_xlim(0,7)
ax.set_ylim(0,60)
plt.grid()
plt.show()
A note of difference, you are using Python 2.6 and this was done using Python 3.6.0 and Matplotlib 2.0.0
Related
Change 5th number from list
I have a one function for my calendar def formatweek(self, theweek, events): week = '' for d, weekday in theweek: #return f'<tr style="color:blue";> {week} </tr>' week += self.formatday(d, events) return f'<tr> {week} </tr>' def formatday(self, day, events): events_per_day = events.filter(start_time__day=day) d = '' for event in events_per_day: d += f'<li> {event.get_html_url} </li>' if day != 0: return f"<td><span class='date'>{day}</span><ul> {d} </ul></td>" return '<td></td>' where theweek is a list of pairs: [(1, 0), (2, 1), (3, 2), (4, 3), (5, 4), (6, 5), (7, 6)] [(8, 0), (9, 1), (10, 2), (11, 3), (12, 4), (13, 5), (14, 6)] [(15, 0), (16, 1), (17, 2), (18, 3), (19, 4), (20, 5), (21, 6)] [(22, 0), (23, 1), (24, 2), (25, 3), (26, 4), (27, 5), (28, 6)] [(29, 0), (30, 1), (31, 2), (0, 3), (0, 4), (0, 5), (0, 6)] Where the first number(for example(1)) in pairs is day in month (1.januar) and the second is a number for weekday name (0-Monday, 1-Thuesday etc...) d and weekday become an int in loop. d = days of month (1,2,3,4....)and Weekday = number for days (Mon - 0, Tue - 1 etc...). It returns this return f'<tr> {week} </tr>'for the table. And I would like to make it return for 5th and 6th weekday numbers (Saturday, Sunday) additionally f'<tr style="color:blue";> {5 (or 6)} </tr>'. So the simple say: I would like to make a weekend days to become blue.
Only last subplot shows (others are blank) and it is the wrong plot
I'm having trouble setting up subplots in matplotlib. Below is a screenshot of the layout I am trying to achieve. I've only gone up through ax4, as I have encountered two issues. Code is also below. (Note that on their own, the functions plot as expected.) I want to continue using "subplot2grid" instead of the other options, and I'm using Python 2.7 Expected behavior: Plots ax1, ax2, and ax3 should be a World Shade Relief Map, with position as shown in desired layout below. Plot ax4 should be a scatter plot, with position as shown in desired layout below. Actual behavior: Plots ax1, ax2, and ax3 are all blank Plot ax4 is not a scatter, but it's actually the map; layout is also wrong. I thought I was missing a "hold on" type feature, but it looks like that's not how matplotlib works. I also made sure I defined the plot limits in myplotA function. import matplotlib.pyplot as plt from matplotlib.ticker import ScalarFormatter from mpl_toolkits.basemap import Basemap from random import randint def myplotA(plotnum, title): south = 34.0129656032 north = 34.721878622 west = -116.7615176 east = -116.336918412 center = [(east + west) / 2, (north + south) / 2] m = Basemap(llcrnrlon=west, llcrnrlat=south, urcrnrlon=east, urcrnrlat=north, resolution='c', epsg=4326, lon_0=center[0], lat_0=center[1], suppress_ticks=False) img = m.arcgisimage(service="World_Shaded_Relief", xpixels=2000) img.set_alpha(0.5) plt.xticks(rotation='horizontal') plotnum.xaxis.set_major_formatter(ScalarFormatter(useOffset=False)) plotnum.axis([west, east, south, north]) for label in (plotnum.get_xticklabels() + plotnum.get_yticklabels()):label.set_fontsize(9) plt.gca().set_title(title, fontsize=12) def myplotB(plotnum, title): x = [randint(0, 10) for i in range(0, 6)] y = [randint(0, 10) for i in range(0, 6)] plotnum.scatter(x, y, s=4) plotnum.xaxis.set_major_formatter(ScalarFormatter(useOffset=False)) plt.xlabel('xlabel', fontsize=8) plt.ylabel('ylabel', fontsize=8) plt.gca().set_title(title, fontsize=12) fig = plt.figure(figsize=(11, 17)) ax1 = plt.subplot2grid((8, 3), (0, 0), rowspan=4, colspan=1) ax2 = plt.subplot2grid((8, 3), (0, 1), rowspan=4, colspan=1) ax3 = plt.subplot2grid((8, 3), (0, 2), rowspan=4, colspan=1) ax4 = plt.subplot2grid((8, 3), (5, 0), rowspan=1, colspan=2) myplotA(ax1, 'ax1') myplotA(ax2, 'ax2') myplotA(ax3, 'ax3') myplotB(ax4, 'ax4') plt.subplots_adjust(left=0.1, bottom=0.1, right=0.9, top=0.9, wspace=.1, hspace=.1) fig.savefig(outpath + '\\' + 'mytest.pdf') Desired Layout Desired Layout Image Actual Result Actual Result Image
You pass the axes to the plotting functions, but inside of those you need to actually use those passed axes. Else all the plt commands will apply to the currently active axes, which is the last one you create. import matplotlib.pyplot as plt from matplotlib.ticker import ScalarFormatter from mpl_toolkits.basemap import Basemap from random import randint def myplotA(ax, title): south = 34.0129656032 north = 34.721878622 west = -116.7615176 east = -116.336918412 center = [(east + west) / 2, (north + south) / 2] m = Basemap(llcrnrlon=west, llcrnrlat=south, urcrnrlon=east, urcrnrlat=north, resolution='c', epsg=4326, lon_0=center[0], lat_0=center[1], suppress_ticks=False, ax=ax) img = m.arcgisimage(service="World_Shaded_Relief", xpixels=2000) img.set_alpha(0.5) plt.setp(ax.get_xticklabels(), rotation='horizontal') plt.setp(ax.get_xticklabels() + ax.get_yticklabels(), fontsize=9) ax.xaxis.set_major_formatter(ScalarFormatter(useOffset=False)) ax.axis([west, east, south, north]) ax.set_title(title, fontsize=12) def myplotB(ax, title): x = [randint(0, 10) for i in range(0, 6)] y = [randint(0, 10) for i in range(0, 6)] ax.scatter(x, y, s=4) ax.xaxis.set_major_formatter(ScalarFormatter(useOffset=False)) ax.set_xlabel('xlabel', fontsize=8) ax.set_ylabel('ylabel', fontsize=8) ax.set_title(title, fontsize=12) fig = plt.figure(figsize=(11, 8)) ax1 = plt.subplot2grid((8, 3), (0, 0), rowspan=4, colspan=1) ax2 = plt.subplot2grid((8, 3), (0, 1), rowspan=4, colspan=1) ax3 = plt.subplot2grid((8, 3), (0, 2), rowspan=4, colspan=1) ax4 = plt.subplot2grid((8, 3), (5, 0), rowspan=1, colspan=2) myplotA(ax1, 'ax1') myplotA(ax2, 'ax2') myplotA(ax3, 'ax3') myplotB(ax4, 'ax4') plt.subplots_adjust(left=0.1, bottom=0.1, right=0.9, top=0.9, wspace=.1, hspace=.1) fig.savefig('mytest.pdf') plt.show()
Thanks #ImportanceOfBeingErnest I tried your code above, but still same plot as shown in the "actual results" part of the OP. However, your words describe the problem: I'm activating the axis, and then activating the next one before plotting. Below does the trick--perhaps this is what you had anyhow and just mistakenly copy/pasted the original code. Thanks for point me in the right direction. fig = plt.figure(figsize=(11, 17)) ax1 = plt.subplot2grid((8, 3), (0, 0), rowspan=4, colspan=1) myplotA(ax1, 'ax1') ax2 = plt.subplot2grid((8, 3), (0, 1), rowspan=4, colspan=1) myplotA(ax2, 'ax2') ax3 = plt.subplot2grid((8, 3), (0, 2), rowspan=4, colspan=1) myplotA(ax3, 'ax3') ax4 = plt.subplot2grid((8, 3), (4, 0), rowspan=1, colspan=2) myplotB(ax4, 'ax4') plt.subplots_adjust(left=0.1, bottom=0.1, right=0.9, top=0.9, wspace=.1, hspace=.1) fig.savefig(outpath + '\\' + 'mytest.pdf') Link to image of output plot; looks as expected
Create partial sublists by index, discarding some data [(x,y,z),...] to [(x,y),...]
I got a list1 which has N items in each item it has (x,y,z). For z in list2, I need to create a new list which has items from list1 with only (x,y) this need to be done for list3, list4 too. list1 = [(1250, 1442, 0), (1280, 1655, 1), (1029, 1680, 2), (624, 1573, 3), (732, 1159, 4), (1530, 1634, 5), (1885, 1628, 6), (2152, 1834, 7), (1252, 2459, 8), (1309, 3023, 9), (1376, 3585, 10), (1571, 2388, 11), (1682, 2952, 12), (1686, 3579, 13), (1184, 1391, 14), (1291, 1382, 15), (1117, 1440, 16), (1361, 1400, 17)] list2 = [0,1,14,15,16,17] list3 = [2,3,4,5,6,7,8,11] list4 = [9,10,12,13] For example, list5 which is between list1 and list2 looks like list5 = [(1250, 1442),(1280, 1655),(1184, 1391)......] Can anyone suggest a fast way to do it? Thank you
Easy enough: def getXYfromIndex(l, indexes): """Returns x,y from bigger list 'l' containing (x,y,z). Uses only those elements (by index) of 'l' that are in 'indexes'""" # list comprehension: returns x,y for each index in 'l' that is in 'indexes' return [(x,y) for x,y,_ in (l[i] for i in indexes)] list1 = [(1250, 1442, 0), (1280, 1655, 1), (1029, 1680, 2), (624, 1573, 3), (732, 1159, 4), (1530, 1634, 5), (1885, 1628, 6), (2152, 1834, 7), (1252, 2459, 8), (1309, 3023, 9), (1376, 3585, 10), (1571, 2388, 11), (1682, 2952, 12), (1686, 3579, 13), (1184, 1391, 14), (1291, 1382, 15), (1117, 1440, 16), (1361, 1400, 17)] list2 = [0,1,14,15,16,17] list3 = [2,3,4,5,6,7,8,11] list4 = [9,10,12,13] print(getXYfromIndex(list1,list2)) # use list5 = getXYfromIndex(list1,list2) print(getXYfromIndex(list1,list3)) # to work with those (x,y) - I just print them print(getXYfromIndex(list1,list4)) Output: [(1250, 1442), (1280, 1655), (1184, 1391), (1291, 1382), (1117, 1440), (1361, 1400)] [(1029, 1680), (624, 1573), (732, 1159), (1530, 1634), (1885, 1628), (2152, 1834), (1252, 2459), (1571, 2388)] [(1309, 3023), (1376, 3585), (1682, 2952), (1686, 3579)]
generating a multi dict with random numbers
I have a data structure defined as follow : reqList[i] = [multidict({ 1: ['type1', randint(1, 5), randint(1, 5), randint(1, 5)], 2: ['type2', randint(1, 5), randint(1, 5), randint(1, 5)], 3: ['type3', randint(1, 5), randint(1, 5), randint(1, 5)], 4: ['type4', randint(1, 5), randint(1, 5), randint(1, 5)] }), multidict({ (1, 2): randint(500, 1000), (2, 3): randint(500, 1000), (3, 4): randint(500, 1000) })] I want to make the creation of this data structure automatic in a for loop for example. I did this: nodes = {} for j in range(1, randint(2, 5)): nodes[j] = ['type%d' % j, randint(1, 5), randint(1, 5), randint(1, 5)] edges = {} for kk in range(1, len(nodes)): edges[(kk, kk + 1)] = randint(500, 1000) print "EDGES", edges reqList[i] = [multidict(nodes), multidict(edges)] del (nodes, edges) when I look into the outputed edges the order of the keys is not kept ! For example I am getting this: EDGES {(1, 2): 583, (3, 4): 504, (2, 3): 993} I want it to be : EDGES {(1, 2): 583, (2, 3): 993, (3, 4): 504} Does the way I am coding it is correct ? if not, could you suggest a better way knowing that I need to get the same result as in the first example?
Dictionary in 2.7 is unordered and you can not keep the order of insert, unless you manually keep a reference on what key got inserted and when in a separate list. The module collections contains a class called OrderedDict that acts like a dictionary but keeps the inserts in ordered, which is what you could use (it also uses a list to keep track of the keys insert but uses a double link list to speed up deletion of keys). There's no other way other than these two method. from collections import OrderedDict nodes = {} for j in range(1, randint(2, 5)): nodes[j] = ['type%d' % j, randint(1, 5), randint(1, 5), randint(1, 5)] edges = OrderedDict() for kk in range(1, len(nodes)): edges[(kk, kk + 1)] = randint(500, 1000) print "EDGES", edges # EDGES OrderedDict([((1, 2), 898), ((2, 3), 814)]) print edges[(1,2)] # still yields the correct number You can read more about OrderedDict here
How to create a table using report lab that can change the number of rows dynamically
I am creating a PDF that has a table in it except the table rows will differ from PDF to PDF table = Table(data, colWidths=[3.05 * cm, 4.5 * cm, 4 * cm,3* cm, 3 * cm]) table.setStyle(TableStyle([ ('INNERGRID', (0,0), (-1,-1), 0.25, black), ('BOX', (0,0), (-1,-1), 0.25, black), ])) table.wrapOn(self.pdf, self.width_table, self.height_table) table.drawOn(self.pdf, *self.coord(1.0, 18.6,cm)) That is what I am using to create the table with now. Thanks,
It's a central question for anyone starting out. Below is a complete workable code to start build from. The answer is, as you wrote yourself in the comment, is to loop. Problems, though, that anyone later will discover is how you deal with multi-page tables and design of those tables. There are various solutions worth looking into. from reportlab.lib.pagesizes import letter from reportlab.lib import colors from reportlab.platypus import Frame, PageTemplate, KeepInFrame from reportlab.lib.units import cm from reportlab.platypus import (Table, TableStyle, BaseDocTemplate) ######################################################################## def create_pdf(): """ Create a pdf """ # Create a frame text_frame = Frame( x1=3.00 * cm, # From left y1=1.5 * cm, # From bottom height=19.60 * cm, width=15.90 * cm, leftPadding=0 * cm, bottomPadding=0 * cm, rightPadding=0 * cm, topPadding=0 * cm, showBoundary=1, id='text_frame') # Create a table test_table = [] data = [] for i in range(11, 1, -1): column1data = f'Column_1 on row {i}' column2data = f'Column_2 on row {i}' data.append([column1data, column2data]) data_table = Table(data, 15.90 * cm / 2) data_table.setStyle(TableStyle([ # Title ('LEFTPADDING', (0, 0), (1, 0), 0), ('RIGHTPADDING', (0, 0), (1, 0), 0), ('VALIGN', (0, 0), (1, 0), 'TOP'), ('ALIGN', (0, 0), (1, 0), 'CENTRE'), # DataTable ('ALIGN', (0, 1), (1, -1), 'CENTRE'), ('SIZE', (0, 1), (-1, -1), 7), ('LEADING', (0, 1), (-1, -1), 8.4), ('VALIGN', (0, 1), (-1, -1), 'MIDDLE'), ('TOPPADDING', (0, 1), (-1, -1), 2.6), ('BOTTOMPADDING', (0, 1), (-1, -1), 2.6), ('LINEBELOW', (0, 1), (-1, -1), 0.3, colors.gray), ])) test_table.append(data_table) test_table = KeepInFrame(0, 0, test_table, mode='overflow') # Building the story story = [test_table] # adding test_table table (alternative, story.add(test_table)) # Establish a document doc = BaseDocTemplate("Example_output.pdf", pagesize=letter) # Creating a page template frontpage = PageTemplate(id='FrontPage', frames=[text_frame] ) # Adding the story to the template and template to the document doc.addPageTemplates(frontpage) # Building doc doc.build(story) # ---------------------------------------------------------------------- if __name__ == "__main__": create_pdf() # Printing the pdf