1 | # |
---|
2 | # function textable -- a Python script to make LaTeX tables |
---|
3 | # from ASCII files with columns |
---|
4 | # |
---|
5 | # Version 1.0 |
---|
6 | # |
---|
7 | # Usage: |
---|
8 | # |
---|
9 | # The call |
---|
10 | # |
---|
11 | # textable(filename) |
---|
12 | # |
---|
13 | # where filename is the name of an ASCII file with columns |
---|
14 | # |
---|
15 | # generates a new file 'filename'+'.tex' |
---|
16 | # with generic header and footer, alignment tabs, and |
---|
17 | # special LaTeX characters escaped. |
---|
18 | # If the number of lines is less than 40 all one table is generated; |
---|
19 | # otherwise the data is broken into two tables. |
---|
20 | # The fontsize is reduced progressively with the number of |
---|
21 | # lines but no more than two tables will be generated. |
---|
22 | # |
---|
23 | # |
---|
24 | # O. Nielsen, ANU, April 2000 |
---|
25 | |
---|
26 | |
---|
27 | """ |
---|
28 | This module contains two functions to generate LaTeX tables. |
---|
29 | |
---|
30 | ------------------- |
---|
31 | textool.maketable() |
---|
32 | ------------------- |
---|
33 | |
---|
34 | Declaration: |
---|
35 | maketable(array,title=None,rowlab=None,collab=None,maxcol=None, \ |
---|
36 | filename=None) |
---|
37 | |
---|
38 | Usage: |
---|
39 | Generates a new file 'filename'+'.tex' |
---|
40 | with a generic header and footer, alignment tabs, and |
---|
41 | special LaTeX characters escaped. |
---|
42 | If the number of lines is less than 40 all one table is generated; |
---|
43 | otherwise the data is broken into two tables. |
---|
44 | The fontsize is reduced progressively with the number of |
---|
45 | lines but no more than two tables will be generated. |
---|
46 | |
---|
47 | Input: array array is a list of lists containing entries for the |
---|
48 | table. Each list corresponds to one row, but they do |
---|
49 | not need to be the same length. |
---|
50 | title (optional) String to be used as title |
---|
51 | rowlab (optional) List of strings to used for row labels |
---|
52 | collab (optional) List of strings to used for column labels |
---|
53 | maxcol (optional) maximal number of columns (if known) |
---|
54 | filename (optional) filename for tex file (default='maketable') |
---|
55 | |
---|
56 | |
---|
57 | |
---|
58 | |
---|
59 | ------------------ |
---|
60 | textool.textable() |
---|
61 | ------------------ |
---|
62 | |
---|
63 | Declaration: |
---|
64 | textable(filename) |
---|
65 | |
---|
66 | Usage: |
---|
67 | Reads data from the ascii file filename and calls maketable to produce |
---|
68 | a LaTeX version. The file should contain rows of data elements but not |
---|
69 | necessarily having the same length. |
---|
70 | Running textable on arbitrary files is possible but meaningless. |
---|
71 | |
---|
72 | |
---|
73 | |
---|
74 | """ |
---|
75 | |
---|
76 | |
---|
77 | |
---|
78 | def textable(FN): |
---|
79 | from string import * |
---|
80 | |
---|
81 | input = open(FN,'r') # Open file with ASCII columns |
---|
82 | #output = open(FN+'.tex','w') # Open file with LateX table |
---|
83 | |
---|
84 | x = input.readlines() |
---|
85 | print 'Textable got ', len(x), 'records from ', FN |
---|
86 | |
---|
87 | |
---|
88 | maxcol = 0 |
---|
89 | array = [] |
---|
90 | for n in range(len(x)): |
---|
91 | record = split(rstrip(x[n])) |
---|
92 | array.append(record) |
---|
93 | col = len(record) # Number of columns in this record |
---|
94 | if col > maxcol: |
---|
95 | maxcol = col # Determine maximal number of columns |
---|
96 | |
---|
97 | maketable(array,rowlab=[],collab=[],title=FN,filename=FN+'.tex') |
---|
98 | |
---|
99 | return() |
---|
100 | |
---|
101 | # |
---|
102 | # Core routine for making and writing TeX table |
---|
103 | # |
---|
104 | # array is a list of lists (rows) |
---|
105 | # |
---|
106 | def maketable(array,title=None,rowlab=None,collab=None,maxcol=None,filename=None): |
---|
107 | |
---|
108 | splitthreshold = 40 # Maximal number of lines in one table |
---|
109 | # Tables with more lines are split into two |
---|
110 | |
---|
111 | import types |
---|
112 | |
---|
113 | # |
---|
114 | # Input checks |
---|
115 | #--------------- |
---|
116 | |
---|
117 | # |
---|
118 | # File name |
---|
119 | # |
---|
120 | if not filename: |
---|
121 | if title: |
---|
122 | filename = nospace(title) + '.tex' |
---|
123 | else: |
---|
124 | filename = 'maketable.tex' |
---|
125 | |
---|
126 | output = open(filename,'w') # Open file with LateX table |
---|
127 | |
---|
128 | # |
---|
129 | # array |
---|
130 | # |
---|
131 | |
---|
132 | if not type(array) in [types.ListType, types.TupleType]: |
---|
133 | array = [array] |
---|
134 | |
---|
135 | # |
---|
136 | # Maximal number of columns |
---|
137 | # |
---|
138 | if not maxcol: |
---|
139 | maxcol = 0 |
---|
140 | for n in range(len(array)): |
---|
141 | record = array[n] |
---|
142 | if not type(record) in [types.ListType, types.TupleType]: |
---|
143 | record = [record] |
---|
144 | col = len(record) # Number of columns in this record |
---|
145 | if col > maxcol: |
---|
146 | maxcol = col # Determine maximal number of columns |
---|
147 | |
---|
148 | # |
---|
149 | # Column labels |
---|
150 | # |
---|
151 | if not collab: |
---|
152 | collab = [] |
---|
153 | |
---|
154 | collab = list(collab) # Make copy to protect input list from being modified |
---|
155 | |
---|
156 | |
---|
157 | for j in range(maxcol): |
---|
158 | if j >= len(collab): |
---|
159 | collab.append('Col '+`j`) # Default column label |
---|
160 | collab[j] = '\\textbf{'+collab[j]+'}' |
---|
161 | |
---|
162 | # |
---|
163 | # Row labels |
---|
164 | # |
---|
165 | if not rowlab: |
---|
166 | rowlab = [] |
---|
167 | |
---|
168 | rowlab = list(rowlab) # Make copy to protect input list from being modified |
---|
169 | |
---|
170 | for j in range(len(array)): |
---|
171 | if j >= len(rowlab): |
---|
172 | rowlab.append('Row '+`j`) # Default row label |
---|
173 | rowlab[j] = '\\textbf{'+rowlab[j]+'}' |
---|
174 | |
---|
175 | # |
---|
176 | # Function body |
---|
177 | # |
---|
178 | y = [] |
---|
179 | for n in range(len(array)): |
---|
180 | record = array[n] |
---|
181 | if not type(record) in [types.ListType, types.TupleType]: |
---|
182 | record = [record] |
---|
183 | |
---|
184 | col = len(record) # Number of columns in this record |
---|
185 | |
---|
186 | if col > 0: |
---|
187 | # Aggregate Latex line |
---|
188 | texline = rowlab[n]+' & ' |
---|
189 | for j in range(maxcol): |
---|
190 | if j > 0: |
---|
191 | texline = texline+'\t& ' |
---|
192 | |
---|
193 | if j < col: |
---|
194 | texline = texline+texmap(str(record[j])) |
---|
195 | |
---|
196 | texline = texline + ' \\\\' |
---|
197 | y.append(texline) |
---|
198 | |
---|
199 | |
---|
200 | # |
---|
201 | # Make a qualified guess about splitting of table and fontsize |
---|
202 | # |
---|
203 | if len(y) <= splitthreshold: |
---|
204 | splittab = 0 |
---|
205 | tabstyle = 1 |
---|
206 | elif splitthreshold < len(y) <= 2*splitthreshold: |
---|
207 | splittab = 1 |
---|
208 | tabstyle = 2 |
---|
209 | else: |
---|
210 | splittab = 1 |
---|
211 | tabstyle = 3 |
---|
212 | |
---|
213 | if 5 < maxcol < 7: |
---|
214 | tabstyle = max(tabstyle,3) |
---|
215 | elif maxcol >= 7: |
---|
216 | tabstyle = max(tabstyle,4) |
---|
217 | |
---|
218 | |
---|
219 | # |
---|
220 | # Create generic table header |
---|
221 | # |
---|
222 | header = [] |
---|
223 | colform = '|l||' + 'c|'*maxcol |
---|
224 | if tabstyle == 1: |
---|
225 | header.append('{\\normalsize') |
---|
226 | elif tabstyle == 2: |
---|
227 | header.append('{\\small') |
---|
228 | elif tabstyle == 2: |
---|
229 | header.append('{\\scriptsize') |
---|
230 | else: |
---|
231 | header.append('{\\tiny') |
---|
232 | |
---|
233 | header.append('\\begin{tabular}{'+colform+'} \\hline') |
---|
234 | |
---|
235 | |
---|
236 | colnames = ' & ' |
---|
237 | for j in range(maxcol): |
---|
238 | if j > 0: |
---|
239 | colnames = colnames+'\t& ' |
---|
240 | |
---|
241 | # colnames = colnames+'\\textbf{Col '+`j`+'}' |
---|
242 | colnames = colnames+collab[j] |
---|
243 | |
---|
244 | header.append(colnames+'\\\\ \\hline\\hline') |
---|
245 | |
---|
246 | # |
---|
247 | # Create generic table footer |
---|
248 | # |
---|
249 | footer = [] |
---|
250 | footer.append('\\end{tabular}}') |
---|
251 | |
---|
252 | |
---|
253 | # |
---|
254 | # Generate file |
---|
255 | # |
---|
256 | |
---|
257 | output.write('\\begin{table}[hbt]\n') |
---|
258 | output.write('\\begin{center}\n') |
---|
259 | if title: |
---|
260 | output.write('\\textbf{'+texmap(str(title))+'}\\\\ \n') |
---|
261 | output.write('\n') |
---|
262 | |
---|
263 | # |
---|
264 | # One column table |
---|
265 | # |
---|
266 | if not splittab: |
---|
267 | # Header |
---|
268 | for n in range(len(header)): |
---|
269 | output.write(header[n]+'\n') |
---|
270 | |
---|
271 | # Contents |
---|
272 | for n in range(len(y)): |
---|
273 | output.write(y[n]) |
---|
274 | if n == len(y)-1: # Put a hline after last entry |
---|
275 | output.write(' \\hline \n') |
---|
276 | else: |
---|
277 | output.write('\n') |
---|
278 | # Footer |
---|
279 | for n in range(len(footer)): |
---|
280 | output.write(footer[n]+'\n') |
---|
281 | |
---|
282 | # |
---|
283 | # Two column table |
---|
284 | # |
---|
285 | else: |
---|
286 | tablen = int(round(len(y)/2.0)) |
---|
287 | for m in range(1): |
---|
288 | # Header |
---|
289 | output.write('\makebox[0.48\\textwidth]{\n') |
---|
290 | for n in range(len(header)): |
---|
291 | output.write(header[n]+'\n') |
---|
292 | |
---|
293 | # Contents |
---|
294 | k = 0 |
---|
295 | for n in range(len(y)): |
---|
296 | k = k+1 |
---|
297 | output.write(y[n]) |
---|
298 | if k == tablen: # Put a hline after last entry |
---|
299 | k = 0 |
---|
300 | output.write(' \\hline \n') |
---|
301 | # Footer |
---|
302 | for j in range(len(footer)): |
---|
303 | output.write(footer[j]+'\n') |
---|
304 | output.write('}\n') |
---|
305 | output.write('\hspace*{1mm}\n') |
---|
306 | output.write('\makebox[0.48\\textwidth]{\n') |
---|
307 | # Header |
---|
308 | for j in range(len(header)): |
---|
309 | output.write(header[j]+'\n') |
---|
310 | elif n == len(y)-1: # Put a hline after last entry |
---|
311 | output.write(' \\hline \n') |
---|
312 | if n == 2*tablen-2: # add an empty line for symmetry |
---|
313 | output.write('\\multicolumn{'+`maxcol`+'}{c}{} \\\\ \n') |
---|
314 | else: |
---|
315 | output.write('\n') |
---|
316 | |
---|
317 | # |
---|
318 | # Final footer |
---|
319 | # |
---|
320 | for n in range(len(footer)): |
---|
321 | output.write(footer[n]+'\n') |
---|
322 | output.write('}\n') |
---|
323 | |
---|
324 | output.write('\\end{center}\n') |
---|
325 | output.write('\\caption{ }\n') |
---|
326 | if title: |
---|
327 | output.write('\\label{tab:'+title+'}\n') |
---|
328 | else: |
---|
329 | output.write('\\label{tab: }\n') |
---|
330 | |
---|
331 | output.write('\\end{table}\n') |
---|
332 | |
---|
333 | output.close() |
---|
334 | print 'Textable wrote generic LaTeX table to', filename |
---|
335 | |
---|
336 | |
---|
337 | # texmap(s) |
---|
338 | # maps string s into Latex |
---|
339 | # |
---|
340 | def texmap(s): |
---|
341 | import types |
---|
342 | from string import * |
---|
343 | |
---|
344 | s = replace(s,'\\','\\backslash') |
---|
345 | s = replace(s,'#','\\#') |
---|
346 | s = replace(s,'$','\\$') |
---|
347 | s = replace(s,'%','\\%') |
---|
348 | s = replace(s,'&','\\&') |
---|
349 | s = replace(s,'~','\\~') |
---|
350 | s = replace(s,'_','\\_') |
---|
351 | s = replace(s,'^','\\^') |
---|
352 | s = replace(s,'{','\\{') |
---|
353 | s = replace(s,'}','\\}') |
---|
354 | |
---|
355 | return(s) |
---|
356 | |
---|
357 | def nospace(s): |
---|
358 | # |
---|
359 | # Replace spaces in s with underscores |
---|
360 | # |
---|
361 | |
---|
362 | import string |
---|
363 | |
---|
364 | newstr = '' |
---|
365 | for i in range(len(s)): |
---|
366 | if s[i] == ' ': |
---|
367 | newstr = newstr+'_' |
---|
368 | else: |
---|
369 | newstr = newstr+s[i] |
---|
370 | |
---|
371 | return(newstr) |
---|
372 | |
---|
373 | |
---|
374 | #======================= EXAMPLE ====================== |
---|
375 | |
---|
376 | def gen_latex_section(dataset,items,years,names='',filename=None): |
---|
377 | |
---|
378 | """gen_latex_section(dataset,items,years,names ='',filename=None) |
---|
379 | Generates a LaTeX document with basic statistics relating |
---|
380 | to the cohort defined by items, dataset, and years. |
---|
381 | The content of the generated report contains graphs with agergp, |
---|
382 | gender statistics and gender, RRMA statisitics. |
---|
383 | In addition there are tables with this information. |
---|
384 | The parameter names is used in the headlines. |
---|
385 | |
---|
386 | Example: |
---|
387 | from CRCdefs import MBSitems |
---|
388 | |
---|
389 | key = 'COLONOSCOPY' |
---|
390 | gen_latex_section('mbs',MBSitems[key],[1997,1998],key) |
---|
391 | """ |
---|
392 | |
---|
393 | import os, types |
---|
394 | from re import match # Regular Expressions |
---|
395 | from textool import * |
---|
396 | |
---|
397 | if not type(years) in [types.ListType, types.TupleType]: |
---|
398 | years = [years] |
---|
399 | if not type(items) in [types.ListType, types.TupleType]: |
---|
400 | items = [items] |
---|
401 | |
---|
402 | if not filename: |
---|
403 | if names == '': |
---|
404 | filename = 'Autoreport' |
---|
405 | else: |
---|
406 | filename = nospace(names) |
---|
407 | |
---|
408 | os.system('mkdir '+ filename) |
---|
409 | #os.system('cd '+ filename) |
---|
410 | curdir = os.getcwd() |
---|
411 | os.chdir(filename) |
---|
412 | |
---|
413 | output = open(filename+'.tex','w') |
---|
414 | |
---|
415 | output.write('\\documentclass{article}\n') |
---|
416 | output.write('\\usepackage{epsfig}\n') |
---|
417 | output.write('\\begin{document}\n') |
---|
418 | |
---|
419 | output.write('\\section{Findings}\n\n') |
---|
420 | for year in years: |
---|
421 | plot_age_gender(dataset,items,year,names,geneps=1) |
---|
422 | plot_rrma_gender(dataset,items,year,names,geneps=1) |
---|
423 | |
---|
424 | output.write('\\subsection{Basic statistics from ') |
---|
425 | output.write(texmap(dataset)+'}\n') |
---|
426 | #output.write(texmap(dataset)+' in '+str(year)+'}\n') |
---|
427 | |
---|
428 | texfiles = [] |
---|
429 | epsfiles = [] |
---|
430 | files = os.listdir('.') |
---|
431 | |
---|
432 | for fname in files: |
---|
433 | if match('.+eps',fname): |
---|
434 | epsfiles.append(fname) |
---|
435 | |
---|
436 | if match('.+tex',fname) and not match(filename+'.tex',fname): |
---|
437 | texfiles.append(fname) |
---|
438 | |
---|
439 | output.write('\\begin{center}\n') |
---|
440 | for file in epsfiles: |
---|
441 | output.write(' \\epsfxsize=0.47\\textwidth \\epsfbox{'+file+'}\n') |
---|
442 | output.write('\\end{center}\n\n') |
---|
443 | output.write('\\clearpage\n\n') |
---|
444 | |
---|
445 | for file in texfiles: |
---|
446 | output.write('\\input{'+file+'}\n') |
---|
447 | |
---|
448 | output.write('\\clearpage\n\n') |
---|
449 | |
---|
450 | output.write('\\end{document}\n') |
---|
451 | output.close() |
---|
452 | |
---|
453 | os.system('latex '+filename) |
---|
454 | os.system('dvips '+filename+' -o '+filename+'.ps') |
---|
455 | os.system('ghostview '+filename+'.ps &') |
---|
456 | print 'print the report using lpr ' + filename + '.ps' |
---|
457 | #print(' ***************************************************** |
---|
458 | # print the report using lpr ' + filename + '.ps |
---|
459 | # ********************************************************') |
---|
460 | |
---|
461 | os.chdir(curdir) |
---|
462 | |
---|