[2712] | 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 | |
---|