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 os import sep
27 from os.path import dirname
28 from re import search
29 from string import ascii_letters, ascii_lowercase, punctuation, whitespace
30 import sys
31
32
33 sys.path.append(sys.path[0])
34 sys.path[0] = '../..'
35
36
37 from graphics import fetch_icon
38 import user_functions
39 from user_functions.data import Uf_info; uf_info = Uf_info()
40 from user_functions.data import Uf_tables; uf_tables = Uf_tables()
41
42
43
44 user_functions.initialise()
45
46
48 - def __init__(self, file='docstring.tex'):
95
96
98 """Allow the function text to be broken nicely across lines.
99
100 The '\' character will be added later by the latex_special_chars() method.
101 """
102
103
104 text = text.replace("(", "(\linebreak[0]")
105
106
107 for char in ascii_letters:
108 text = text.replace(".%s" % char, ".\linebreak[0]%s" % char)
109
110
111 text = text.replace("=", "=\linebreak[0]")
112
113
114 text = text.replace("\linebreak", "linebreak")
115
116
117 return text
118
119
150
151
188
189
190
214
215
232
233
235 """Create the user function sectioning."""
236
237
238 self.file.write("\n\n")
239
240
241 self.file.write("\\pagebreak[4]\n")
242 self.file.write("\\rule{\columnwidth}{1pt}\n")
243
244
245 self.file.write("\\vspace{-20pt}\n")
246 self.uf_name_latex = self.uf_name
247
248
249 self.uf_name_latex = self.latex_special_chars(self.uf_name_latex)
250 self.uf_name_latex = self.word_formatting(self.uf_name_latex, bold=True)
251
252
253 self.uf_name_latex = self.uf_name_latex.replace('.', '\-.')
254 self.uf_name_latex = self.uf_name_latex.replace('\_', '\-\_')
255
256
257 self.file.write("\subsection{%s} \label{uf: %s}\n" % (self.uf_name_latex, self.uf_name))
258
259
260 if self.uf_class:
261 icon = fetch_icon(self.uf_class.gui_icon, size='128x128', format=None, sep='/', full_path=False)
262 if icon:
263 self.file.write("\includegraphics[bb=0 0 18 18]{%s} \hfill " % icon)
264 else:
265 self.file.write("\hfill ")
266
267
268 icon = fetch_icon(self.uf.gui_icon, size='128x128', format=None, sep='/', full_path=False)
269 if icon:
270 self.file.write("\includegraphics[bb=0 0 18 18]{%s}\n" % icon)
271 else:
272 self.file.write("\n")
273
274
275 self.file.write("\n")
276
277
279 """Insert index marks into the text, word by word.
280
281 @param index: The index of the word in the self.words data structure.
282 @type index: int
283 @keyword bold: A flag which if True will cause the index entries to be in bold font.
284 @type bold: bool
285 """
286
287
288 if bold:
289 end_string = '|textbf}'
290 else:
291 end_string = '}'
292
293
294 for i in range(len(self.entries)):
295
296 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]):
297 self.words[index] = self.words[index] + '\\index{' + self.entries[i][1] + end_string
298
299
300 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]):
301 self.words[index] = self.words[index] + '\\index{' + self.entries[i][1] + end_string
302
303
304 elif self.entries[i][2] == 1 and search(self.entries[i][0], self.words[index]):
305 self.words[index] = self.words[index] + '\\index{' + self.entries[i][1] + end_string
306
307
309 """Function for returning a data structure containing all words which should be indexed."""
310
311
312 self.entries = []
313
314
315
316
317 self.entries.append(['AIC', 'model selection!AIC'])
318 self.entries.append(['AICc', 'model selection!AICc'])
319 self.entries.append(['angle', 'angles'])
320 self.entries.append(['anisotropic', 'diffusion!anisotropic'])
321 self.entries.append(['ANOVA', 'model selection!ANOVA'])
322 self.entries.append(['asymmetric', 'diffusion!ellipsoid (asymmetric)'])
323 self.entries.append(['axially symmetric', 'diffusion!spheroid (axially symmetric)'])
324
325 self.entries.append(['BIC', 'model selection!BIC'])
326 self.entries.append(['BFGS', 'optimisation!algorithm!BFGS'])
327 self.entries.append(['bond length', 'bond length'])
328 self.entries.append(['bootstrap', 'model selection!bootstrap'])
329 self.entries.append(['bound', 'parameter!bounds'])
330 self.entries.append(['Brownian', 'diffusion!Brownian'])
331 self.entries.append(['bzip2', 'compression!bzip2'])
332
333 self.entries.append(['cauchy', 'optimisation!algorithm!Cauchy point'])
334 self.entries.append(['CG-Steihaug', 'optimisation!algorithm!CG-Steihaug'])
335 self.entries.append(['chemical exchange', 'chemical exchange'])
336 self.entries.append(['chi-squared', 'chi-squared'])
337 self.entries.append(['compression', 'compression'])
338 self.entries.append(['conjugate gradient', 'optimisation!algorithm!conjugate gradient'])
339 self.entries.append(['constraint', 'constraint'])
340 self.entries.append(['copy', 'copy'])
341 self.entries.append(['correlation time', 'correlation time'])
342 self.entries.append(['cross-validation', 'model selection!cross-validation'])
343
344 self.entries.append(['dasha', 'software!Dasha'])
345 self.entries.append(['Dasha', 'software!Dasha'])
346 self.entries.append(['delete', 'delete'])
347 self.entries.append(['diffusion tensor', 'diffusion!tensor'])
348 self.entries.append(['display', 'display'])
349 self.entries.append(['dogleg', 'optimisation!algorithm!dogleg'])
350
351 self.entries.append(['eigenvalue', 'eigenvalues'])
352 self.entries.append(['elimination', 'model elimination'])
353 self.entries.append(['ellipsoid', 'diffusion!ellipsoid (asymmetric)'])
354 self.entries.append(['Euler angle', 'Euler angles'])
355 self.entries.append(['exact trust region', 'optimisation!algorithm!exact trust region'])
356
357 self.entries.append(['Fletcher-Reeves', 'optimisation!algorithm!Fletcher-Reeves'])
358 self.entries.append(['floating point', 'floating point number'])
359
360 self.entries.append(['grace', 'software!Grace'])
361 self.entries.append(['Grace', 'software!Grace'])
362 self.entries.append(['gzip', 'compression!gzip'])
363
364 self.entries.append(['Hestenes-Stiefel', 'optimisation!algorithm!Hestenes-Stiefel'])
365 self.entries.append(['hypothesis testing', 'model selection!hypothesis testing'])
366
367 self.entries.append(['isotropic', 'diffusion!sphere (isotropic)'])
368
369 self.entries.append(['Levenberg-Marquardt', 'optimisation!algorithm!Levenberg-Marquardt'])
370 self.entries.append(['limit', 'parameter!limit'])
371
372 self.entries.append(['map', 'map'])
373 self.entries.append(['method of [Mm]ultipliers', 'optimisation!constraint algorithm!Method of Multipliers'])
374 self.entries.append(['minimise', 'optimisation'])
375 self.entries.append(['minimisation', 'optimisation'])
376 self.entries.append(['model elimination', 'model elimination'])
377 self.entries.append(['modelfree4', 'software!Modelfree'])
378 self.entries.append(['Modelfree4', 'software!Modelfree'])
379 self.entries.append(['modelling', 'modelling'])
380 self.entries.append(['molecule', 'molecule'])
381 self.entries.append(['molmol', 'software!MOLMOL'])
382 self.entries.append(['Molmol', 'software!MOLMOL'])
383
384 self.entries.append(['opendx', 'software!OpenDX'])
385 self.entries.append(['OpenDX', 'software!OpenDX'])
386 self.entries.append(['optimise', 'optimise'])
387 self.entries.append(['order parameter', 'order parameter'])
388
389 self.entries.append(['newton', 'optimisation!algorithm!Newton'])
390 self.entries.append(['newton-CG', 'optimisation!algorithm!Newton conjugate gradient'])
391 self.entries.append(['NMR', 'NMR'])
392
393 self.entries.append(['PDB', 'PDB'])
394 self.entries.append(['Polak-Ribi.*re', 'optimisation!algorithm!Polak-Ribiere@Polak-Ribi\`ere'])
395 self.entries.append(['Polak-Ribi.*re +', 'optimisation!algorithm!Polak-Ribiere@Polak-Ribi\`ere +'])
396 self.entries.append(['plot', 'plot'])
397 self.entries.append(['python', 'Python'])
398
399 self.entries.append(['read', 'read'])
400 self.entries.append(['regular expression', 'regular expression'])
401 self.entries.append(['relaxation', 'relaxation'])
402 self.entries.append(['rotation', 'rotation'])
403
404 self.entries.append(['sequence', 'sequence'])
405 self.entries.append(['script', 'scripting!script file'])
406 self.entries.append(['scripting', 'scripting'])
407 self.entries.append(['simplex', 'optimisation!algorithm!Nelder-Mead simplex'])
408 self.entries.append(['sphere', 'diffusion!sphere (isotropic)'])
409 self.entries.append(['spheroid', 'diffusion!spheroid (axially symmetric)'])
410 self.entries.append(['sparky', 'software!Sparky'])
411 self.entries.append(['Sparky', 'software!Sparky'])
412 self.entries.append(['steepest descent', 'optimisation!algorithm!steepest descent'])
413
414 self.entries.append(['tar', 'tar'])
415
416 self.entries.append(['uncompressed', 'compression!uncompressed'])
417
418 self.entries.append(['write', 'write'])
419
420 self.entries.append(['xeasy', 'software!XEasy'])
421 self.entries.append(['Xeasy', 'software!XEasy'])
422 self.entries.append(['XEasy', 'software!XEasy'])
423
424
425 for i in range(len(self.entries)):
426
427 self.entries[i].append(len(self.entries[i][0].split(' ')))
428
429
430 if search(self.entries[i][0][0], ascii_lowercase):
431 self.entries[i][0] = '[' + self.entries[i][0][0].upper() + self.entries[i][0][0] + ']' + self.entries[i][0][1:]
432
433
434 self.entries[i][0] = '^' + self.entries[i][0]
435
436
437 self.entries[i].reverse()
438
439
440 self.entries.sort(reverse=1)
441 for i in range(len(self.entries)):
442 self.entries[i].reverse()
443
444
588
589
591 """Function for changing the quotes for LaTeX processing."""
592
593
594 new_string = ''
595 in_quote = 0
596
597
598 for i in range(len(string)):
599
600 if search('\'', string[i]):
601
602 if not in_quote and (i == 0 or not search('[a-z]', string[i-1])):
603 new_string = new_string + '`'
604 in_quote = 1
605 continue
606
607
608 else:
609 in_quote = 0
610
611
612 new_string = new_string + string[i]
613
614 return new_string
615
616
618 """Function for handling LaTeX special characters."""
619
620
621 string = string.replace('\\', 'This is a backslash to be replaced at the end of this functioN')
622
623
624 for char in "#$%&_{}":
625 string = string.replace(char, '\\'+char)
626
627
628 for char in "^~":
629 string = string.replace(char, '\\'+char+'{}')
630
631
632 string = string.replace('This is a backslash to be replaced at the end of this functioN', '$\\backslash$')
633
634
635 string = string.replace('linebreak[0]', '\linebreak[0]')
636
637
638 return string
639
640
642 """Function for placing quotes within the quote environment."""
643
644
645 elements = self.words[index].split("'")
646
647
648 if len(elements) == 3:
649 self.words[index] = elements[0] + '\quotecmd{' + elements[1] + '}' + elements[2]
650
651
652 elif len(elements) > 3:
653 sys.stderr.write('Unknown quote: ' + repr(self.words[index]))
654 sys.exit()
655
656
657 if len(elements) == 2:
658
659 if not self.in_quote and not search('[a-z]$', elements[0]):
660 self.words[index] = elements[0] + '\quotecmd{' + elements[1]
661 self.in_quote = 1
662
663
664 elif self.in_quote:
665 self.words[index] = elements[0] + '}' + elements[1]
666 self.in_quote = 0
667
668
670 """Only replace in safe places within the text."""
671
672
673
674
675 string = string.replace('0'+text, '0'+latex)
676 string = string.replace('1'+text, '1'+latex)
677 string = string.replace('2'+text, '2'+latex)
678 string = string.replace('3'+text, '3'+latex)
679 string = string.replace('4'+text, '4'+latex)
680 string = string.replace('5'+text, '5'+latex)
681 string = string.replace('6'+text, '6'+latex)
682 string = string.replace('7'+text, '7'+latex)
683 string = string.replace('8'+text, '8'+latex)
684 string = string.replace('9'+text, '9'+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 string = string.replace(' '+text+']', ' '+latex+']')
699
700
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 string = string.replace('{'+text+' ', '{'+latex+' ')
709 string = string.replace('{'+text+',', '{'+latex+',')
710 string = string.replace('{'+text+';', '{'+latex+';')
711 string = string.replace(' '+text+'\\', ' '+latex+'\\')
712
713
714 string = string.replace('`'+text+'\'', '`'+latex+'\'')
715 string = string.replace('`'+text+' ', '`'+latex+' ')
716 string = string.replace('`'+text+',', '`'+latex+',')
717 string = string.replace('`'+text+'.', '`'+latex+'.')
718 string = string.replace('`'+text+';', '`'+latex+';')
719 string = string.replace(' '+text+'\'', ' '+latex+'\'')
720
721
722 substring = string[-len(text)-1:].replace(' '+text, ' '+latex)
723 string = string[0:-len(text)-1] + substring
724
725 substring = string[-len(text)-1:].replace('.'+text, '.'+latex)
726 string = string[0:-len(text)-1] + substring
727
728 string = string.replace(' '+text+'\n', ' '+latex+'\n')
729 string = string.replace('.'+text+'\n', '.'+latex+'\n')
730
731
732 string = string.replace(' '+text+'\^', ' '+latex+'\^')
733 string = string.replace('('+text+'\^', '('+latex+'\^')
734 string = string.replace('\n'+text+'\^', '\n'+latex+'\^')
735
736
737 if search('^'+text+'['+punctuation+']', string) or search('^'+text+'['+whitespace+']', string) or search('\n'+text+'['+punctuation+']', string) or search('\n'+text+'['+whitespace+']', string):
738 string = string.replace(text+' ', latex+' ')
739 string = string.replace(text+',', latex+',')
740 string = string.replace(text+'.', latex+'.')
741 string = string.replace(text+';', latex+';')
742 string = string.replace(text+']', latex+']')
743 string = string.replace(text+')', latex+')')
744 string = string.replace(text+'^', latex+'^')
745 string = string.replace(text+'\\', latex+'\\')
746 string = string.replace(text+'\'', latex+'\'')
747 string = string.replace(text+'\n', latex+'\n')
748
749
750
751 return string
752
753
755 """Create a LaTeX file defining the relax language syntax for the listings package.
756
757 @param uf_names: The list of all user function names.
758 @type uf_names: list of str
759 """
760
761
762 file = open(self.path + sep + 'script_definition.tex', 'w')
763
764
765 py_keywords = [
766 'and',
767 'assert',
768 'break',
769 'continue',
770 'del',
771 'else',
772 'exec',
773 'global',
774 'help',
775 'if',
776 'in',
777 'is',
778 'for',
779 'not',
780 'or',
781 'pass',
782 'print',
783 'raise',
784 'return',
785 'while',
786 'yield'
787 ]
788 py_keywords2 = [
789 'as',
790 'from',
791 'import',
792 ]
793 py_keywords3 = [
794 'class',
795 'def',
796 ]
797
798
799 file.write("\lstdefinelanguage{relax}{\n")
800
801
802 file.write(" alsoletter={.>|},\n")
803
804
805 file.write(" morekeywords={")
806 for name in py_keywords:
807 file.write("%s," % name)
808 file.write("},\n")
809
810
811 file.write(" morekeywords=[2]{")
812 for name in py_keywords2:
813 file.write("%s," % name)
814 file.write("},\n")
815
816
817 file.write(" morekeywords=[3]{")
818 for name in py_keywords3:
819 file.write("%s," % name)
820 file.write("},\n")
821
822
823 file.write(" morekeywords=[4]{relax>,relax|},\n")
824
825
826 file.write(" morekeywords=[5]{")
827 for name in uf_names:
828 file.write("%s," % name)
829 file.write("},\n")
830
831
832 file.write(" moreprocnamekeys={def,class},\n")
833 file.write(" sensitive=true,\n")
834 file.write(" morecomment=[l]{\#},\n")
835 file.write(" morestring=[b]',\n")
836 file.write(" morestring=[b]\",\n")
837 file.write(" morestring=[b]\"\"\",\n")
838 file.write("}\n")
839
840
841 file.close()
842
843
845 """Determine if column wrapping should occur.
846
847 @param table: The table.
848 @type table: list of lists of str
849 @keyword max_char: The maximum number of characters a column is allowed before wrapping is applied.
850 @type max_char: int
851 @return: The list of flags for wrapping columns.
852 @rtype: list of bool
853 """
854
855
856 num_cols = len(table[0])
857 widths = [0] * num_cols
858 for i in range(len(table)):
859 for j in range(num_cols):
860
861 if len(table[i][j]) > widths[j]:
862 widths[j] = len(table[i][j])
863
864
865 wrap = []
866 for i in range(len(widths)):
867 if widths[i] > max_char:
868 wrap.append(True)
869 else:
870 wrap.append(False)
871
872
873 return wrap
874
875
909
910
912 """Format and write out an itemised list.
913
914 @param item_list: The list of items and description lists.
915 @type item_list: list of list of str
916 """
917
918
919 latex_lines = []
920 items = False
921 for i in range(len(item_list)):
922
923 item = item_list[i][0]
924 if item == None:
925 item = ''
926 if item != '':
927 items = True
928 item = self.latex_special_chars(item)
929 item = self.latex_formatting(item)
930 item = self.word_formatting(item)
931
932
933 desc = self.latex_special_chars(item_list[i][1])
934 desc = self.latex_formatting(desc)
935 desc = self.word_formatting(desc)
936
937
938 if item != '':
939 latex_lines.append("\\item[%s --] %s\n" % (item, desc))
940 else:
941 latex_lines.append("\\item[]%s\n" % desc)
942
943
944 if not items:
945 self.file.write("\\begin{itemize}\n")
946 else:
947 self.file.write("\\begin{description}\n")
948
949
950 for line in latex_lines:
951 self.file.write(line)
952
953
954 if not items:
955 self.file.write("\\end{itemize}\n\n")
956 else:
957 self.file.write("\\end{description}\n\n")
958
959
961 """Format and write out a list.
962
963 @param list: The list.
964 @type list: list of str
965 """
966
967
968 self.file.write("\\begin{itemize}\n")
969
970
971 for item in list:
972
973 item = self.latex_special_chars(item)
974 item = self.latex_formatting(item)
975 item = self.word_formatting(item)
976
977
978 self.file.write("\\item[]%s\n" % item)
979
980
981 self.file.write("\\end{itemize}\n\n")
982
983
998
999
1001 """Format and write out the prompt UI examples.
1002
1003 @param list: The list of prompt UI examples.
1004 @type list: list of str
1005 """
1006
1007
1008 for text in list:
1009
1010 self.file.write("\\begin{lstlisting}[numbers=none]\n%s\n\\end{lstlisting}\n\n" % text)
1011
1012
1013 self.file.write("\n")
1014
1015
1017 """Format and write out a table.
1018
1019 @param label: The unique table label.
1020 @type label: list of lists of str
1021 """
1022
1023
1024 table = uf_tables.get_table(label)
1025
1026
1027 self.file.write("Please see Table~\\ref{%s} on page~\\pageref{%s}.\n\n" % (label, label))
1028
1029
1030 if label in self.uf_table_labels:
1031 return
1032 else:
1033 self.uf_table_labels.append(label)
1034
1035
1036 col_wrap = self.tabular_wrapping(table.cells)
1037 wrap = sum(col_wrap)
1038
1039
1040 num_rows = len(table.cells)
1041 num_cols = len(table.headings)
1042
1043
1044 if table.longtable:
1045
1046 self.file.write("\\onecolumn\n")
1047 self.file.write("\\begin{scriptsize}\n")
1048 self.file.write("\\begin{center}\n")
1049 self.file.write("\\begin{longtable}{%s}\n" % ("l"*num_cols))
1050 else:
1051
1052 self.file.write("\\begin{table*}\n")
1053 self.file.write("\\begin{scriptsize}\n")
1054 self.file.write("\\begin{center}\n")
1055
1056
1057 self.file.write("\\caption[%s]{%s}\n" % (table.caption_short, table.caption))
1058
1059
1060 if table.longtable:
1061
1062 self.file.write("\\\\\n")
1063 self.file.write("\\toprule\n")
1064 else:
1065
1066 if wrap:
1067 self.file.write("\\begin{tabularx}{\\textwidth}{")
1068 else:
1069 self.file.write("\\begin{tabular}{")
1070 for i in range(num_cols):
1071 if col_wrap[i]:
1072 text = "X"
1073 else:
1074 text = "l"
1075 self.file.write(text)
1076 self.file.write("}\n")
1077 self.file.write("\\\\[-5pt]\n")
1078 self.file.write("\\toprule\n")
1079
1080
1081 for j in range(num_cols):
1082
1083 if j > 0:
1084 self.file.write(' & ')
1085
1086
1087 cell = table.headings[j]
1088 cell = self.latex_special_chars(cell)
1089 cell = self.latex_formatting(cell)
1090
1091
1092 self.file.write(cell)
1093
1094
1095 self.file.write(" \\\\\n")
1096
1097
1098 if table.longtable:
1099 self.file.write("\\midrule\n")
1100 self.file.write("\\endhead\n\n")
1101 self.file.write("\\bottomrule\n")
1102 self.file.write("\\endfoot\n")
1103 else:
1104
1105 self.file.write("\\midrule\n")
1106
1107
1108 if table.longtable:
1109 self.file.write("\\label{%s}\n" % label)
1110
1111
1112 for i in range(num_rows):
1113
1114 for j in range(num_cols):
1115
1116 if j > 0:
1117 self.file.write(' & ')
1118
1119
1120 cell = table.cells[i][j]
1121 cell = self.latex_special_chars(cell)
1122 cell = self.latex_formatting(cell)
1123
1124
1125 self.file.write(cell)
1126
1127
1128 self.file.write(" \\\\\n")
1129
1130
1131 if table.longtable:
1132 self.file.write("\\end{longtable}\n")
1133 self.file.write("\\end{center}\n")
1134 self.file.write("\\end{scriptsize}\n")
1135 self.file.write("\\twocolumn\n")
1136 else:
1137 self.file.write("\\bottomrule\n")
1138 self.file.write("\\\\[-5pt]\n")
1139 self.file.write("\\label{%s}\n" % label)
1140 if wrap:
1141 self.file.write("\\end{tabularx}\n")
1142 else:
1143 self.file.write("\\end{tabular}\n")
1144 self.file.write("\\end{center}\n")
1145 self.file.write("\\end{scriptsize}\n")
1146 self.file.write("\\end{table*}\n")
1147
1148
1149 self.table_count += 1
1150 self.uf_table_count += 1
1151
1152
1153 self.file.write("\n\n")
1154
1155
1157 """Format and write out the verbatim text.
1158
1159 @param text: The text to write out in a LaTeX verbatim environment.
1160 @type text: str
1161 """
1162
1163
1164 self.file.write("{\\footnotesize \\begin{verbatim}\n")
1165 self.file.write(text)
1166 self.file.write("\n\\end{verbatim}}\n\n")
1167