1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 from re import search
24 from string import ascii_letters, ascii_lowercase, punctuation, whitespace
25 import sys
26
27
28 sys.path.append(sys.path[0])
29 sys.path[0] = '../..'
30
31
32 from graphics import fetch_icon
33 from user_functions.data import Uf_info; uf_info = Uf_info()
34 from user_functions.data import Uf_tables; uf_tables = Uf_tables()
35
36
38 - def __init__(self, file='docstring.tex'):
78
79
81 """Allow the function text to be broken nicely across lines.
82
83 The '\' character will be added later by the latex_special_chars() method.
84 """
85
86
87 text = text.replace("(", "(\linebreak[0]")
88
89
90 for char in ascii_letters:
91 text = text.replace(".%s" % char, ".\linebreak[0]%s" % char)
92
93
94 text = text.replace("=", "=\linebreak[0]")
95
96
97 text = text.replace("\linebreak", "linebreak")
98
99
100 return text
101
102
133
134
171
172
173
197
198
215
216
218 """Create the user function sectioning."""
219
220
221 self.file.write("\n\n")
222
223
224 self.file.write("\\pagebreak[4]\n")
225 self.file.write("\\rule{\columnwidth}{1pt}\n")
226
227
228 self.file.write("\\vspace{-20pt}\n")
229 self.uf_name_latex = self.uf_name
230
231
232 self.uf_name_latex = self.latex_special_chars(self.uf_name_latex)
233 self.uf_name_latex = self.word_formatting(self.uf_name_latex, bold=True)
234
235
236 self.uf_name_latex = self.uf_name_latex.replace('.', '\-.')
237 self.uf_name_latex = self.uf_name_latex.replace('\_', '\-\_')
238
239
240 self.file.write("\subsection{%s} \label{uf: %s}\n" % (self.uf_name_latex, self.uf_name))
241
242
243 if self.uf_class:
244 icon = fetch_icon(self.uf_class.gui_icon, size='128x128', format=None)
245 if icon:
246 self.file.write("\includegraphics[bb=0 0 18 18]{%s} \hfill " % icon)
247 else:
248 self.file.write("\hfill ")
249
250
251 icon = fetch_icon(self.uf.gui_icon, size='128x128', format=None)
252 if icon:
253 self.file.write("\includegraphics[bb=0 0 18 18]{%s}\n" % icon)
254 else:
255 self.file.write("\n")
256
257
258 self.file.write("\n")
259
260
262 """Insert index marks into the text, word by word.
263
264 @param index: The index of the word in the self.words data structure.
265 @type index: int
266 @keyword bold: A flag which if True will cause the index entries to be in bold font.
267 @type bold: bool
268 """
269
270
271 if bold:
272 end_string = '|textbf}'
273 else:
274 end_string = '}'
275
276
277 for i in range(len(self.entries)):
278
279 if index+2 < len(self.words) and self.entries[i][2] == 3 and search(self.entries[i][0], self.words[index] + ' ' + self.words[index+1] + ' ' + self.words[index+2]):
280 self.words[index] = self.words[index] + '\\index{' + self.entries[i][1] + end_string
281
282
283 elif index+1 < len(self.words) and self.entries[i][2] == 2 and search(self.entries[i][0], self.words[index] + ' ' + self.words[index+1]):
284 self.words[index] = self.words[index] + '\\index{' + self.entries[i][1] + end_string
285
286
287 elif self.entries[i][2] == 1 and search(self.entries[i][0], self.words[index]):
288 self.words[index] = self.words[index] + '\\index{' + self.entries[i][1] + end_string
289
290
292 """Function for returning a data structure containing all words which should be indexed."""
293
294
295 self.entries = []
296
297
298
299
300 self.entries.append(['AIC', 'model selection!AIC'])
301 self.entries.append(['AICc', 'model selection!AICc'])
302 self.entries.append(['angle', 'angles'])
303 self.entries.append(['anisotropic', 'diffusion!anisotropic'])
304 self.entries.append(['ANOVA', 'model selection!ANOVA'])
305 self.entries.append(['asymmetric', 'diffusion!ellipsoid (asymmetric)'])
306 self.entries.append(['axially symmetric', 'diffusion!spheroid (axially symmetric)'])
307
308 self.entries.append(['BIC', 'model selection!BIC'])
309 self.entries.append(['BFGS', 'minimisation techniques!BFGS'])
310 self.entries.append(['bond length', 'bond length'])
311 self.entries.append(['bootstrap', 'model selection!bootstrap'])
312 self.entries.append(['bound', 'parameter!bounds'])
313 self.entries.append(['Brownian', 'diffusion!Brownian'])
314 self.entries.append(['bzip2', 'compression!bzip2'])
315
316 self.entries.append(['cauchy', 'minimisation techniques!Cauchy point'])
317 self.entries.append(['CG-Steihaug', 'minimisation techniques!CG-Steihaug'])
318 self.entries.append(['chemical exchange', 'chemical exchange'])
319 self.entries.append(['chi-squared', 'chi-squared'])
320 self.entries.append(['compression', 'compression'])
321 self.entries.append(['conjugate gradient', 'minimisation techniques!conjugate gradient'])
322 self.entries.append(['constraint', 'constraint'])
323 self.entries.append(['copy', 'copy'])
324 self.entries.append(['correlation time', 'correlation time'])
325 self.entries.append(['cross-validation', 'model selection!cross-validation'])
326
327 self.entries.append(['dasha', 'software!Dasha'])
328 self.entries.append(['Dasha', 'software!Dasha'])
329 self.entries.append(['delete', 'delete'])
330 self.entries.append(['diffusion tensor', 'diffusion!tensor'])
331 self.entries.append(['display', 'display'])
332 self.entries.append(['dogleg', 'minimisation techniques!dogleg'])
333
334 self.entries.append(['eigenvalue', 'eigenvalues'])
335 self.entries.append(['elimination', 'model elimination'])
336 self.entries.append(['ellipsoid', 'diffusion!ellipsoid (asymmetric)'])
337 self.entries.append(['Euler angle', 'Euler angles'])
338 self.entries.append(['exact trust region', 'minimisation techniques!exact trust region'])
339
340 self.entries.append(['Fletcher-Reeves', 'minimisation techniques!Fletcher-Reeves'])
341 self.entries.append(['floating point', 'floating point number'])
342
343 self.entries.append(['grace', 'software!Grace'])
344 self.entries.append(['Grace', 'software!Grace'])
345 self.entries.append(['gzip', 'compression!gzip'])
346
347 self.entries.append(['Hestenes-Stiefel', 'minimisation techniques!Hestenes-Stiefel'])
348 self.entries.append(['hypothesis testing', 'model selection!hypothesis testing'])
349
350 self.entries.append(['isotropic', 'diffusion!sphere (isotropic)'])
351
352 self.entries.append(['Levenberg-Marquardt', 'minimisation techniques!Levenberg-Marquardt'])
353 self.entries.append(['limit', 'parameter!limit'])
354
355 self.entries.append(['map', 'map'])
356 self.entries.append(['method of [Mm]ultipliers', 'minimisation techniques!Method of Multipliers'])
357 self.entries.append(['minimise', 'minimisation'])
358 self.entries.append(['minimisation', 'minimisation'])
359 self.entries.append(['model elimination', 'model elimination'])
360 self.entries.append(['modelfree4', 'software!Modelfree'])
361 self.entries.append(['Modelfree4', 'software!Modelfree'])
362 self.entries.append(['modelling', 'modelling'])
363 self.entries.append(['molecule', 'molecule'])
364 self.entries.append(['molmol', 'software!MOLMOL'])
365 self.entries.append(['Molmol', 'software!MOLMOL'])
366
367 self.entries.append(['opendx', 'software!OpenDX'])
368 self.entries.append(['OpenDX', 'software!OpenDX'])
369 self.entries.append(['optimise', 'optimise'])
370 self.entries.append(['order parameter', 'order parameter'])
371
372 self.entries.append(['newton', 'minimisation techniques!Newton'])
373 self.entries.append(['newton-CG', 'minimisation techniques!Newton conjugate gradient'])
374 self.entries.append(['NMR', 'NMR'])
375
376 self.entries.append(['PDB', 'PDB'])
377 self.entries.append(['Polak-Ribi.*re', 'minimisation techniques!Polak-Ribiere@Polak-Ribi\`ere'])
378 self.entries.append(['Polak-Ribi.*re +', 'minimisation techniques!Polak-Ribiere@Polak-Ribi\`ere +'])
379 self.entries.append(['plot', 'plot'])
380 self.entries.append(['python', 'Python'])
381
382 self.entries.append(['read', 'read'])
383 self.entries.append(['regular expression', 'regular expression'])
384 self.entries.append(['relaxation', 'relaxation'])
385 self.entries.append(['rotation', 'rotation'])
386
387 self.entries.append(['sequence', 'sequence'])
388 self.entries.append(['script', 'scripting!script file'])
389 self.entries.append(['scripting', 'scripting'])
390 self.entries.append(['simplex', 'minimisation techniques!simplex'])
391 self.entries.append(['sphere', 'diffusion!sphere (isotropic)'])
392 self.entries.append(['spheroid', 'diffusion!spheroid (axially symmetric)'])
393 self.entries.append(['sparky', 'software!Sparky'])
394 self.entries.append(['Sparky', 'software!Sparky'])
395 self.entries.append(['steepest descent', 'minimisation techniques!steepest descent'])
396
397 self.entries.append(['tar', 'tar'])
398
399 self.entries.append(['uncompressed', 'compression!uncompressed'])
400
401 self.entries.append(['write', 'write'])
402
403 self.entries.append(['xeasy', 'software!XEasy'])
404 self.entries.append(['Xeasy', 'software!XEasy'])
405 self.entries.append(['XEasy', 'software!XEasy'])
406
407
408 for i in range(len(self.entries)):
409
410 self.entries[i].append(len(self.entries[i][0].split(' ')))
411
412
413 if search(self.entries[i][0][0], ascii_lowercase):
414 self.entries[i][0] = '[' + self.entries[i][0][0].upper() + self.entries[i][0][0] + ']' + self.entries[i][0][1:]
415
416
417 self.entries[i][0] = '^' + self.entries[i][0]
418
419
420 self.entries[i].reverse()
421
422
423 self.entries.sort(reverse=1)
424 for i in range(len(self.entries)):
425 self.entries[i].reverse()
426
427
571
572
574 """Function for changing the quotes for LaTeX processing."""
575
576
577 new_string = ''
578 in_quote = 0
579
580
581 for i in range(len(string)):
582
583 if search('\'', string[i]):
584
585 if not in_quote and (i == 0 or not search('[a-z]', string[i-1])):
586 new_string = new_string + '`'
587 in_quote = 1
588 continue
589
590
591 else:
592 in_quote = 0
593
594
595 new_string = new_string + string[i]
596
597 return new_string
598
599
601 """Function for handling LaTeX special characters."""
602
603
604 string = string.replace('\\', 'This is a backslash to be replaced at the end of this functioN')
605
606
607 for char in "#$%&_{}":
608 string = string.replace(char, '\\'+char)
609
610
611 for char in "^~":
612 string = string.replace(char, '\\'+char+'{}')
613
614
615 string = string.replace('This is a backslash to be replaced at the end of this functioN', '$\\backslash$')
616
617
618 string = string.replace('linebreak[0]', '\linebreak[0]')
619
620
621 return string
622
623
625 """Function for placing quotes within the quote environment."""
626
627
628 elements = self.words[index].split("'")
629
630
631 if len(elements) == 3:
632 self.words[index] = elements[0] + '\quotecmd{' + elements[1] + '}' + elements[2]
633
634
635 elif len(elements) > 3:
636 sys.stderr.write('Unknown quote: ' + repr(self.words[index]))
637 sys.exit()
638
639
640 if len(elements) == 2:
641
642 if not self.in_quote and not search('[a-z]$', elements[0]):
643 self.words[index] = elements[0] + '\quotecmd{' + elements[1]
644 self.in_quote = 1
645
646
647 elif self.in_quote:
648 self.words[index] = elements[0] + '}' + elements[1]
649 self.in_quote = 0
650
651
653 """Only replace in safe places within the text."""
654
655
656
657
658 string = string.replace('0'+text, '0'+latex)
659 string = string.replace('1'+text, '1'+latex)
660 string = string.replace('2'+text, '2'+latex)
661 string = string.replace('3'+text, '3'+latex)
662 string = string.replace('4'+text, '4'+latex)
663 string = string.replace('5'+text, '5'+latex)
664 string = string.replace('6'+text, '6'+latex)
665 string = string.replace('7'+text, '7'+latex)
666 string = string.replace('8'+text, '8'+latex)
667 string = string.replace('9'+text, '9'+latex)
668
669
670 string = string.replace(' '+text+',', ' '+latex+',')
671 string = string.replace(' '+text+'.', ' '+latex+'.')
672 string = string.replace(' '+text+' ', ' '+latex+' ')
673 string = string.replace(' '+text+';', ' '+latex+';')
674 string = string.replace(' '+text+':', ' '+latex+':')
675
676
677 string = string.replace('['+text+']', '['+latex+']')
678 string = string.replace('['+text+' ', '['+latex+' ')
679 string = string.replace('['+text+',', '['+latex+',')
680 string = string.replace('['+text+';', '['+latex+';')
681 string = string.replace(' '+text+']', ' '+latex+']')
682
683
684 string = string.replace('('+text+')', '('+latex+')')
685 string = string.replace('('+text+' ', '('+latex+' ')
686 string = string.replace('('+text+',', '('+latex+',')
687 string = string.replace('('+text+';', '('+latex+';')
688 string = string.replace(' '+text+')', ' '+latex+')')
689
690
691 string = string.replace('{'+text+' ', '{'+latex+' ')
692 string = string.replace('{'+text+',', '{'+latex+',')
693 string = string.replace('{'+text+';', '{'+latex+';')
694 string = string.replace(' '+text+'\\', ' '+latex+'\\')
695
696
697 string = string.replace('`'+text+'\'', '`'+latex+'\'')
698 string = string.replace('`'+text+' ', '`'+latex+' ')
699 string = string.replace('`'+text+',', '`'+latex+',')
700 string = string.replace('`'+text+'.', '`'+latex+'.')
701 string = string.replace('`'+text+';', '`'+latex+';')
702 string = string.replace(' '+text+'\'', ' '+latex+'\'')
703
704
705 substring = string[-len(text)-1:].replace(' '+text, ' '+latex)
706 string = string[0:-len(text)-1] + substring
707
708 substring = string[-len(text)-1:].replace('.'+text, '.'+latex)
709 string = string[0:-len(text)-1] + substring
710
711 string = string.replace(' '+text+'\n', ' '+latex+'\n')
712 string = string.replace('.'+text+'\n', '.'+latex+'\n')
713
714
715 string = string.replace(' '+text+'\^', ' '+latex+'\^')
716 string = string.replace('('+text+'\^', '('+latex+'\^')
717 string = string.replace('\n'+text+'\^', '\n'+latex+'\^')
718
719
720 if search('^'+text+'['+punctuation+']', string) or search('^'+text+'['+whitespace+']', string) or search('\n'+text+'['+punctuation+']', string) or search('\n'+text+'['+whitespace+']', string):
721 string = string.replace(text+' ', latex+' ')
722 string = string.replace(text+',', latex+',')
723 string = string.replace(text+'.', latex+'.')
724 string = string.replace(text+';', latex+';')
725 string = string.replace(text+']', latex+']')
726 string = string.replace(text+')', latex+')')
727 string = string.replace(text+'^', latex+'^')
728 string = string.replace(text+'\\', latex+'\\')
729 string = string.replace(text+'\'', latex+'\'')
730 string = string.replace(text+'\n', latex+'\n')
731
732
733
734 return string
735
736
738 """Determine if column wrapping should occur.
739
740 @param table: The table.
741 @type table: list of lists of str
742 @keyword max_char: The maximum number of characters a column is allowed before wrapping is applied.
743 @type max_char: int
744 @return: The list of flags for wrapping columns.
745 @rtype: list of bool
746 """
747
748
749 num_cols = len(table[0])
750 widths = [0] * num_cols
751 for i in range(len(table)):
752 for j in range(num_cols):
753
754 if len(table[i][j]) > widths[j]:
755 widths[j] = len(table[i][j])
756
757
758 wrap = []
759 for i in range(len(widths)):
760 if widths[i] > max_char:
761 wrap.append(True)
762 else:
763 wrap.append(False)
764
765
766 return wrap
767
768
802
803
805 """Format and write out an itemised list.
806
807 @param item_list: The list of items and description lists.
808 @type item_list: list of list of str
809 """
810
811
812 latex_lines = []
813 items = False
814 for i in range(len(item_list)):
815
816 item = item_list[i][0]
817 if item == None:
818 item = ''
819 if item != '':
820 items = True
821 item = self.latex_special_chars(item)
822 item = self.latex_formatting(item)
823 item = self.word_formatting(item)
824
825
826 desc = self.latex_special_chars(item_list[i][1])
827 desc = self.latex_formatting(desc)
828 desc = self.word_formatting(desc)
829
830
831 if item != '':
832 latex_lines.append("\\item[%s --] %s\n" % (item, desc))
833 else:
834 latex_lines.append("\\item[]%s\n" % desc)
835
836
837 if not items:
838 self.file.write("\\begin{itemize}\n")
839 else:
840 self.file.write("\\begin{description}\n")
841
842
843 for line in latex_lines:
844 self.file.write(line)
845
846
847 if not items:
848 self.file.write("\\end{itemize}\n\n")
849 else:
850 self.file.write("\\end{description}\n\n")
851
852
854 """Format and write out a list.
855
856 @param list: The list.
857 @type list: list of str
858 """
859
860
861 self.file.write("\\begin{itemize}\n")
862
863
864 for item in list:
865
866 item = self.latex_special_chars(item)
867 item = self.latex_formatting(item)
868 item = self.word_formatting(item)
869
870
871 self.file.write("\\item[]%s\n" % item)
872
873
874 self.file.write("\\end{itemize}\n\n")
875
876
891
892
912
913
915 """Format and write out a table.
916
917 @param label: The unique table label.
918 @type label: list of lists of str
919 """
920
921
922 table = uf_tables.get_table(label)
923
924
925 self.file.write("Please see Table~\\ref{%s} on page~\\pageref{%s}.\n\n" % (label, label))
926
927
928 if label in self.uf_table_labels:
929 return
930 else:
931 self.uf_table_labels.append(label)
932
933
934 col_wrap = self.tabular_wrapping(table.cells)
935 wrap = sum(col_wrap)
936
937
938 num_rows = len(table.cells)
939 num_cols = len(table.headings)
940
941
942 if table.longtable:
943
944 self.file.write("\\onecolumn\n")
945 self.file.write("\\begin{scriptsize}\n")
946 self.file.write("\\begin{center}\n")
947 self.file.write("\\begin{longtable}{%s}\n" % ("l"*num_cols))
948 else:
949
950 self.file.write("\\begin{table*}\n")
951 self.file.write("\\begin{scriptsize}\n")
952 self.file.write("\\begin{center}\n")
953
954
955 self.file.write("\\caption[%s]{%s}\n" % (table.caption_short, table.caption))
956
957
958 if table.longtable:
959
960 self.file.write("\\\\\n")
961 self.file.write("\\toprule\n")
962 else:
963
964 if wrap:
965 self.file.write("\\begin{tabularx}{\\textwidth}{")
966 else:
967 self.file.write("\\begin{tabular}{")
968 for i in range(num_cols):
969 if col_wrap[i]:
970 text = "X"
971 else:
972 text = "l"
973 self.file.write(text)
974 self.file.write("}\n")
975 self.file.write("\\\\[-5pt]\n")
976 self.file.write("\\toprule\n")
977
978
979 for j in range(num_cols):
980
981 if j > 0:
982 self.file.write(' & ')
983
984
985 cell = table.headings[j]
986 cell = self.latex_special_chars(cell)
987 cell = self.latex_formatting(cell)
988
989
990 self.file.write(cell)
991
992
993 self.file.write(" \\\\\n")
994
995
996 if table.longtable:
997 self.file.write("\\midrule\n")
998 self.file.write("\\endhead\n\n")
999 self.file.write("\\bottomrule\n")
1000 self.file.write("\\endfoot\n")
1001 else:
1002
1003 self.file.write("\\midrule\n")
1004
1005
1006 if table.longtable:
1007 self.file.write("\\label{%s}\n" % label)
1008
1009
1010 for i in range(num_rows):
1011
1012 for j in range(num_cols):
1013
1014 if j > 0:
1015 self.file.write(' & ')
1016
1017
1018 cell = table.cells[i][j]
1019 cell = self.latex_special_chars(cell)
1020 cell = self.latex_formatting(cell)
1021
1022
1023 self.file.write(cell)
1024
1025
1026 self.file.write(" \\\\\n")
1027
1028
1029 if table.longtable:
1030 self.file.write("\\end{longtable}\n")
1031 self.file.write("\\end{center}\n")
1032 self.file.write("\\end{scriptsize}\n")
1033 self.file.write("\\twocolumn\n")
1034 else:
1035 self.file.write("\\bottomrule\n")
1036 self.file.write("\\\\[-5pt]\n")
1037 self.file.write("\\label{%s}\n" % label)
1038 if wrap:
1039 self.file.write("\\end{tabularx}\n")
1040 else:
1041 self.file.write("\\end{tabular}\n")
1042 self.file.write("\\end{center}\n")
1043 self.file.write("\\end{scriptsize}\n")
1044 self.file.write("\\end{table*}\n")
1045
1046
1047 self.table_count += 1
1048 self.uf_table_count += 1
1049
1050
1051 self.file.write("\n\n")
1052
1053
1055 """Format and write out the verbatim text.
1056
1057 @param text: The text to write out in a LaTeX verbatim environment.
1058 @type text: str
1059 """
1060
1061
1062 self.file.write("{\\footnotesize \\begin{verbatim}\n")
1063 self.file.write(text)
1064 self.file.write("\n\\end{verbatim}}\n\n")
1065