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