├── LICENSE.md ├── README.md ├── examples ├── boxes.pdf ├── boxes.py ├── boxes.tex ├── deep_architect.pdf ├── deep_architect.py ├── deep_architect.tex ├── factor_graphs.pdf ├── factor_graphs.py ├── factor_graphs.tex ├── flowchart.pdf ├── flowchart.py ├── flowchart.tex ├── lda.pdf ├── lda.py ├── lda.tex ├── pentagon.pdf ├── pentagon.py ├── pentagon.tex ├── segments.pdf ├── segments.py ├── segments.tex ├── transformer.pdf ├── transformer.py ├── transformer.tex ├── tree.pdf ├── tree.py ├── tree.tex ├── xlnet.pdf ├── xlnet.py └── xlnet.tex ├── sane_tikz ├── core.py └── formatting.py ├── setup.py └── tutorial.md /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Renato Negrinho 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | I recommend using [VS Code](https://code.visualstudio.com) with 3 | [LaTeX Workshop](https://marketplace.visualstudio.com/items?itemName=James-Yu.latex-workshop) for easily visualizing changes to figures. In preview mode, once you run the code to regenerate the tex file for the figure, the figure should update automatically in the pdf preview window. 4 | If `sane_tikz` was useful for you to create figures for your paper, consider mentioning it in the acknowledgements and share it via an issue or email or on Twitter with the hashtag #sane_tikz. 5 | See [tutorial](tutorial.md) for a high-level description of the design decisions or dive right into the examples. 6 | Use `pip install sane_tikz` to install from PyPi and `git clone https://github.com/negrinho/sane_tikz && cd sane_tikz && pip install -e .` to install from the repo. 7 | 8 | # Examples 9 | 10 | Check the [examples](https://github.com/negrinho/sane_tikz/blob/master/examples/): 11 | 12 | 13 | - segments: [[py]](https://github.com/negrinho/sane_tikz/blob/master/examples/segments.py) [[tex]](https://github.com/negrinho/sane_tikz/blob/master/examples/segments.tex) [[pdf]](https://github.com/negrinho/sane_tikz/blob/master/examples/segments.pdf) 14 | 15 |

16 | 17 | 18 | 19 |

20 | 21 | - flowchart: [[py]](https://github.com/negrinho/sane_tikz/blob/master/examples/flowchart.py) [[tex]](https://github.com/negrinho/sane_tikz/blob/master/examples/flowchart.tex) [[pdf]](https://github.com/negrinho/sane_tikz/blob/master/examples/flowchart.pdf) 22 | 23 |

24 | 25 | 26 | 27 |

28 | 29 | 30 | - pentagon: [[py]](https://github.com/negrinho/sane_tikz/blob/master/examples/pentagon.py) [[tex]](https://github.com/negrinho/sane_tikz/blob/master/examples/pentagon.tex) [[pdf]](https://github.com/negrinho/sane_tikz/blob/master/examples/pentagon.pdf) 31 | 32 |

33 | 34 | 35 | 36 |

37 | 38 | - boxes: [[py]](https://github.com/negrinho/sane_tikz/blob/master/examples/boxes.py) [[tex]](https://github.com/negrinho/sane_tikz/blob/master/examples/boxes.tex) [[pdf]](https://github.com/negrinho/sane_tikz/blob/master/examples/boxes.pdf) 39 | 40 |

41 | 42 | 43 | 44 |

45 | 46 | - lda: [[py]](https://github.com/negrinho/sane_tikz/blob/master/examples/lda.py) [[tex]](https://github.com/negrinho/sane_tikz/blob/master/examples/lda.tex) [[pdf]](https://github.com/negrinho/sane_tikz/blob/master/examples/lda.pdf) 47 | 48 |

49 | 50 | 51 | 52 |

53 | 54 | - tree: [[py]](https://github.com/negrinho/sane_tikz/blob/master/examples/tree.py) [[tex]](https://github.com/negrinho/sane_tikz/blob/master/examples/tree.tex) [[pdf]](https://github.com/negrinho/sane_tikz/blob/master/examples/tree.pdf) 55 | 56 |

57 | 58 | 59 | 60 |

61 | 62 | - transformer: [[py]](https://github.com/negrinho/sane_tikz/blob/master/examples/transformer.py) [[tex]](https://github.com/negrinho/sane_tikz/blob/master/examples/transformer.tex) [[pdf]](https://github.com/negrinho/sane_tikz/blob/master/examples/transformer.pdf) 63 | 64 |

65 | 66 | 67 | 68 |

69 | 70 | - xlnet: [[py]](https://github.com/negrinho/sane_tikz/blob/master/examples/xlnet.py) [[tex]](https://github.com/negrinho/sane_tikz/blob/master/examples/xlnet.tex) [[pdf]](https://github.com/negrinho/sane_tikz/blob/master/examples/xlnet.pdf) 71 | 72 |

73 | 74 | 75 | 76 |

77 | 78 | - deep_architect: [[py]](https://github.com/negrinho/sane_tikz/blob/master/examples/deep_architect.py) [[tex]](https://github.com/negrinho/sane_tikz/blob/master/examples/deep_architect.tex) [[pdf]](https://github.com/negrinho/sane_tikz/blob/master/examples/deep_architect.pdf) 79 | 80 |

81 | 82 | 83 | 84 |

85 | 86 | 93 | 94 | 95 | # Roadmap 96 | 97 | - Easy GIF generation 98 | - Multiple output formats (png, svg, ...) 99 | - 3D plotting 100 | - More 2D plotting primitives for common plots (bar, line, scatter, ...) 101 | - Slide deck creation (i.e., an alternative to Beamer) 102 | 103 | -------------------------------------------------------------------------------- /examples/boxes.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/negrinho/sane_tikz/fd6f291d9815613594d724678cb91ac9d412fbb7/examples/boxes.pdf -------------------------------------------------------------------------------- /examples/boxes.py: -------------------------------------------------------------------------------- 1 | # answer to latex exchange question: https://tex.stackexchange.com/questions/528846/horizontal-bar-graph-with-pgfplot-and-equal-sized-ticks/529041#529041 2 | 3 | import sane_tikz.core as stz 4 | import sane_tikz.formatting as fmt 5 | 6 | large_data = [4, 2, 1, 1, 0, 5, 4, 2, 2, 0] 7 | large_label_strs = [ 8 | "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", 9 | "Ten" 10 | ] 11 | small_data = [1, 3, 0, 5] 12 | small_label_strs = large_label_strs[:4] 13 | 14 | tick_spacing = 1.0 15 | num_ticks = 5 16 | tick_length = 0.1 17 | rectangle_height = 0.3 18 | rectangle_spacing = 0.2 19 | label_spacing = 0.1 20 | r_fmt = fmt.fill_color('gray') 21 | margin = 0.2 22 | 23 | frame_width = num_ticks * tick_spacing 24 | frame_spacing = 1.6 25 | t_fmt = fmt.line_color('gray') 26 | 27 | 28 | def get_ticks(e): 29 | top_left_cs, bottom_right_cs = stz.bbox(e) 30 | bottom_left_cs = stz.bottom_left_coords(top_left_cs, bottom_right_cs) 31 | top_ticks = [] 32 | bottom_ticks = [] 33 | for i in range(1, num_ticks): 34 | top_cs = stz.translate_coords_horizontally(top_left_cs, 35 | i * tick_spacing) 36 | top_t = stz.vertical_line_segment(top_cs, -tick_length, t_fmt) 37 | top_ticks.append(top_t) 38 | 39 | bottom_cs = stz.translate_coords_horizontally(bottom_left_cs, 40 | i * tick_spacing) 41 | bottom_t = stz.vertical_line_segment(bottom_cs, tick_length, t_fmt) 42 | bottom_ticks.append(bottom_t) 43 | return [bottom_ticks, top_ticks] 44 | 45 | 46 | def bar_plot(data, label_strs): 47 | cs = [0, 0] 48 | rs = [ 49 | stz.rectangle_from_width_and_height(cs, rectangle_height, x, r_fmt) 50 | for x in data 51 | ] 52 | 53 | stz.distribute_vertically_with_spacing(rs, rectangle_spacing) 54 | frame_height = (len(data) * rectangle_height + 55 | (len(data) - 1) * rectangle_spacing + 2.0 * margin) 56 | frame = stz.rectangle_from_width_and_height(cs, frame_height, frame_width) 57 | stz.align_centers_vertically([frame, rs], 0.0) 58 | 59 | labels = [] 60 | for i, r in enumerate(rs): 61 | l_cs = stz.coords_from_bbox_with_fn(r, stz.left_center_coords) 62 | l_cs = stz.translate_coords_horizontally(l_cs, -label_spacing) 63 | l_s = label_strs[i] 64 | lab = stz.latex(l_cs, l_s, fmt.anchor('right_center')) 65 | labels.append(lab) 66 | 67 | ticks = get_ticks(frame) 68 | return [rs, labels, frame, ticks] 69 | 70 | 71 | e_large = bar_plot(large_data, large_label_strs) 72 | e_small = bar_plot(small_data, small_label_strs) 73 | stz.distribute_horizontally_with_spacing([e_small, e_large], frame_spacing) 74 | stz.align_bottoms([e_large, e_small], 0) 75 | 76 | stz.draw_to_tikz_standalone([e_small, e_large], "boxes.tex") 77 | -------------------------------------------------------------------------------- /examples/boxes.tex: -------------------------------------------------------------------------------- 1 | \documentclass{standalone} 2 | \usepackage[T1]{fontenc}\usepackage{tikz} 3 | \usepackage{amsmath, amsfonts} 4 | \usetikzlibrary{arrows.meta} 5 | \begin{document} 6 | \begin{tikzpicture} 7 | \draw[fill=gray] (0.000000, 0.500000) -- (1.000000, 0.500000) -- (1.000000, 0.200000) -- (0.000000, 0.200000) -- cycle; 8 | \draw[fill=gray] (0.000000, 1.000000) -- (3.000000, 1.000000) -- (3.000000, 0.700000) -- (0.000000, 0.700000) -- cycle; 9 | \draw[fill=gray] (0.000000, 1.500000) -- (0.000000, 1.500000) -- (0.000000, 1.200000) -- (0.000000, 1.200000) -- cycle; 10 | \draw[fill=gray] (0.000000, 2.000000) -- (5.000000, 2.000000) -- (5.000000, 1.700000) -- (0.000000, 1.700000) -- cycle; 11 | \node[anchor=east] at (-0.100000,0.350000) {One}; 12 | \node[anchor=east] at (-0.100000,0.850000) {Two}; 13 | \node[anchor=east] at (-0.100000,1.350000) {Three}; 14 | \node[anchor=east] at (-0.100000,1.850000) {Four}; 15 | \draw[] (0.000000, 2.200000) -- (5.000000, 2.200000) -- (5.000000, 0.000000) -- (0.000000, 0.000000) -- cycle; 16 | \draw[draw=gray] (1.000000, 0.000000) -- (1.000000, 0.100000); 17 | \draw[draw=gray] (2.000000, 0.000000) -- (2.000000, 0.100000); 18 | \draw[draw=gray] (3.000000, 0.000000) -- (3.000000, 0.100000); 19 | \draw[draw=gray] (4.000000, 0.000000) -- (4.000000, 0.100000); 20 | \draw[draw=gray] (1.000000, 2.200000) -- (1.000000, 2.100000); 21 | \draw[draw=gray] (2.000000, 2.200000) -- (2.000000, 2.100000); 22 | \draw[draw=gray] (3.000000, 2.200000) -- (3.000000, 2.100000); 23 | \draw[draw=gray] (4.000000, 2.200000) -- (4.000000, 2.100000); 24 | \draw[fill=gray] (6.700000, 0.500000) -- (10.700000, 0.500000) -- (10.700000, 0.200000) -- (6.700000, 0.200000) -- cycle; 25 | \draw[fill=gray] (6.700000, 1.000000) -- (8.700000, 1.000000) -- (8.700000, 0.700000) -- (6.700000, 0.700000) -- cycle; 26 | \draw[fill=gray] (6.700000, 1.500000) -- (7.700000, 1.500000) -- (7.700000, 1.200000) -- (6.700000, 1.200000) -- cycle; 27 | \draw[fill=gray] (6.700000, 2.000000) -- (7.700000, 2.000000) -- (7.700000, 1.700000) -- (6.700000, 1.700000) -- cycle; 28 | \draw[fill=gray] (6.700000, 2.500000) -- (6.700000, 2.500000) -- (6.700000, 2.200000) -- (6.700000, 2.200000) -- cycle; 29 | \draw[fill=gray] (6.700000, 3.000000) -- (11.700000, 3.000000) -- (11.700000, 2.700000) -- (6.700000, 2.700000) -- cycle; 30 | \draw[fill=gray] (6.700000, 3.500000) -- (10.700000, 3.500000) -- (10.700000, 3.200000) -- (6.700000, 3.200000) -- cycle; 31 | \draw[fill=gray] (6.700000, 4.000000) -- (8.700000, 4.000000) -- (8.700000, 3.700000) -- (6.700000, 3.700000) -- cycle; 32 | \draw[fill=gray] (6.700000, 4.500000) -- (8.700000, 4.500000) -- (8.700000, 4.200000) -- (6.700000, 4.200000) -- cycle; 33 | \draw[fill=gray] (6.700000, 5.000000) -- (6.700000, 5.000000) -- (6.700000, 4.700000) -- (6.700000, 4.700000) -- cycle; 34 | \node[anchor=east] at (6.600000,0.350000) {One}; 35 | \node[anchor=east] at (6.600000,0.850000) {Two}; 36 | \node[anchor=east] at (6.600000,1.350000) {Three}; 37 | \node[anchor=east] at (6.600000,1.850000) {Four}; 38 | \node[anchor=east] at (6.600000,2.350000) {Five}; 39 | \node[anchor=east] at (6.600000,2.850000) {Six}; 40 | \node[anchor=east] at (6.600000,3.350000) {Seven}; 41 | \node[anchor=east] at (6.600000,3.850000) {Eight}; 42 | \node[anchor=east] at (6.600000,4.350000) {Nine}; 43 | \node[anchor=east] at (6.600000,4.850000) {Ten}; 44 | \draw[] (6.700000, 5.200000) -- (11.700000, 5.200000) -- (11.700000, 0.000000) -- (6.700000, 0.000000) -- cycle; 45 | \draw[draw=gray] (7.700000, 0.000000) -- (7.700000, 0.100000); 46 | \draw[draw=gray] (8.700000, 0.000000) -- (8.700000, 0.100000); 47 | \draw[draw=gray] (9.700000, 0.000000) -- (9.700000, 0.100000); 48 | \draw[draw=gray] (10.700000, 0.000000) -- (10.700000, 0.100000); 49 | \draw[draw=gray] (7.700000, 5.200000) -- (7.700000, 5.100000); 50 | \draw[draw=gray] (8.700000, 5.200000) -- (8.700000, 5.100000); 51 | \draw[draw=gray] (9.700000, 5.200000) -- (9.700000, 5.100000); 52 | \draw[draw=gray] (10.700000, 5.200000) -- (10.700000, 5.100000); 53 | \end{tikzpicture} 54 | \end{document} 55 | -------------------------------------------------------------------------------- /examples/deep_architect.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/negrinho/sane_tikz/fd6f291d9815613594d724678cb91ac9d412fbb7/examples/deep_architect.pdf -------------------------------------------------------------------------------- /examples/deep_architect.py: -------------------------------------------------------------------------------- 1 | # Figure 5 in https://arxiv.org/pdf/1909.13404.pdf (towards modular and programmable architecture search) 2 | 3 | import sane_tikz.core as stz 4 | import sane_tikz.formatting as fmt 5 | 6 | frame_height = 9.5 7 | frame_width = 10.0 8 | frame_spacing = 0.2 9 | frame_roundness = 0.6 10 | frame_line_width = 4.5 * fmt.standard_line_width 11 | module_height = 1.6 12 | module_width = 2.8 13 | io_height = 0.40 14 | io_long_side = 0.9 15 | io_short_side = 1.0 * io_long_side 16 | io_spacing = 0.12 17 | p_height = 1.2 * io_height 18 | p_width = 1.2 19 | p_spacing = io_spacing / 2.0 20 | h_width = 1 * p_width 21 | h_height = 1.3 * p_height 22 | h_spacing = io_spacing / 2.0 23 | io_corner_roundness = 0.0 24 | module_roundness = 0.0 25 | line_width = 2.0 * fmt.standard_line_width 26 | module_inner_vertical_spacing = 0.1 27 | delta_increment = 0.0 28 | 29 | horizontal_module_spacing = 0.2 30 | vertical_module_spacing = 0.2 31 | spacing_between_module_and_hyperp = 0.8 32 | spacing_between_hyperp_and_hyperp = 0.4 33 | arrow_length = vertical_module_spacing 34 | 35 | name2color = fmt.google_slides_named_colors() 36 | 37 | connect_s_fmt = fmt.combine_tikz_strs( 38 | [fmt.arrow_heads("end"), fmt.line_width(line_width)]) 39 | 40 | input_s_fmt = fmt.combine_tikz_strs([ 41 | fmt.line_width(line_width), 42 | ]) 43 | 44 | output_s_fmt = fmt.combine_tikz_strs([ 45 | fmt.line_width(line_width), 46 | ]) 47 | 48 | property_s_fmt = fmt.combine_tikz_strs([ 49 | fmt.line_width(line_width), 50 | ]) 51 | 52 | module_s_fmt = fmt.combine_tikz_strs([ 53 | fmt.line_width(line_width), 54 | ]) 55 | 56 | hyperp_s_fmt = fmt.combine_tikz_strs([ 57 | fmt.line_width(line_width), 58 | ]) 59 | 60 | frame_s_fmt = fmt.combine_tikz_strs([ 61 | fmt.rounded_corners(frame_roundness), 62 | fmt.line_width(frame_line_width), 63 | ]) 64 | 65 | unassigned_h_s_fmt = fmt.combine_tikz_strs([ 66 | fmt.anchor("left_center"), 67 | ]) 68 | 69 | assigned_h_s_fmt = fmt.combine_tikz_strs([ 70 | fmt.anchor("left_center"), 71 | ]) 72 | 73 | 74 | def input(name): 75 | x1 = io_short_side / 2.0 76 | x2 = io_long_side / 2.0 77 | r = stz.closed_path([[-x1, io_height], [x1, io_height], [x2, 0], [-x2, 0]], 78 | input_s_fmt) 79 | l = stz.latex(stz.center_coords(r), name) 80 | return [r, l] 81 | 82 | 83 | def output(name): 84 | x1 = io_long_side / 2.0 85 | x2 = io_short_side / 2.0 86 | r = stz.closed_path([[-x1, io_height], [x1, io_height], [x2, 0], [-x2, 0]], 87 | output_s_fmt) 88 | l = stz.latex(stz.center_coords(r), name) 89 | return [r, l] 90 | 91 | 92 | def property(name, width_scale=1.0, height_scale=1.0): 93 | e = stz.ellipse([0, 0], width_scale * p_width / 2.0, 94 | height_scale * p_height / 2.0, property_s_fmt) 95 | l = stz.latex(stz.center_coords(e), name) 96 | return [e, l] 97 | 98 | 99 | def module(module_name, 100 | input_names, 101 | output_names, 102 | hyperp_names, 103 | p_width_scale=1.0): 104 | 105 | i_lst = [input(s) for s in input_names] 106 | o_lst = [output(s) for s in output_names] 107 | m = stz.rectangle([0, 0], [module_width, -module_height], module_s_fmt) 108 | l = stz.latex(stz.center_coords(m), "\\textbf{%s}" % module_name) 109 | 110 | stz.distribute_horizontally_with_spacing(i_lst, io_spacing) 111 | stz.translate_bbox_top_left_to_coords( 112 | i_lst, [module_inner_vertical_spacing, -module_inner_vertical_spacing]) 113 | stz.distribute_horizontally_with_spacing(o_lst, io_spacing) 114 | stz.translate_bbox_bottom_left_to_coords(o_lst, [ 115 | module_inner_vertical_spacing, 116 | -module_height + module_inner_vertical_spacing 117 | ]) 118 | 119 | if len(hyperp_names) > 0: 120 | h_lst = [property(s, p_width_scale) for s in hyperp_names] 121 | stz.distribute_vertically_with_spacing(h_lst, p_spacing) 122 | stz.translate_bbox_top_right_to_coords(h_lst, [ 123 | module_width - module_inner_vertical_spacing, 124 | -module_inner_vertical_spacing - delta_increment 125 | ]) 126 | return [[m, l], i_lst, o_lst, h_lst] 127 | else: 128 | return [[m, l], i_lst, o_lst] 129 | 130 | 131 | def independent_hyperparameter(name, values_expr, value=None): 132 | 133 | e = stz.ellipse([0, 0], h_width / 2.0, h_height / 2.0, hyperp_s_fmt) 134 | l = stz.latex(stz.center_coords(e), "\\textbf{%s}" % name) 135 | fn_cs = stz.coords_from_bbox_with_fn(e, stz.right_center_coords) 136 | if value is None: 137 | l_vs = stz.latex(fn_cs, "\\textbf{[%s]}" % (values_expr,), 138 | unassigned_h_s_fmt) 139 | return [e, l, l_vs] 140 | else: 141 | v_cs = stz.coords_from_bbox_with_fn(e, stz.right_center_coords) 142 | l_v = stz.latex(v_cs, "\\textbf{%s}" % value, assigned_h_s_fmt) 143 | return [e, l, l_v] 144 | 145 | 146 | def dependent_hyperparameter(name, hyperp_names, fn_expr, value=None): 147 | e = stz.ellipse([0, 0], h_width / 2.0, h_height / 2.0, hyperp_s_fmt) 148 | if value is None: 149 | e["horizontal_radius"] *= 2.1 * e["horizontal_radius"] 150 | 151 | l_cs = stz.center_coords(e) 152 | if value is None: 153 | l_cs = stz.translate_coords_horizontally(l_cs, 0.1) 154 | l = stz.latex(l_cs, "\\textbf{%s}" % name) 155 | 156 | if value is None: 157 | fn_cs = stz.coords_from_bbox_with_fn(e, stz.right_center_coords) 158 | l_fn = stz.latex(fn_cs, "\\textbf{fn: %s}" % (fn_expr,), 159 | unassigned_h_s_fmt) 160 | 161 | p = property("x", 0.25, 0.7) 162 | p_cs = stz.translate_coords_horizontally( 163 | stz.coords_from_bbox_with_fn(e, stz.left_center_coords), 0.1) 164 | stz.translate_bbox_left_center_to_coords(p, p_cs) 165 | return [e, l, l_fn, p] 166 | else: 167 | v_cs = stz.coords_from_bbox_with_fn(e, stz.right_center_coords) 168 | l_v = stz.latex(v_cs, "\\textbf{%s}" % value, assigned_h_s_fmt) 169 | return [e, l, l_v] 170 | 171 | 172 | def dense(idx): 173 | return module("Dense-%d" % idx, ["in"], ["out"], ["units"]) 174 | 175 | 176 | def conv2d(idx): 177 | return module("Conv2D-%d" % idx, ["in"], ["out"], ["filters"], 1.1) 178 | 179 | 180 | def dropout(idx): 181 | return module("Dropout-%d" % idx, ["in"], ["out"], ["prob"], 0.9) 182 | 183 | 184 | def optional(idx): 185 | return module("Optional-%d" % idx, ["in"], ["out"], ["opt"]) 186 | 187 | 188 | def concat(idx): 189 | return module("Concat-%d" % idx, ["in0", "in1"], ["out"], []) 190 | 191 | 192 | def repeat(idx): 193 | return module("Repeat-%d" % idx, ["in"], ["out"], ["k"], 0.5) 194 | 195 | 196 | def connect_modules(m_from, m_to, output_idx, input_idx): 197 | return stz.line_segment( 198 | stz.coords_from_bbox_with_fn(m_from[2][output_idx], 199 | stz.bottom_center_coords), 200 | stz.coords_from_bbox_with_fn(m_to[1][input_idx], stz.top_center_coords), 201 | connect_s_fmt) 202 | 203 | 204 | def connect_hyperp_to_module(h, m, property_idx): 205 | return stz.line_segment( 206 | stz.coords_from_bbox_with_fn(h[:2], stz.left_center_coords), 207 | stz.coords_from_bbox_with_fn(m[3][property_idx], 208 | stz.right_center_coords), connect_s_fmt) 209 | 210 | 211 | def connect_hyperp_to_hyperp(h_from, h_to): 212 | return stz.line_segment( 213 | stz.coords_from_bbox_with_fn(h_from[:2], stz.right_center_coords), 214 | stz.coords_from_bbox_with_fn(h_to[3], stz.top_center_coords), 215 | connect_s_fmt) 216 | 217 | 218 | def frame(frame_idx): 219 | assert frame_idx >= 0 and frame_idx <= 3 220 | c1 = conv2d(1) 221 | o = optional(1) 222 | r1 = repeat(1) 223 | r2 = repeat(2) 224 | cc = concat(1) 225 | c2 = conv2d(2) 226 | c3 = conv2d(3) 227 | c4 = conv2d(4) 228 | d = dropout(1) 229 | 230 | stz.distribute_horizontally_with_spacing([r1, r2], 231 | horizontal_module_spacing) 232 | stz.distribute_horizontally_with_spacing([c2, [c3, c4]], 233 | horizontal_module_spacing) 234 | 235 | modules = [] 236 | if frame_idx == 0: 237 | stz.distribute_vertically_with_spacing([cc, [r1, r2], o, c1], 238 | vertical_module_spacing) 239 | 240 | stz.align_centers_horizontally([cc, [r1, r2], o, c1], 0) 241 | modules.extend([c1, o, r1, r2, cc]) 242 | 243 | else: 244 | stz.distribute_vertically_with_spacing([c4, c3], 245 | vertical_module_spacing) 246 | stz.distribute_horizontally_with_spacing([c2, [c3, c4]], 247 | horizontal_module_spacing) 248 | stz.align_centers_vertically([[c3, c4], c2], 0) 249 | 250 | if frame_idx == 1: 251 | stz.distribute_vertically_with_spacing([cc, [c2, c3, c4], o, c1], 252 | vertical_module_spacing) 253 | stz.align_centers_horizontally([cc, [c2, c3, c4], o, c1], 0) 254 | modules.extend([c1, o, c2, c3, c4, cc]) 255 | 256 | else: 257 | stz.distribute_vertically_with_spacing([cc, [c2, c3, c4], d, c1], 258 | vertical_module_spacing) 259 | stz.align_centers_horizontally([cc, [c2, c3, c4], d, c1], 0) 260 | modules.extend([c1, d, c2, c3, c4, cc]) 261 | 262 | module_connections = [] 263 | if frame_idx == 0: 264 | module_connections.extend([ 265 | connect_modules(c1, o, 0, 0), 266 | connect_modules(o, r1, 0, 0), 267 | connect_modules(o, r2, 0, 0), 268 | connect_modules(r1, cc, 0, 0), 269 | connect_modules(r2, cc, 0, 1), 270 | ]) 271 | 272 | else: 273 | if frame_idx == 1: 274 | module_connections.extend([ 275 | connect_modules(c1, o, 0, 0), 276 | connect_modules(o, c2, 0, 0), 277 | connect_modules(o, c3, 0, 0), 278 | ]) 279 | else: 280 | module_connections.extend([ 281 | connect_modules(c1, d, 0, 0), 282 | connect_modules(d, c2, 0, 0), 283 | connect_modules(d, c3, 0, 0), 284 | ]) 285 | 286 | module_connections.extend([ 287 | connect_modules(c3, c4, 0, 0), 288 | connect_modules(c2, cc, 0, 0), 289 | connect_modules(c4, cc, 0, 1), 290 | ]) 291 | 292 | # # hyperparameters 293 | if frame_idx <= 1: 294 | h_o = independent_hyperparameter("IH-2", "0, 1") 295 | else: 296 | h_o = independent_hyperparameter("IH-2", "0, 1", "1") 297 | 298 | if frame_idx <= 0: 299 | h_r1 = dependent_hyperparameter("DH-1", ["x"], "2*x") 300 | h_r2 = independent_hyperparameter("IH-3", "1, 2, 4") 301 | else: 302 | h_r1 = dependent_hyperparameter("DH-1", ["x"], "2*x", "2") 303 | h_r2 = independent_hyperparameter("IH-3", "1, 2, 4", "1") 304 | 305 | if frame_idx <= 2: 306 | h_c1 = independent_hyperparameter("IH-1", "64, 128") 307 | h_c2 = independent_hyperparameter("IH-4", "64, 128") 308 | h_c3 = independent_hyperparameter("IH-5", "64, 128") 309 | h_c4 = independent_hyperparameter("IH-6", "64, 128") 310 | h_d = independent_hyperparameter("IH-7", "0.25, 0.5") 311 | else: 312 | h_c1 = independent_hyperparameter("IH-1", "64, 128", "64") 313 | h_c2 = independent_hyperparameter("IH-4", "64, 128", "128") 314 | h_c3 = independent_hyperparameter("IH-5", "64, 128", "128") 315 | h_c4 = independent_hyperparameter("IH-6", "64, 128", "64") 316 | h_d = independent_hyperparameter("IH-7", "0.25, 0.5", "0.5") 317 | 318 | def place_hyperp_right_of(h, m): 319 | y_p = stz.center_coords(m[3])[1] 320 | stz.align_centers_vertically([h], y_p) 321 | stz.place_to_the_right(h, m, spacing_between_module_and_hyperp) 322 | 323 | hyperparameters = [] 324 | place_hyperp_right_of(h_c1, c1) 325 | if frame_idx in [0, 1]: 326 | place_hyperp_right_of(h_o, o) 327 | hyperparameters.append(h_o) 328 | 329 | if frame_idx == 0: 330 | place_hyperp_right_of(h_r1, r2) 331 | stz.place_above_and_align_to_the_right(h_r2, h_r1, 0.8) 332 | hyperparameters.extend([h_r1, h_r2, h_c1]) 333 | else: 334 | place_hyperp_right_of(h_c1, c1) 335 | place_hyperp_right_of(h_c3, c3) 336 | place_hyperp_right_of(h_c4, c4) 337 | stz.place_below(h_c2, h_c1, 3.0) 338 | hyperparameters.extend([h_c1, h_c2, h_c3, h_c4]) 339 | 340 | if frame_idx in [2, 3]: 341 | place_hyperp_right_of(h_d, d) 342 | hyperparameters.extend([h_d]) 343 | 344 | unreachable_hyperps = [] 345 | if frame_idx == 1: 346 | stz.distribute_vertically_with_spacing([h_r1, h_r2], 0.2) 347 | unreachable_hyperps.extend([h_r1, h_r2]) 348 | if frame_idx >= 2: 349 | stz.distribute_vertically_with_spacing([h_o, h_r1, h_r2], 0.2) 350 | unreachable_hyperps.extend([h_r1, h_r2, h_o]) 351 | hyperparameters.extend(unreachable_hyperps) 352 | 353 | cs_fn = lambda e: stz.coords_from_bbox_with_fn(e, stz.left_center_coords) 354 | if frame_idx == 0: 355 | 356 | stz.translate_bbox_left_center_to_coords(h_r2, cs_fn([h_o, h_r1])) 357 | elif frame_idx == 1: 358 | stz.translate_bbox_left_center_to_coords(h_c2, cs_fn([h_o, h_c3])) 359 | else: 360 | stz.translate_bbox_left_center_to_coords(h_c2, cs_fn([h_d, h_c3])) 361 | 362 | hyperp_connections = [ 363 | connect_hyperp_to_module(h_c1, c1, 0), 364 | ] 365 | if frame_idx in [0, 1]: 366 | hyperp_connections.extend([connect_hyperp_to_module(h_o, o, 0)]) 367 | if frame_idx == 0: 368 | hyperp_connections.extend([ 369 | connect_hyperp_to_module(h_r1, r2, 0), 370 | connect_hyperp_to_module(h_r2, r1, 0), 371 | connect_hyperp_to_hyperp(h_r2, h_r1) 372 | ]) 373 | else: 374 | hyperp_connections.extend([ 375 | connect_hyperp_to_module(h_c2, c2, 0), 376 | connect_hyperp_to_module(h_c3, c3, 0), 377 | connect_hyperp_to_module(h_c4, c4, 0), 378 | ]) 379 | if frame_idx in [2, 3]: 380 | hyperp_connections.append(connect_hyperp_to_module(h_d, d, 0)) 381 | 382 | f = stz.rectangle_from_width_and_height([0, 0], frame_height, frame_width, 383 | frame_s_fmt) 384 | e = [modules, module_connections, hyperparameters, hyperp_connections] 385 | stz.translate_bbox_center_to_coords( 386 | f, stz.translate_coords_horizontally(stz.center_coords(e), 0.8)) 387 | if len(unreachable_hyperps) > 0: 388 | stz.translate_bbox_bottom_right_to_coords(unreachable_hyperps, 389 | stz.bbox(e)[1]) 390 | 391 | # frame id 392 | s = ["a", "b", "c", "d"][frame_idx] 393 | label = [stz.latex([0, 0], "\\Huge \\textbf %s" % s)] 394 | stz.translate_bbox_top_left_to_coords( 395 | label, 396 | stz.translate_coords_antidiagonally( 397 | stz.coords_from_bbox_with_fn(f, stz.top_left_coords), 0.6)) 398 | 399 | return e + [f, label] 400 | 401 | 402 | def search_space_transition(): 403 | 404 | e0 = frame(0) 405 | e1 = frame(1) 406 | e2 = frame(2) 407 | e3 = frame(3) 408 | e = [e0, e1, e2, e3] 409 | 410 | def get_idx(e_frame, indices): 411 | e = e_frame 412 | for idx in indices: 413 | e = e[idx] 414 | return e 415 | 416 | def highlight(e_frame, indices, idx, color): 417 | e = get_idx(e_frame, indices) 418 | s_fmt = fmt.combine_tikz_strs([e["tikz_str"], fmt.fill_color(color)]) 419 | e['tikz_str'] = s_fmt 420 | 421 | # highlight new modules 422 | highlight(e1, [0, 2, 0, 0], 0, "light_green_2") 423 | highlight(e1, [0, 3, 0, 0], 0, "light_green_2") 424 | highlight(e1, [0, 4, 0, 0], 0, "light_green_2") 425 | highlight(e2, [0, 1, 0, 0], 0, "light_green_2") 426 | 427 | # highlight new hyperparameters 428 | highlight(e1, [2, 2, 0], 0, "light_green_2") 429 | highlight(e1, [2, 3, 0], 0, "light_green_2") 430 | highlight(e1, [2, 4, 0], 0, "light_green_2") 431 | highlight(e2, [2, 4, 0], 0, "light_green_2") 432 | 433 | # highlight assigned hyperparameters 434 | highlight(e1, [2, 5, 0], 0, "light_red_2") 435 | highlight(e1, [2, 6, 0], 0, "light_red_2") 436 | highlight(e2, [2, 7, 0], 0, "light_red_2") 437 | highlight(e3, [2, 0, 0], 0, "light_red_2") 438 | highlight(e3, [2, 1, 0], 0, "light_red_2") 439 | highlight(e3, [2, 2, 0], 0, "light_red_2") 440 | highlight(e3, [2, 3, 0], 0, "light_red_2") 441 | highlight(e3, [2, 4, 0], 0, "light_red_2") 442 | 443 | # arrange the four frames 444 | stz.align_tops(e, 0.0) 445 | stz.distribute_horizontally_with_spacing([e0, e1], frame_spacing) 446 | stz.distribute_horizontally_with_spacing([e2, e3], frame_spacing) 447 | stz.distribute_vertically_with_spacing([[e2, e3], [e0, e1]], frame_spacing) 448 | 449 | stz.draw_to_tikz_standalone(e, "deep_architect.tex", name2color) 450 | 451 | 452 | search_space_transition() 453 | -------------------------------------------------------------------------------- /examples/deep_architect.tex: -------------------------------------------------------------------------------- 1 | \documentclass{standalone} 2 | \usepackage[T1]{fontenc}\usepackage{tikz} 3 | \usepackage{amsmath, amsfonts} 4 | \usetikzlibrary{arrows.meta} 5 | \begin{document} 6 | \begin{tikzpicture} 7 | \definecolor{dark_purple_1}{RGB}{103,77,167} 8 | \definecolor{light_green_1}{RGB}{147,196,124} 9 | \definecolor{light_green_2}{RGB}{182,215,168} 10 | \definecolor{light_green_3}{RGB}{217,234,211} 11 | \definecolor{dark_red_berry_3}{RGB}{91,15,0} 12 | \definecolor{light_blue_1}{RGB}{111,168,220} 13 | \definecolor{dark_orange_1}{RGB}{230,144,56} 14 | \definecolor{dark_purple_3}{RGB}{32,18,77} 15 | \definecolor{yellow}{RGB}{253,255,1} 16 | \definecolor{dark_green_1}{RGB}{106,168,78} 17 | \definecolor{dark_red_berry_1}{RGB}{166,28,0} 18 | \definecolor{dark_red_berry_2}{RGB}{132,33,11} 19 | \definecolor{dark_purple_2}{RGB}{53,29,116} 20 | \definecolor{light_blue_2}{RGB}{159,197,232} 21 | \definecolor{light_blue_3}{RGB}{208,226,243} 22 | \definecolor{cyan}{RGB}{83,255,255} 23 | \definecolor{dark_magenta_3}{RGB}{76,16,48} 24 | \definecolor{magenta}{RGB}{247,0,255} 25 | \definecolor{blue}{RGB}{38,1,255} 26 | \definecolor{dark_cornflower_blue_1}{RGB}{60,120,216} 27 | \definecolor{light_red_2}{RGB}{234,153,153} 28 | \definecolor{light_red_3}{RGB}{244,204,205} 29 | \definecolor{light_red_1}{RGB}{224,101,102} 30 | \definecolor{purple}{RGB}{153,1,254} 31 | \definecolor{dark_red_3}{RGB}{101,1,0} 32 | \definecolor{dark_green_3}{RGB}{39,78,18} 33 | \definecolor{light_purple_1}{RGB}{142,123,195} 34 | \definecolor{dark_red_2}{RGB}{153,3,0} 35 | \definecolor{light_cornflower_blue_1}{RGB}{109,157,235} 36 | \definecolor{red_berry}{RGB}{151,3,0} 37 | \definecolor{light_cornflower_blue_3}{RGB}{202,218,248} 38 | \definecolor{light_cornflower_blue_2}{RGB}{164,194,244} 39 | \definecolor{black}{RGB}{0,0,0} 40 | \definecolor{dark_red_1}{RGB}{205,5,0} 41 | \definecolor{orange}{RGB}{247,153,4} 42 | \definecolor{white}{RGB}{255,255,255} 43 | \definecolor{red}{RGB}{245,8,2} 44 | \definecolor{dark_cyan_1}{RGB}{69,129,142} 45 | \definecolor{dark_cyan_2}{RGB}{21,79,92} 46 | \definecolor{dark_cyan_3}{RGB}{12,52,61} 47 | \definecolor{dark_yellow_2}{RGB}{191,144,0} 48 | \definecolor{dark_blue_1}{RGB}{61,132,198} 49 | \definecolor{dark_blue_3}{RGB}{15,55,99} 50 | \definecolor{dark_blue_2}{RGB}{28,82,148} 51 | \definecolor{light_magenta_2}{RGB}{213,166,189} 52 | \definecolor{light_magenta_3}{RGB}{234,209,220} 53 | \definecolor{light_orange_1}{RGB}{246,179,107} 54 | \definecolor{dark_grey_4}{RGB}{67,67,67} 55 | \definecolor{dark_orange_3}{RGB}{120,63,4} 56 | \definecolor{dark_grey_2}{RGB}{153,153,153} 57 | \definecolor{dark_grey_3}{RGB}{102,102,102} 58 | \definecolor{light_grey_3}{RGB}{239,239,239} 59 | \definecolor{light_grey_2}{RGB}{217,217,217} 60 | \definecolor{light_grey_1}{RGB}{204,204,204} 61 | \definecolor{light_magenta_1}{RGB}{194,123,160} 62 | \definecolor{light_cyan_3}{RGB}{208,224,228} 63 | \definecolor{light_cyan_2}{RGB}{162,196,201} 64 | \definecolor{light_cyan_1}{RGB}{118,165,175} 65 | \definecolor{light_orange_3}{RGB}{252,229,205} 66 | \definecolor{dark_yellow_3}{RGB}{127,96,0} 67 | \definecolor{cornflower_blue}{RGB}{74,134,232} 68 | \definecolor{dark_yellow_1}{RGB}{241,194,51} 69 | \definecolor{dark_cornflower_blue_3}{RGB}{28,68,134} 70 | \definecolor{dark_green_2}{RGB}{56,118,29} 71 | \definecolor{dark_magenta_2}{RGB}{115,27,70} 72 | \definecolor{dark_magenta_1}{RGB}{166,77,120} 73 | \definecolor{light_purple_2}{RGB}{180,167,214} 74 | \definecolor{light_purple_3}{RGB}{217,210,233} 75 | \definecolor{light_red_berry_3}{RGB}{230,184,175} 76 | \definecolor{light_red_berry_2}{RGB}{221,125,106} 77 | \definecolor{grey}{RGB}{183,183,183} 78 | \definecolor{light_red_berry_1}{RGB}{204,65,37} 79 | \definecolor{light_orange_2}{RGB}{249,203,156} 80 | \definecolor{green}{RGB}{74,255,0} 81 | \definecolor{dark_orange_2}{RGB}{180,94,6} 82 | \definecolor{light_yellow_1}{RGB}{251,218,101} 83 | \definecolor{light_yellow_2}{RGB}{252,230,153} 84 | \definecolor{light_yellow_3}{RGB}{253,242,204} 85 | \definecolor{dark_cornflower_blue_2}{RGB}{36,85,204} 86 | \draw[line width=0.031250cm] (-1.556000, -1.250000) -- (1.244000, -1.250000) -- (1.244000, -2.850000) -- (-1.556000, -2.850000) -- cycle; 87 | \node[] at (-0.156000,-2.050000) {\textbf{Conv2D-1}}; 88 | \draw[line width=0.031250cm] (-1.456000, -1.350000) -- (-0.556000, -1.350000) -- (-0.556000, -1.750000) -- (-1.456000, -1.750000) -- cycle; 89 | \node[] at (-1.006000,-1.550000) {in}; 90 | \draw[line width=0.031250cm] (-1.456000, -2.350000) -- (-0.556000, -2.350000) -- (-0.556000, -2.750000) -- (-1.456000, -2.750000) -- cycle; 91 | \node[] at (-1.006000,-2.550000) {out}; 92 | \draw[line width=0.031250cm] (0.484000, -1.590000) ellipse (0.660000 and 0.240000); 93 | \node[] at (0.484000,-1.590000) {filters}; 94 | \draw[line width=0.031250cm] (-1.556000, -3.050000) -- (1.244000, -3.050000) -- (1.244000, -4.650000) -- (-1.556000, -4.650000) -- cycle; 95 | \node[] at (-0.156000,-3.850000) {\textbf{Optional-1}}; 96 | \draw[line width=0.031250cm] (-1.456000, -3.150000) -- (-0.556000, -3.150000) -- (-0.556000, -3.550000) -- (-1.456000, -3.550000) -- cycle; 97 | \node[] at (-1.006000,-3.350000) {in}; 98 | \draw[line width=0.031250cm] (-1.456000, -4.150000) -- (-0.556000, -4.150000) -- (-0.556000, -4.550000) -- (-1.456000, -4.550000) -- cycle; 99 | \node[] at (-1.006000,-4.350000) {out}; 100 | \draw[line width=0.031250cm] (0.544000, -3.390000) ellipse (0.600000 and 0.240000); 101 | \node[] at (0.544000,-3.390000) {opt}; 102 | \draw[line width=0.031250cm] (-3.056000, -4.850000) -- (-0.256000, -4.850000) -- (-0.256000, -6.450000) -- (-3.056000, -6.450000) -- cycle; 103 | \node[] at (-1.656000,-5.650000) {\textbf{Repeat-1}}; 104 | \draw[line width=0.031250cm] (-2.956000, -4.950000) -- (-2.056000, -4.950000) -- (-2.056000, -5.350000) -- (-2.956000, -5.350000) -- cycle; 105 | \node[] at (-2.506000,-5.150000) {in}; 106 | \draw[line width=0.031250cm] (-2.956000, -5.950000) -- (-2.056000, -5.950000) -- (-2.056000, -6.350000) -- (-2.956000, -6.350000) -- cycle; 107 | \node[] at (-2.506000,-6.150000) {out}; 108 | \draw[line width=0.031250cm] (-0.656000, -5.190000) ellipse (0.300000 and 0.240000); 109 | \node[] at (-0.656000,-5.190000) {k}; 110 | \draw[line width=0.031250cm] (-0.056000, -4.850000) -- (2.744000, -4.850000) -- (2.744000, -6.450000) -- (-0.056000, -6.450000) -- cycle; 111 | \node[] at (1.344000,-5.650000) {\textbf{Repeat-2}}; 112 | \draw[line width=0.031250cm] (0.044000, -4.950000) -- (0.944000, -4.950000) -- (0.944000, -5.350000) -- (0.044000, -5.350000) -- cycle; 113 | \node[] at (0.494000,-5.150000) {in}; 114 | \draw[line width=0.031250cm] (0.044000, -5.950000) -- (0.944000, -5.950000) -- (0.944000, -6.350000) -- (0.044000, -6.350000) -- cycle; 115 | \node[] at (0.494000,-6.150000) {out}; 116 | \draw[line width=0.031250cm] (2.344000, -5.190000) ellipse (0.300000 and 0.240000); 117 | \node[] at (2.344000,-5.190000) {k}; 118 | \draw[line width=0.031250cm] (-1.556000, -6.650000) -- (1.244000, -6.650000) -- (1.244000, -8.250000) -- (-1.556000, -8.250000) -- cycle; 119 | \node[] at (-0.156000,-7.450000) {\textbf{Concat-1}}; 120 | \draw[line width=0.031250cm] (-1.456000, -6.750000) -- (-0.556000, -6.750000) -- (-0.556000, -7.150000) -- (-1.456000, -7.150000) -- cycle; 121 | \node[] at (-1.006000,-6.950000) {in0}; 122 | \draw[line width=0.031250cm] (-0.436000, -6.750000) -- (0.464000, -6.750000) -- (0.464000, -7.150000) -- (-0.436000, -7.150000) -- cycle; 123 | \node[] at (0.014000,-6.950000) {in1}; 124 | \draw[line width=0.031250cm] (-1.456000, -7.750000) -- (-0.556000, -7.750000) -- (-0.556000, -8.150000) -- (-1.456000, -8.150000) -- cycle; 125 | \node[] at (-1.006000,-7.950000) {out}; 126 | \draw[-latex, line width=0.031250cm] (-1.006000, -2.750000) -- (-1.006000, -3.150000); 127 | \draw[-latex, line width=0.031250cm] (-1.006000, -4.550000) -- (-2.506000, -4.950000); 128 | \draw[-latex, line width=0.031250cm] (-1.006000, -4.550000) -- (0.494000, -4.950000); 129 | \draw[-latex, line width=0.031250cm] (-2.506000, -6.350000) -- (-1.006000, -6.750000); 130 | \draw[-latex, line width=0.031250cm] (0.494000, -6.350000) -- (0.014000, -6.750000); 131 | \draw[line width=0.031250cm] (2.644000, -3.390000) ellipse (0.600000 and 0.312000); 132 | \node[] at (2.644000,-3.390000) {\textbf{IH-2}}; 133 | \node[anchor=west] at (3.244000,-3.390000) {\textbf{[0, 1]}}; 134 | \draw[line width=0.031250cm] (4.300000, -5.190000) ellipse (0.756000 and 0.312000); 135 | \node[] at (4.400000,-5.190000) {\textbf{DH-1}}; 136 | \node[anchor=west] at (5.056000,-5.190000) {\textbf{fn: 2*x}}; 137 | \draw[line width=0.031250cm] (3.794000, -5.190000) ellipse (0.150000 and 0.168000); 138 | \node[] at (3.794000,-5.190000) {x}; 139 | \draw[line width=0.031250cm] (2.644000, -4.290000) ellipse (0.600000 and 0.312000); 140 | \node[] at (2.644000,-4.290000) {\textbf{IH-3}}; 141 | \node[anchor=west] at (3.244000,-4.290000) {\textbf{[1, 2, 4]}}; 142 | \draw[line width=0.031250cm] (2.644000, -1.590000) ellipse (0.600000 and 0.312000); 143 | \node[] at (2.644000,-1.590000) {\textbf{IH-1}}; 144 | \node[anchor=west] at (3.244000,-1.590000) {\textbf{[64, 128]}}; 145 | \draw[-latex, line width=0.031250cm] (2.044000, -1.590000) -- (1.144000, -1.590000); 146 | \draw[-latex, line width=0.031250cm] (2.044000, -3.390000) -- (1.144000, -3.390000); 147 | \draw[-latex, line width=0.031250cm] (3.544000, -5.190000) -- (2.644000, -5.190000); 148 | \draw[-latex, line width=0.031250cm] (2.044000, -4.290000) -- (-0.356000, -5.190000); 149 | \draw[-latex, line width=0.031250cm] (3.244000, -4.290000) -- (3.794000, -5.022000); 150 | \draw[rounded corners=0.600000cm, line width=0.070312cm] (-3.200000, 0.000000) -- (6.800000, 0.000000) -- (6.800000, -9.500000) -- (-3.200000, -9.500000) -- cycle; 151 | \node[] at (-2.600000,-0.600000) {\Huge \textbf a}; 152 | \draw[line width=0.031250cm] (8.800000, -0.350000) -- (11.600000, -0.350000) -- (11.600000, -1.950000) -- (8.800000, -1.950000) -- cycle; 153 | \node[] at (10.200000,-1.150000) {\textbf{Conv2D-1}}; 154 | \draw[line width=0.031250cm] (8.900000, -0.450000) -- (9.800000, -0.450000) -- (9.800000, -0.850000) -- (8.900000, -0.850000) -- cycle; 155 | \node[] at (9.350000,-0.650000) {in}; 156 | \draw[line width=0.031250cm] (8.900000, -1.450000) -- (9.800000, -1.450000) -- (9.800000, -1.850000) -- (8.900000, -1.850000) -- cycle; 157 | \node[] at (9.350000,-1.650000) {out}; 158 | \draw[line width=0.031250cm] (10.840000, -0.690000) ellipse (0.660000 and 0.240000); 159 | \node[] at (10.840000,-0.690000) {filters}; 160 | \draw[line width=0.031250cm] (8.800000, -2.150000) -- (11.600000, -2.150000) -- (11.600000, -3.750000) -- (8.800000, -3.750000) -- cycle; 161 | \node[] at (10.200000,-2.950000) {\textbf{Optional-1}}; 162 | \draw[line width=0.031250cm] (8.900000, -2.250000) -- (9.800000, -2.250000) -- (9.800000, -2.650000) -- (8.900000, -2.650000) -- cycle; 163 | \node[] at (9.350000,-2.450000) {in}; 164 | \draw[line width=0.031250cm] (8.900000, -3.250000) -- (9.800000, -3.250000) -- (9.800000, -3.650000) -- (8.900000, -3.650000) -- cycle; 165 | \node[] at (9.350000,-3.450000) {out}; 166 | \draw[line width=0.031250cm] (10.900000, -2.490000) ellipse (0.600000 and 0.240000); 167 | \node[] at (10.900000,-2.490000) {opt}; 168 | \draw[line width=0.031250cm, fill=light_green_2] (7.300000, -4.850000) -- (10.100000, -4.850000) -- (10.100000, -6.450000) -- (7.300000, -6.450000) -- cycle; 169 | \node[] at (8.700000,-5.650000) {\textbf{Conv2D-2}}; 170 | \draw[line width=0.031250cm] (7.400000, -4.950000) -- (8.300000, -4.950000) -- (8.300000, -5.350000) -- (7.400000, -5.350000) -- cycle; 171 | \node[] at (7.850000,-5.150000) {in}; 172 | \draw[line width=0.031250cm] (7.400000, -5.950000) -- (8.300000, -5.950000) -- (8.300000, -6.350000) -- (7.400000, -6.350000) -- cycle; 173 | \node[] at (7.850000,-6.150000) {out}; 174 | \draw[line width=0.031250cm] (9.340000, -5.190000) ellipse (0.660000 and 0.240000); 175 | \node[] at (9.340000,-5.190000) {filters}; 176 | \draw[line width=0.031250cm, fill=light_green_2] (10.300000, -3.950000) -- (13.100000, -3.950000) -- (13.100000, -5.550000) -- (10.300000, -5.550000) -- cycle; 177 | \node[] at (11.700000,-4.750000) {\textbf{Conv2D-3}}; 178 | \draw[line width=0.031250cm] (10.400000, -4.050000) -- (11.300000, -4.050000) -- (11.300000, -4.450000) -- (10.400000, -4.450000) -- cycle; 179 | \node[] at (10.850000,-4.250000) {in}; 180 | \draw[line width=0.031250cm] (10.400000, -5.050000) -- (11.300000, -5.050000) -- (11.300000, -5.450000) -- (10.400000, -5.450000) -- cycle; 181 | \node[] at (10.850000,-5.250000) {out}; 182 | \draw[line width=0.031250cm] (12.340000, -4.290000) ellipse (0.660000 and 0.240000); 183 | \node[] at (12.340000,-4.290000) {filters}; 184 | \draw[line width=0.031250cm, fill=light_green_2] (10.300000, -5.750000) -- (13.100000, -5.750000) -- (13.100000, -7.350000) -- (10.300000, -7.350000) -- cycle; 185 | \node[] at (11.700000,-6.550000) {\textbf{Conv2D-4}}; 186 | \draw[line width=0.031250cm] (10.400000, -5.850000) -- (11.300000, -5.850000) -- (11.300000, -6.250000) -- (10.400000, -6.250000) -- cycle; 187 | \node[] at (10.850000,-6.050000) {in}; 188 | \draw[line width=0.031250cm] (10.400000, -6.850000) -- (11.300000, -6.850000) -- (11.300000, -7.250000) -- (10.400000, -7.250000) -- cycle; 189 | \node[] at (10.850000,-7.050000) {out}; 190 | \draw[line width=0.031250cm] (12.340000, -6.090000) ellipse (0.660000 and 0.240000); 191 | \node[] at (12.340000,-6.090000) {filters}; 192 | \draw[line width=0.031250cm] (8.800000, -7.550000) -- (11.600000, -7.550000) -- (11.600000, -9.150000) -- (8.800000, -9.150000) -- cycle; 193 | \node[] at (10.200000,-8.350000) {\textbf{Concat-1}}; 194 | \draw[line width=0.031250cm] (8.900000, -7.650000) -- (9.800000, -7.650000) -- (9.800000, -8.050000) -- (8.900000, -8.050000) -- cycle; 195 | \node[] at (9.350000,-7.850000) {in0}; 196 | \draw[line width=0.031250cm] (9.920000, -7.650000) -- (10.820000, -7.650000) -- (10.820000, -8.050000) -- (9.920000, -8.050000) -- cycle; 197 | \node[] at (10.370000,-7.850000) {in1}; 198 | \draw[line width=0.031250cm] (8.900000, -8.650000) -- (9.800000, -8.650000) -- (9.800000, -9.050000) -- (8.900000, -9.050000) -- cycle; 199 | \node[] at (9.350000,-8.850000) {out}; 200 | \draw[-latex, line width=0.031250cm] (9.350000, -1.850000) -- (9.350000, -2.250000); 201 | \draw[-latex, line width=0.031250cm] (9.350000, -3.650000) -- (7.850000, -4.950000); 202 | \draw[-latex, line width=0.031250cm] (9.350000, -3.650000) -- (10.850000, -4.050000); 203 | \draw[-latex, line width=0.031250cm] (10.850000, -5.450000) -- (10.850000, -5.850000); 204 | \draw[-latex, line width=0.031250cm] (7.850000, -6.350000) -- (9.350000, -7.650000); 205 | \draw[-latex, line width=0.031250cm] (10.850000, -7.250000) -- (10.370000, -7.650000); 206 | \draw[line width=0.031250cm] (13.000000, -2.490000) ellipse (0.600000 and 0.312000); 207 | \node[] at (13.000000,-2.490000) {\textbf{IH-2}}; 208 | \node[anchor=west] at (13.600000,-2.490000) {\textbf{[0, 1]}}; 209 | \draw[line width=0.031250cm] (13.000000, -0.690000) ellipse (0.600000 and 0.312000); 210 | \node[] at (13.000000,-0.690000) {\textbf{IH-1}}; 211 | \node[anchor=west] at (13.600000,-0.690000) {\textbf{[64, 128]}}; 212 | \draw[line width=0.031250cm, fill=light_green_2] (13.000000, -3.390000) ellipse (0.600000 and 0.312000); 213 | \node[] at (13.000000,-3.390000) {\textbf{IH-4}}; 214 | \node[anchor=west] at (13.600000,-3.390000) {\textbf{[64, 128]}}; 215 | \draw[line width=0.031250cm, fill=light_green_2] (14.500000, -4.290000) ellipse (0.600000 and 0.312000); 216 | \node[] at (14.500000,-4.290000) {\textbf{IH-5}}; 217 | \node[anchor=west] at (15.100000,-4.290000) {\textbf{[64, 128]}}; 218 | \draw[line width=0.031250cm, fill=light_green_2] (14.500000, -6.090000) ellipse (0.600000 and 0.312000); 219 | \node[] at (14.500000,-6.090000) {\textbf{IH-6}}; 220 | \node[anchor=west] at (15.100000,-6.090000) {\textbf{[64, 128]}}; 221 | \draw[line width=0.031250cm, fill=light_red_2] (14.500000, -8.014000) ellipse (0.600000 and 0.312000); 222 | \node[] at (14.500000,-8.014000) {\textbf{DH-1}}; 223 | \node[anchor=west] at (15.100000,-8.014000) {\textbf{2}}; 224 | \draw[line width=0.031250cm, fill=light_red_2] (14.500000, -8.838000) ellipse (0.600000 and 0.312000); 225 | \node[] at (14.500000,-8.838000) {\textbf{IH-3}}; 226 | \node[anchor=west] at (15.100000,-8.838000) {\textbf{1}}; 227 | \draw[-latex, line width=0.031250cm] (12.400000, -0.690000) -- (11.500000, -0.690000); 228 | \draw[-latex, line width=0.031250cm] (12.400000, -2.490000) -- (11.500000, -2.490000); 229 | \draw[-latex, line width=0.031250cm] (12.400000, -3.390000) -- (10.000000, -5.190000); 230 | \draw[-latex, line width=0.031250cm] (13.900000, -4.290000) -- (13.000000, -4.290000); 231 | \draw[-latex, line width=0.031250cm] (13.900000, -6.090000) -- (13.000000, -6.090000); 232 | \draw[rounded corners=0.600000cm, line width=0.070312cm] (7.000000, 0.000000) -- (17.000000, 0.000000) -- (17.000000, -9.500000) -- (7.000000, -9.500000) -- cycle; 233 | \node[] at (7.600000,-0.600000) {\Huge \textbf b}; 234 | \draw[line width=0.031250cm] (-1.400000, -10.050000) -- (1.400000, -10.050000) -- (1.400000, -11.650000) -- (-1.400000, -11.650000) -- cycle; 235 | \node[] at (0.000000,-10.850000) {\textbf{Conv2D-1}}; 236 | \draw[line width=0.031250cm] (-1.300000, -10.150000) -- (-0.400000, -10.150000) -- (-0.400000, -10.550000) -- (-1.300000, -10.550000) -- cycle; 237 | \node[] at (-0.850000,-10.350000) {in}; 238 | \draw[line width=0.031250cm] (-1.300000, -11.150000) -- (-0.400000, -11.150000) -- (-0.400000, -11.550000) -- (-1.300000, -11.550000) -- cycle; 239 | \node[] at (-0.850000,-11.350000) {out}; 240 | \draw[line width=0.031250cm] (0.640000, -10.390000) ellipse (0.660000 and 0.240000); 241 | \node[] at (0.640000,-10.390000) {filters}; 242 | \draw[line width=0.031250cm, fill=light_green_2] (-1.400000, -11.850000) -- (1.400000, -11.850000) -- (1.400000, -13.450000) -- (-1.400000, -13.450000) -- cycle; 243 | \node[] at (0.000000,-12.650000) {\textbf{Dropout-1}}; 244 | \draw[line width=0.031250cm] (-1.300000, -11.950000) -- (-0.400000, -11.950000) -- (-0.400000, -12.350000) -- (-1.300000, -12.350000) -- cycle; 245 | \node[] at (-0.850000,-12.150000) {in}; 246 | \draw[line width=0.031250cm] (-1.300000, -12.950000) -- (-0.400000, -12.950000) -- (-0.400000, -13.350000) -- (-1.300000, -13.350000) -- cycle; 247 | \node[] at (-0.850000,-13.150000) {out}; 248 | \draw[line width=0.031250cm] (0.760000, -12.190000) ellipse (0.540000 and 0.240000); 249 | \node[] at (0.760000,-12.190000) {prob}; 250 | \draw[line width=0.031250cm] (-2.900000, -14.550000) -- (-0.100000, -14.550000) -- (-0.100000, -16.150000) -- (-2.900000, -16.150000) -- cycle; 251 | \node[] at (-1.500000,-15.350000) {\textbf{Conv2D-2}}; 252 | \draw[line width=0.031250cm] (-2.800000, -14.650000) -- (-1.900000, -14.650000) -- (-1.900000, -15.050000) -- (-2.800000, -15.050000) -- cycle; 253 | \node[] at (-2.350000,-14.850000) {in}; 254 | \draw[line width=0.031250cm] (-2.800000, -15.650000) -- (-1.900000, -15.650000) -- (-1.900000, -16.050000) -- (-2.800000, -16.050000) -- cycle; 255 | \node[] at (-2.350000,-15.850000) {out}; 256 | \draw[line width=0.031250cm] (-0.860000, -14.890000) ellipse (0.660000 and 0.240000); 257 | \node[] at (-0.860000,-14.890000) {filters}; 258 | \draw[line width=0.031250cm] (0.100000, -13.650000) -- (2.900000, -13.650000) -- (2.900000, -15.250000) -- (0.100000, -15.250000) -- cycle; 259 | \node[] at (1.500000,-14.450000) {\textbf{Conv2D-3}}; 260 | \draw[line width=0.031250cm] (0.200000, -13.750000) -- (1.100000, -13.750000) -- (1.100000, -14.150000) -- (0.200000, -14.150000) -- cycle; 261 | \node[] at (0.650000,-13.950000) {in}; 262 | \draw[line width=0.031250cm] (0.200000, -14.750000) -- (1.100000, -14.750000) -- (1.100000, -15.150000) -- (0.200000, -15.150000) -- cycle; 263 | \node[] at (0.650000,-14.950000) {out}; 264 | \draw[line width=0.031250cm] (2.140000, -13.990000) ellipse (0.660000 and 0.240000); 265 | \node[] at (2.140000,-13.990000) {filters}; 266 | \draw[line width=0.031250cm] (0.100000, -15.450000) -- (2.900000, -15.450000) -- (2.900000, -17.050000) -- (0.100000, -17.050000) -- cycle; 267 | \node[] at (1.500000,-16.250000) {\textbf{Conv2D-4}}; 268 | \draw[line width=0.031250cm] (0.200000, -15.550000) -- (1.100000, -15.550000) -- (1.100000, -15.950000) -- (0.200000, -15.950000) -- cycle; 269 | \node[] at (0.650000,-15.750000) {in}; 270 | \draw[line width=0.031250cm] (0.200000, -16.550000) -- (1.100000, -16.550000) -- (1.100000, -16.950000) -- (0.200000, -16.950000) -- cycle; 271 | \node[] at (0.650000,-16.750000) {out}; 272 | \draw[line width=0.031250cm] (2.140000, -15.790000) ellipse (0.660000 and 0.240000); 273 | \node[] at (2.140000,-15.790000) {filters}; 274 | \draw[line width=0.031250cm] (-1.400000, -17.250000) -- (1.400000, -17.250000) -- (1.400000, -18.850000) -- (-1.400000, -18.850000) -- cycle; 275 | \node[] at (0.000000,-18.050000) {\textbf{Concat-1}}; 276 | \draw[line width=0.031250cm] (-1.300000, -17.350000) -- (-0.400000, -17.350000) -- (-0.400000, -17.750000) -- (-1.300000, -17.750000) -- cycle; 277 | \node[] at (-0.850000,-17.550000) {in0}; 278 | \draw[line width=0.031250cm] (-0.280000, -17.350000) -- (0.620000, -17.350000) -- (0.620000, -17.750000) -- (-0.280000, -17.750000) -- cycle; 279 | \node[] at (0.170000,-17.550000) {in1}; 280 | \draw[line width=0.031250cm] (-1.300000, -18.350000) -- (-0.400000, -18.350000) -- (-0.400000, -18.750000) -- (-1.300000, -18.750000) -- cycle; 281 | \node[] at (-0.850000,-18.550000) {out}; 282 | \draw[-latex, line width=0.031250cm] (-0.850000, -11.550000) -- (-0.850000, -11.950000); 283 | \draw[-latex, line width=0.031250cm] (-0.850000, -13.350000) -- (-2.350000, -14.650000); 284 | \draw[-latex, line width=0.031250cm] (-0.850000, -13.350000) -- (0.650000, -13.750000); 285 | \draw[-latex, line width=0.031250cm] (0.650000, -15.150000) -- (0.650000, -15.550000); 286 | \draw[-latex, line width=0.031250cm] (-2.350000, -16.050000) -- (-0.850000, -17.350000); 287 | \draw[-latex, line width=0.031250cm] (0.650000, -16.950000) -- (0.170000, -17.350000); 288 | \draw[line width=0.031250cm] (2.800000, -10.390000) ellipse (0.600000 and 0.312000); 289 | \node[] at (2.800000,-10.390000) {\textbf{IH-1}}; 290 | \node[anchor=west] at (3.400000,-10.390000) {\textbf{[64, 128]}}; 291 | \draw[line width=0.031250cm] (2.800000, -13.090000) ellipse (0.600000 and 0.312000); 292 | \node[] at (2.800000,-13.090000) {\textbf{IH-4}}; 293 | \node[anchor=west] at (3.400000,-13.090000) {\textbf{[64, 128]}}; 294 | \draw[line width=0.031250cm] (4.300000, -13.990000) ellipse (0.600000 and 0.312000); 295 | \node[] at (4.300000,-13.990000) {\textbf{IH-5}}; 296 | \node[anchor=west] at (4.900000,-13.990000) {\textbf{[64, 128]}}; 297 | \draw[line width=0.031250cm] (4.300000, -15.790000) ellipse (0.600000 and 0.312000); 298 | \node[] at (4.300000,-15.790000) {\textbf{IH-6}}; 299 | \node[anchor=west] at (4.900000,-15.790000) {\textbf{[64, 128]}}; 300 | \draw[line width=0.031250cm, fill=light_green_2] (2.800000, -12.190000) ellipse (0.600000 and 0.312000); 301 | \node[] at (2.800000,-12.190000) {\textbf{IH-7}}; 302 | \node[anchor=west] at (3.400000,-12.190000) {\textbf{[0.25, 0.5]}}; 303 | \draw[line width=0.031250cm] (4.300000, -17.714000) ellipse (0.600000 and 0.312000); 304 | \node[] at (4.300000,-17.714000) {\textbf{DH-1}}; 305 | \node[anchor=west] at (4.900000,-17.714000) {\textbf{2}}; 306 | \draw[line width=0.031250cm] (4.300000, -18.538000) ellipse (0.600000 and 0.312000); 307 | \node[] at (4.300000,-18.538000) {\textbf{IH-3}}; 308 | \node[anchor=west] at (4.900000,-18.538000) {\textbf{1}}; 309 | \draw[line width=0.031250cm, fill=light_red_2] (4.300000, -16.890000) ellipse (0.600000 and 0.312000); 310 | \node[] at (4.300000,-16.890000) {\textbf{IH-2}}; 311 | \node[anchor=west] at (4.900000,-16.890000) {\textbf{1}}; 312 | \draw[-latex, line width=0.031250cm] (2.200000, -10.390000) -- (1.300000, -10.390000); 313 | \draw[-latex, line width=0.031250cm] (2.200000, -13.090000) -- (-0.200000, -14.890000); 314 | \draw[-latex, line width=0.031250cm] (3.700000, -13.990000) -- (2.800000, -13.990000); 315 | \draw[-latex, line width=0.031250cm] (3.700000, -15.790000) -- (2.800000, -15.790000); 316 | \draw[-latex, line width=0.031250cm] (2.200000, -12.190000) -- (1.300000, -12.190000); 317 | \draw[rounded corners=0.600000cm, line width=0.070312cm] (-3.200000, -9.700000) -- (6.800000, -9.700000) -- (6.800000, -19.200000) -- (-3.200000, -19.200000) -- cycle; 318 | \node[] at (-2.600000,-10.300000) {\Huge \textbf c}; 319 | \draw[line width=0.031250cm] (8.800000, -10.050000) -- (11.600000, -10.050000) -- (11.600000, -11.650000) -- (8.800000, -11.650000) -- cycle; 320 | \node[] at (10.200000,-10.850000) {\textbf{Conv2D-1}}; 321 | \draw[line width=0.031250cm] (8.900000, -10.150000) -- (9.800000, -10.150000) -- (9.800000, -10.550000) -- (8.900000, -10.550000) -- cycle; 322 | \node[] at (9.350000,-10.350000) {in}; 323 | \draw[line width=0.031250cm] (8.900000, -11.150000) -- (9.800000, -11.150000) -- (9.800000, -11.550000) -- (8.900000, -11.550000) -- cycle; 324 | \node[] at (9.350000,-11.350000) {out}; 325 | \draw[line width=0.031250cm] (10.840000, -10.390000) ellipse (0.660000 and 0.240000); 326 | \node[] at (10.840000,-10.390000) {filters}; 327 | \draw[line width=0.031250cm] (8.800000, -11.850000) -- (11.600000, -11.850000) -- (11.600000, -13.450000) -- (8.800000, -13.450000) -- cycle; 328 | \node[] at (10.200000,-12.650000) {\textbf{Dropout-1}}; 329 | \draw[line width=0.031250cm] (8.900000, -11.950000) -- (9.800000, -11.950000) -- (9.800000, -12.350000) -- (8.900000, -12.350000) -- cycle; 330 | \node[] at (9.350000,-12.150000) {in}; 331 | \draw[line width=0.031250cm] (8.900000, -12.950000) -- (9.800000, -12.950000) -- (9.800000, -13.350000) -- (8.900000, -13.350000) -- cycle; 332 | \node[] at (9.350000,-13.150000) {out}; 333 | \draw[line width=0.031250cm] (10.960000, -12.190000) ellipse (0.540000 and 0.240000); 334 | \node[] at (10.960000,-12.190000) {prob}; 335 | \draw[line width=0.031250cm] (7.300000, -14.550000) -- (10.100000, -14.550000) -- (10.100000, -16.150000) -- (7.300000, -16.150000) -- cycle; 336 | \node[] at (8.700000,-15.350000) {\textbf{Conv2D-2}}; 337 | \draw[line width=0.031250cm] (7.400000, -14.650000) -- (8.300000, -14.650000) -- (8.300000, -15.050000) -- (7.400000, -15.050000) -- cycle; 338 | \node[] at (7.850000,-14.850000) {in}; 339 | \draw[line width=0.031250cm] (7.400000, -15.650000) -- (8.300000, -15.650000) -- (8.300000, -16.050000) -- (7.400000, -16.050000) -- cycle; 340 | \node[] at (7.850000,-15.850000) {out}; 341 | \draw[line width=0.031250cm] (9.340000, -14.890000) ellipse (0.660000 and 0.240000); 342 | \node[] at (9.340000,-14.890000) {filters}; 343 | \draw[line width=0.031250cm] (10.300000, -13.650000) -- (13.100000, -13.650000) -- (13.100000, -15.250000) -- (10.300000, -15.250000) -- cycle; 344 | \node[] at (11.700000,-14.450000) {\textbf{Conv2D-3}}; 345 | \draw[line width=0.031250cm] (10.400000, -13.750000) -- (11.300000, -13.750000) -- (11.300000, -14.150000) -- (10.400000, -14.150000) -- cycle; 346 | \node[] at (10.850000,-13.950000) {in}; 347 | \draw[line width=0.031250cm] (10.400000, -14.750000) -- (11.300000, -14.750000) -- (11.300000, -15.150000) -- (10.400000, -15.150000) -- cycle; 348 | \node[] at (10.850000,-14.950000) {out}; 349 | \draw[line width=0.031250cm] (12.340000, -13.990000) ellipse (0.660000 and 0.240000); 350 | \node[] at (12.340000,-13.990000) {filters}; 351 | \draw[line width=0.031250cm] (10.300000, -15.450000) -- (13.100000, -15.450000) -- (13.100000, -17.050000) -- (10.300000, -17.050000) -- cycle; 352 | \node[] at (11.700000,-16.250000) {\textbf{Conv2D-4}}; 353 | \draw[line width=0.031250cm] (10.400000, -15.550000) -- (11.300000, -15.550000) -- (11.300000, -15.950000) -- (10.400000, -15.950000) -- cycle; 354 | \node[] at (10.850000,-15.750000) {in}; 355 | \draw[line width=0.031250cm] (10.400000, -16.550000) -- (11.300000, -16.550000) -- (11.300000, -16.950000) -- (10.400000, -16.950000) -- cycle; 356 | \node[] at (10.850000,-16.750000) {out}; 357 | \draw[line width=0.031250cm] (12.340000, -15.790000) ellipse (0.660000 and 0.240000); 358 | \node[] at (12.340000,-15.790000) {filters}; 359 | \draw[line width=0.031250cm] (8.800000, -17.250000) -- (11.600000, -17.250000) -- (11.600000, -18.850000) -- (8.800000, -18.850000) -- cycle; 360 | \node[] at (10.200000,-18.050000) {\textbf{Concat-1}}; 361 | \draw[line width=0.031250cm] (8.900000, -17.350000) -- (9.800000, -17.350000) -- (9.800000, -17.750000) -- (8.900000, -17.750000) -- cycle; 362 | \node[] at (9.350000,-17.550000) {in0}; 363 | \draw[line width=0.031250cm] (9.920000, -17.350000) -- (10.820000, -17.350000) -- (10.820000, -17.750000) -- (9.920000, -17.750000) -- cycle; 364 | \node[] at (10.370000,-17.550000) {in1}; 365 | \draw[line width=0.031250cm] (8.900000, -18.350000) -- (9.800000, -18.350000) -- (9.800000, -18.750000) -- (8.900000, -18.750000) -- cycle; 366 | \node[] at (9.350000,-18.550000) {out}; 367 | \draw[-latex, line width=0.031250cm] (9.350000, -11.550000) -- (9.350000, -11.950000); 368 | \draw[-latex, line width=0.031250cm] (9.350000, -13.350000) -- (7.850000, -14.650000); 369 | \draw[-latex, line width=0.031250cm] (9.350000, -13.350000) -- (10.850000, -13.750000); 370 | \draw[-latex, line width=0.031250cm] (10.850000, -15.150000) -- (10.850000, -15.550000); 371 | \draw[-latex, line width=0.031250cm] (7.850000, -16.050000) -- (9.350000, -17.350000); 372 | \draw[-latex, line width=0.031250cm] (10.850000, -16.950000) -- (10.370000, -17.350000); 373 | \draw[line width=0.031250cm, fill=light_red_2] (13.000000, -10.390000) ellipse (0.600000 and 0.312000); 374 | \node[] at (13.000000,-10.390000) {\textbf{IH-1}}; 375 | \node[anchor=west] at (13.600000,-10.390000) {\textbf{64}}; 376 | \draw[line width=0.031250cm, fill=light_red_2] (13.000000, -13.090000) ellipse (0.600000 and 0.312000); 377 | \node[] at (13.000000,-13.090000) {\textbf{IH-4}}; 378 | \node[anchor=west] at (13.600000,-13.090000) {\textbf{128}}; 379 | \draw[line width=0.031250cm, fill=light_red_2] (14.500000, -13.990000) ellipse (0.600000 and 0.312000); 380 | \node[] at (14.500000,-13.990000) {\textbf{IH-5}}; 381 | \node[anchor=west] at (15.100000,-13.990000) {\textbf{128}}; 382 | \draw[line width=0.031250cm, fill=light_red_2] (14.500000, -15.790000) ellipse (0.600000 and 0.312000); 383 | \node[] at (14.500000,-15.790000) {\textbf{IH-6}}; 384 | \node[anchor=west] at (15.100000,-15.790000) {\textbf{64}}; 385 | \draw[line width=0.031250cm, fill=light_red_2] (13.000000, -12.190000) ellipse (0.600000 and 0.312000); 386 | \node[] at (13.000000,-12.190000) {\textbf{IH-7}}; 387 | \node[anchor=west] at (13.600000,-12.190000) {\textbf{0.5}}; 388 | \draw[line width=0.031250cm] (14.500000, -17.714000) ellipse (0.600000 and 0.312000); 389 | \node[] at (14.500000,-17.714000) {\textbf{DH-1}}; 390 | \node[anchor=west] at (15.100000,-17.714000) {\textbf{2}}; 391 | \draw[line width=0.031250cm] (14.500000, -18.538000) ellipse (0.600000 and 0.312000); 392 | \node[] at (14.500000,-18.538000) {\textbf{IH-3}}; 393 | \node[anchor=west] at (15.100000,-18.538000) {\textbf{1}}; 394 | \draw[line width=0.031250cm] (14.500000, -16.890000) ellipse (0.600000 and 0.312000); 395 | \node[] at (14.500000,-16.890000) {\textbf{IH-2}}; 396 | \node[anchor=west] at (15.100000,-16.890000) {\textbf{1}}; 397 | \draw[-latex, line width=0.031250cm] (12.400000, -10.390000) -- (11.500000, -10.390000); 398 | \draw[-latex, line width=0.031250cm] (12.400000, -13.090000) -- (10.000000, -14.890000); 399 | \draw[-latex, line width=0.031250cm] (13.900000, -13.990000) -- (13.000000, -13.990000); 400 | \draw[-latex, line width=0.031250cm] (13.900000, -15.790000) -- (13.000000, -15.790000); 401 | \draw[-latex, line width=0.031250cm] (12.400000, -12.190000) -- (11.500000, -12.190000); 402 | \draw[rounded corners=0.600000cm, line width=0.070312cm] (7.000000, -9.700000) -- (17.000000, -9.700000) -- (17.000000, -19.200000) -- (7.000000, -19.200000) -- cycle; 403 | \node[] at (7.600000,-10.300000) {\Huge \textbf d}; 404 | \end{tikzpicture} 405 | \end{document} 406 | -------------------------------------------------------------------------------- /examples/factor_graphs.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/negrinho/sane_tikz/fd6f291d9815613594d724678cb91ac9d412fbb7/examples/factor_graphs.pdf -------------------------------------------------------------------------------- /examples/factor_graphs.py: -------------------------------------------------------------------------------- 1 | import sane_tikz.core as stz 2 | import sane_tikz.formatting as fmt 3 | 4 | horizontal_node_spacing = 2.0 5 | vertical_node_spacing = 0.8 6 | node_radius = 0.36 7 | filled_node_radius = 0.08 8 | rectangle_roundness = 0.1 9 | rectangle_width = 1.4 10 | vertical_rectangle_distance = 0.8 11 | horizontal_rectangle_distance = 1.4 12 | triangle_angle_delta = 40 13 | triangle_radius = node_radius 14 | vd = vertical_rectangle_distance 15 | hd = horizontal_rectangle_distance 16 | 17 | 18 | def node(label): 19 | return [stz.circle([0, 0], node_radius), stz.latex([0, 0], label)] 20 | 21 | 22 | def small_node(cs): 23 | s_fmt = fmt.fill_color('black') 24 | return stz.circle(cs, filled_node_radius, s_fmt) 25 | 26 | 27 | def small_node_relative(e_from, e_to, alpha=0.5): 28 | from_cs = stz.center_coords(e_from) 29 | to_cs = stz.center_coords(e_to) 30 | cs = stz.convex_combination_coords(from_cs, to_cs, alpha) 31 | return small_node(cs) 32 | 33 | 34 | def connect_nodes(e_from, e_to): 35 | cs_from = stz.center_coords(e_from) 36 | cs_to = stz.center_coords(e_to) 37 | angle = stz.vector_to_angle([cs_from, cs_to]) 38 | return stz.line_segment_between_circles(cs_from, node_radius, angle, cs_to, 39 | node_radius, angle + 180.0) 40 | 41 | 42 | def connect_small_node_to_node(e_small_from, e_to): 43 | cs_from = stz.center_coords(e_small_from) 44 | cs_to = stz.center_coords(e_to) 45 | angle = stz.vector_to_angle([cs_from, cs_to]) 46 | return stz.line_segment_between_circles(cs_from, filled_node_radius, angle, 47 | cs_to, node_radius, angle + 180.0) 48 | 49 | 50 | def label_small_node(label, e_small, angle, distance, label_width): 51 | s_fmt = fmt.combine_tikz_strs([ 52 | fmt.rounded_corners(rectangle_roundness), 53 | fmt.fill_color_with_no_line('gray!20') 54 | ]) 55 | s_fmt_t = fmt.fill_color_with_no_line('gray!20') 56 | r = stz.rectangle_from_width_and_height([0, 0], 1.8 * node_radius, 57 | label_width, s_fmt) 58 | cs = stz.center_coords(e_small) 59 | cs_label = stz.coords_on_circle(cs, distance, angle) 60 | stz.translate_bbox_center_to_coords(r, cs_label) 61 | l = stz.latex(cs_label, label) 62 | t = stz.closed_path([ 63 | stz.coords_on_circle(cs, filled_node_radius, angle), cs_label, 64 | stz.coords_on_circle(cs_label, triangle_radius, 65 | angle + 180.0 + triangle_angle_delta) 66 | ], s_fmt_t) 67 | return [r, t, l] 68 | 69 | 70 | def figure_a(): 71 | x1 = node("$x_1$") 72 | x2 = node("$x_2$") 73 | x3 = node("$x_3$") 74 | stz.distribute_horizontally_with_spacing([x1, x2, x3], 75 | horizontal_node_spacing) 76 | nodes = [x1, x2, x3] 77 | 78 | c1 = small_node_relative(x1, x2) 79 | c2 = small_node_relative(x2, x3) 80 | c3 = small_node([0, 0]) 81 | stz.place_to_the_left_and_align_to_the_center( 82 | c3, x1, horizontal_node_spacing / 2.0 - filled_node_radius) 83 | small_nodes = [c1, c2, c3] 84 | small_nodes.extend([small_node([0, 0]) for _ in range(3)]) 85 | stz.distribute_centers_horizontally_with_spacing( 86 | small_nodes[-3:], horizontal_node_spacing + 2.0 * node_radius) 87 | stz.place_below_and_align_to_the_center(small_nodes[-3:], nodes, 88 | vertical_node_spacing) 89 | 90 | x1_x2 = connect_nodes(x1, x2) 91 | x2_x3 = connect_nodes(x2, x3) 92 | x1_c3 = connect_small_node_to_node(c3, x1) 93 | connections = [x1_x2, x2_x3, x1_c3] 94 | connections.extend([ 95 | connect_small_node_to_node(small_nodes[-3 + i], nodes[i]) 96 | for i in range(3) 97 | ]) 98 | 99 | labels = [ 100 | label_small_node("$p(x_1)$", c3, 90.0, vd, rectangle_width), 101 | label_small_node("$l(x_1; z_1)$", small_nodes[3], 0.0, hd, 102 | rectangle_width), 103 | label_small_node("$p(x_3 | x_2)$", c2, 90.0, vd, rectangle_width) 104 | ] 105 | 106 | return [nodes, small_nodes, connections, labels] 107 | 108 | 109 | def figure_b(): 110 | x1 = node("$x_1$") 111 | x2 = node("$x_2$") 112 | x3 = node("$x_3$") 113 | stz.distribute_horizontally_with_spacing([x1, x2, x3], 114 | horizontal_node_spacing) 115 | nodes = [x1, x2, x3] 116 | 117 | c1 = small_node_relative(x1, x2) 118 | c2 = small_node_relative(x2, x3) 119 | c3 = small_node([0, 0]) 120 | stz.place_to_the_left_and_align_to_the_center( 121 | c3, x1, horizontal_node_spacing / 2.0 - filled_node_radius) 122 | small_nodes = [c1, c2, c3] 123 | small_nodes.extend([small_node([0, 0]) for _ in range(3)]) 124 | stz.distribute_centers_horizontally_with_spacing( 125 | small_nodes[-3:], horizontal_node_spacing + 2.0 * node_radius) 126 | stz.place_below_and_align_to_the_center(small_nodes[-3:], nodes, 127 | vertical_node_spacing) 128 | 129 | x1_x2 = connect_nodes(x1, x2) 130 | x2_x3 = connect_nodes(x2, x3) 131 | x1_c3 = connect_small_node_to_node(c3, x1) 132 | connections = [x1_x2, x2_x3, x1_c3] 133 | connections.extend([ 134 | connect_small_node_to_node(small_nodes[-3 + i], nodes[i]) 135 | for i in range(3) 136 | ]) 137 | 138 | # for qs 139 | q1 = node("$q_1$") 140 | q2 = node("$q_2$") 141 | q3 = node("$q_3$") 142 | stz.distribute_horizontally_with_spacing([q1, q2, q3], 143 | horizontal_node_spacing) 144 | nodes.extend([q1, q2, q3]) 145 | stz.place_above_and_align_to_the_center([q1, q2, q3], [x1, x2, x3], 146 | vertical_node_spacing) 147 | 148 | qc1 = small_node_relative(q1, q2) 149 | qc2 = small_node_relative(q2, q3) 150 | qc3 = small_node([0, 0]) 151 | stz.place_to_the_left_and_align_to_the_center( 152 | qc3, q1, horizontal_node_spacing / 2.0 - filled_node_radius) 153 | small_nodes.extend([qc1, qc2, qc3]) 154 | 155 | q1_q2 = connect_nodes(q1, q2) 156 | q2_q3 = connect_nodes(q2, q3) 157 | q1_qc3 = connect_small_node_to_node(qc3, q1) 158 | connections.extend([q1_q2, q2_q3, q1_qc3]) 159 | connections.extend( 160 | [connect_nodes(e1, e2) for e1, e2 in zip([x1, x2, x3], [q1, q2, q3])]) 161 | 162 | labels = [ 163 | label_small_node("$p(q_1)$", qc3, -90.0, vd, rectangle_width), 164 | label_small_node("$p(q_2| q_3)$", qc2, -90.0, vd, rectangle_width), 165 | ] 166 | 167 | return [nodes, small_nodes, connections, labels] 168 | 169 | 170 | def figure_c(): 171 | x1 = node("$x_1$") 172 | x2 = node("$x_2$") 173 | x3 = node("$x_3$") 174 | stz.distribute_horizontally_with_spacing([x1, x2, x3], 175 | horizontal_node_spacing) 176 | nodes = [x1, x2, x3] 177 | 178 | c1 = small_node_relative(x1, x2) 179 | c2 = small_node_relative(x2, x3) 180 | small_nodes = [c1, c2] 181 | small_nodes.extend([small_node([0, 0]) for _ in range(3)]) 182 | stz.distribute_centers_horizontally_with_spacing( 183 | small_nodes[-3:], horizontal_node_spacing + 2.0 * node_radius) 184 | stz.place_below_and_align_to_the_center(small_nodes[-3:], nodes, 185 | vertical_node_spacing) 186 | 187 | x1_x2 = connect_nodes(x1, x2) 188 | x2_x3 = connect_nodes(x2, x3) 189 | connections = [x1_x2, x2_x3] 190 | connections.extend([ 191 | connect_small_node_to_node(small_nodes[-3 + i], nodes[i]) 192 | for i in range(3) 193 | ]) 194 | 195 | u1 = node("$u_1$") 196 | u2 = node("$u_2$") 197 | nodes.extend([u1, u2]) 198 | for u, c in zip([u1, u2], [c1, c2]): 199 | cx = small_node([0, 0]) 200 | stz.place_above_and_align_to_the_center( 201 | u, c, vertical_node_spacing - node_radius) 202 | stz.place_above_and_align_to_the_center( 203 | cx, u, vertical_node_spacing - node_radius) 204 | connections.extend([ 205 | connect_small_node_to_node(c, u), 206 | connect_small_node_to_node(cx, u) 207 | ]) 208 | small_nodes.append(cx) 209 | 210 | labels = [ 211 | label_small_node("$J_x(x_1)$", small_nodes[2], 0.0, hd, 212 | rectangle_width), 213 | label_small_node("$J_u(u_1)$", small_nodes[5], 0.0, hd, 214 | rectangle_width), 215 | label_small_node("$p(x_3| x_2, u_2)$", small_nodes[1], -90.0, vd, 216 | 1.4 * rectangle_width) 217 | ] 218 | 219 | return [nodes, small_nodes, connections, labels] 220 | 221 | 222 | def figure_d(): 223 | x1 = node("$T_1$") 224 | x2 = node("$T_2$") 225 | x3 = node("$T_3$") 226 | stz.distribute_horizontally_with_spacing([x1, x2, x3], 227 | horizontal_node_spacing) 228 | nodes = [x1, x2, x3] 229 | 230 | c1 = small_node_relative(x1, x2) 231 | c2 = small_node_relative(x2, x3) 232 | c3 = small_node([0, 0]) 233 | stz.place_to_the_left_and_align_to_the_center( 234 | c3, x1, horizontal_node_spacing / 2.0 - filled_node_radius) 235 | small_nodes = [c1, c2, c3] 236 | 237 | connections = [ 238 | connect_nodes(x1, x2), 239 | connect_nodes(x2, x3), 240 | connect_small_node_to_node(c3, x1), 241 | ] 242 | 243 | x4 = node("$T_4$") 244 | x5 = node("$T_5$") 245 | stz.distribute_horizontally_with_spacing([x5, x4], horizontal_node_spacing) 246 | stz.place_above_and_align_to_the_center([x5, x4], [x2, x3], 247 | vertical_node_spacing) 248 | nodes.extend([x4, x5]) 249 | 250 | connections.extend([ 251 | connect_nodes(x2, x5), 252 | connect_nodes(x3, x4), 253 | connect_nodes(x4, x5), 254 | ]) 255 | 256 | small_nodes.extend([ 257 | small_node_relative(x2, x5), 258 | small_node_relative(x3, x4), 259 | small_node_relative(x4, x5) 260 | ]) 261 | 262 | labels = [ 263 | label_small_node("$f_p(T_1)$", c3, 90.0, vd, rectangle_width), 264 | label_small_node("$f_l(T_5, T_2)$", small_nodes[-3], 180.0, hd, 265 | 1.25 * rectangle_width), 266 | label_small_node("$f_b(T_4, T_5)$", small_nodes[-1], -90.0, vd, 267 | 1.25 * rectangle_width) 268 | ] 269 | 270 | return [nodes, small_nodes, connections, labels] 271 | 272 | 273 | def figure_e(): 274 | x1 = node("$T_1$") 275 | x2 = node("$T_2$") 276 | x3 = node("$T_3$") 277 | stz.distribute_horizontally_with_spacing([x1, x2, x3], 278 | horizontal_node_spacing) 279 | nodes = [x1, x2, x3] 280 | 281 | c1 = small_node_relative(x1, x2) 282 | c2 = small_node_relative(x2, x3) 283 | c3 = small_node([0, 0]) 284 | stz.place_to_the_left_and_align_to_the_center( 285 | c3, x1, horizontal_node_spacing / 2.0 - filled_node_radius) 286 | small_nodes = [c1, c2, c3] 287 | 288 | connections = [ 289 | connect_nodes(x1, x2), 290 | connect_nodes(x2, x3), 291 | connect_small_node_to_node(c3, x1), 292 | ] 293 | 294 | x4 = node("$l_4$") 295 | x5 = node("$l_5$") 296 | stz.distribute_horizontally_with_spacing([x5, x4], horizontal_node_spacing) 297 | stz.place_above_and_align_to_the_center([x5, x4], [x2], 298 | vertical_node_spacing) 299 | nodes.extend([x4, x5]) 300 | 301 | connections.extend([ 302 | connect_nodes(x1, x5), 303 | connect_nodes(x2, x5), 304 | connect_nodes(x2, x4), 305 | connect_nodes(x3, x4), 306 | connect_nodes(x1, x4), 307 | ]) 308 | 309 | small_nodes.extend([ 310 | small_node_relative(x1, x5, 0.6), 311 | small_node_relative(x2, x5, 0.6), 312 | small_node_relative(x2, x4, 0.6), 313 | small_node_relative(x3, x4, 0.6), 314 | small_node_relative(x1, x4, 0.6), 315 | ]) 316 | 317 | labels = [ 318 | label_small_node("$f_{br}(T_1, l_5)$", small_nodes[-5], 135.0, hd, 319 | 1.4 * rectangle_width) 320 | ] 321 | 322 | return [nodes, small_nodes, connections, labels] 323 | 324 | 325 | def figure_f(): 326 | x1 = node("$C_1$") 327 | x2 = node("$C_2$") 328 | x3 = node("$C_3$") 329 | stz.distribute_horizontally_with_spacing([x1, x2, x3], 330 | horizontal_node_spacing) 331 | nodes = [x1, x2, x3] 332 | 333 | small_nodes = [] 334 | connections = [] 335 | 336 | x4 = node("$p_4$") 337 | x5 = node("$p_5$") 338 | stz.distribute_horizontally_with_spacing([x5, x4], horizontal_node_spacing) 339 | stz.place_above_and_align_to_the_center([x5, x4], [x2], 340 | vertical_node_spacing) 341 | nodes.extend([x4, x5]) 342 | 343 | connections.extend([ 344 | connect_nodes(x1, x5), 345 | connect_nodes(x2, x5), 346 | connect_nodes(x2, x4), 347 | connect_nodes(x3, x4), 348 | connect_nodes(x1, x4), 349 | ]) 350 | 351 | small_nodes.extend([ 352 | small_node_relative(x1, x5, 0.6), 353 | small_node_relative(x2, x5, 0.6), 354 | small_node_relative(x2, x4, 0.6), 355 | small_node_relative(x3, x4, 0.6), 356 | small_node_relative(x1, x4, 0.6), 357 | ]) 358 | 359 | labels = [ 360 | label_small_node("$f_{rp}(C_1, p_5)$", small_nodes[-5], 135.0, hd, 361 | 1.4 * rectangle_width) 362 | ] 363 | 364 | return [nodes, small_nodes, connections, labels] 365 | 366 | 367 | e = [ 368 | figure_a(), 369 | figure_b(), 370 | figure_c(), 371 | figure_d(), 372 | figure_e(), 373 | figure_f(), 374 | ] 375 | stz.distribute_vertically_with_spacing(e[:3][::-1], 2.0) 376 | stz.distribute_vertically_with_spacing(e[3:][::-1], 2.0) 377 | stz.distribute_horizontally_with_spacing([e[:3], e[3:]], 2.0) 378 | 379 | stz.draw_to_tikz_standalone(e, "factor_graphs.tex") 380 | -------------------------------------------------------------------------------- /examples/factor_graphs.tex: -------------------------------------------------------------------------------- 1 | \documentclass{standalone} 2 | \usepackage[T1]{fontenc}\usepackage{tikz} 3 | \usepackage{amsmath, amsfonts} 4 | \usetikzlibrary{arrows.meta} 5 | \begin{document} 6 | \begin{tikzpicture} 7 | \draw[] (0.000000, 10.848000) circle (0.360000); 8 | \node[] at (0.000000,10.848000) {$x_1$}; 9 | \draw[] (2.720000, 10.848000) circle (0.360000); 10 | \node[] at (2.720000,10.848000) {$x_2$}; 11 | \draw[] (5.440000, 10.848000) circle (0.360000); 12 | \node[] at (5.440000,10.848000) {$x_3$}; 13 | \draw[fill=black] (1.360000, 10.848000) circle (0.080000); 14 | \draw[fill=black] (4.080000, 10.848000) circle (0.080000); 15 | \draw[fill=black] (-1.360000, 10.848000) circle (0.080000); 16 | \draw[fill=black] (0.000000, 9.608000) circle (0.080000); 17 | \draw[fill=black] (2.720000, 9.608000) circle (0.080000); 18 | \draw[fill=black] (5.440000, 9.608000) circle (0.080000); 19 | \draw[] (0.360000, 10.848000) -- (2.360000, 10.848000); 20 | \draw[] (3.080000, 10.848000) -- (5.080000, 10.848000); 21 | \draw[] (-1.280000, 10.848000) -- (-0.360000, 10.848000); 22 | \draw[] (0.000000, 9.688000) -- (-0.000000, 10.488000); 23 | \draw[] (2.720000, 9.688000) -- (2.720000, 10.488000); 24 | \draw[] (5.440000, 9.688000) -- (5.440000, 10.488000); 25 | \draw[rounded corners=0.100000cm, fill=gray!20, draw=none] (-2.060000, 11.972000) -- (-0.660000, 11.972000) -- (-0.660000, 11.324000) -- (-2.060000, 11.324000) -- cycle; 26 | \draw[fill=gray!20, draw=none] (-1.360000, 10.928000) -- (-1.360000, 11.648000) -- (-1.128596, 11.372224) -- cycle; 27 | \node[] at (-1.360000,11.648000) {$p(x_1)$}; 28 | \draw[rounded corners=0.100000cm, fill=gray!20, draw=none] (0.700000, 9.932000) -- (2.100000, 9.932000) -- (2.100000, 9.284000) -- (0.700000, 9.284000) -- cycle; 29 | \draw[fill=gray!20, draw=none] (0.080000, 9.608000) -- (1.400000, 9.608000) -- (1.124224, 9.376596) -- cycle; 30 | \node[] at (1.400000,9.608000) {$l(x_1; z_1)$}; 31 | \draw[rounded corners=0.100000cm, fill=gray!20, draw=none] (3.380000, 11.972000) -- (4.780000, 11.972000) -- (4.780000, 11.324000) -- (3.380000, 11.324000) -- cycle; 32 | \draw[fill=gray!20, draw=none] (4.080000, 10.928000) -- (4.080000, 11.648000) -- (4.311404, 11.372224) -- cycle; 33 | \node[] at (4.080000,11.648000) {$p(x_3 | x_2)$}; 34 | \draw[] (0.000000, 5.404000) circle (0.360000); 35 | \node[] at (0.000000,5.404000) {$x_1$}; 36 | \draw[] (2.720000, 5.404000) circle (0.360000); 37 | \node[] at (2.720000,5.404000) {$x_2$}; 38 | \draw[] (5.440000, 5.404000) circle (0.360000); 39 | \node[] at (5.440000,5.404000) {$x_3$}; 40 | \draw[] (0.000000, 6.924000) circle (0.360000); 41 | \node[] at (0.000000,6.924000) {$q_1$}; 42 | \draw[] (2.720000, 6.924000) circle (0.360000); 43 | \node[] at (2.720000,6.924000) {$q_2$}; 44 | \draw[] (5.440000, 6.924000) circle (0.360000); 45 | \node[] at (5.440000,6.924000) {$q_3$}; 46 | \draw[fill=black] (1.360000, 5.404000) circle (0.080000); 47 | \draw[fill=black] (4.080000, 5.404000) circle (0.080000); 48 | \draw[fill=black] (-1.360000, 5.404000) circle (0.080000); 49 | \draw[fill=black] (0.000000, 4.164000) circle (0.080000); 50 | \draw[fill=black] (2.720000, 4.164000) circle (0.080000); 51 | \draw[fill=black] (5.440000, 4.164000) circle (0.080000); 52 | \draw[fill=black] (1.360000, 6.924000) circle (0.080000); 53 | \draw[fill=black] (4.080000, 6.924000) circle (0.080000); 54 | \draw[fill=black] (-1.360000, 6.924000) circle (0.080000); 55 | \draw[] (0.360000, 5.404000) -- (2.360000, 5.404000); 56 | \draw[] (3.080000, 5.404000) -- (5.080000, 5.404000); 57 | \draw[] (-1.280000, 5.404000) -- (-0.360000, 5.404000); 58 | \draw[] (0.000000, 4.244000) -- (-0.000000, 5.044000); 59 | \draw[] (2.720000, 4.244000) -- (2.720000, 5.044000); 60 | \draw[] (5.440000, 4.244000) -- (5.440000, 5.044000); 61 | \draw[] (0.360000, 6.924000) -- (2.360000, 6.924000); 62 | \draw[] (3.080000, 6.924000) -- (5.080000, 6.924000); 63 | \draw[] (-1.280000, 6.924000) -- (-0.360000, 6.924000); 64 | \draw[] (0.000000, 5.764000) -- (-0.000000, 6.564000); 65 | \draw[] (2.720000, 5.764000) -- (2.720000, 6.564000); 66 | \draw[] (5.440000, 5.764000) -- (5.440000, 6.564000); 67 | \draw[rounded corners=0.100000cm, fill=gray!20, draw=none] (-2.060000, 6.448000) -- (-0.660000, 6.448000) -- (-0.660000, 5.800000) -- (-2.060000, 5.800000) -- cycle; 68 | \draw[fill=gray!20, draw=none] (-1.360000, 6.844000) -- (-1.360000, 6.124000) -- (-1.591404, 6.399776) -- cycle; 69 | \node[] at (-1.360000,6.124000) {$p(q_1)$}; 70 | \draw[rounded corners=0.100000cm, fill=gray!20, draw=none] (3.380000, 6.448000) -- (4.780000, 6.448000) -- (4.780000, 5.800000) -- (3.380000, 5.800000) -- cycle; 71 | \draw[fill=gray!20, draw=none] (4.080000, 6.844000) -- (4.080000, 6.124000) -- (3.848596, 6.399776) -- cycle; 72 | \node[] at (4.080000,6.124000) {$p(q_2| q_3)$}; 73 | \draw[] (0.000000, 0.000000) circle (0.360000); 74 | \node[] at (0.000000,0.000000) {$x_1$}; 75 | \draw[] (2.720000, 0.000000) circle (0.360000); 76 | \node[] at (2.720000,0.000000) {$x_2$}; 77 | \draw[] (5.440000, 0.000000) circle (0.360000); 78 | \node[] at (5.440000,0.000000) {$x_3$}; 79 | \draw[] (1.360000, 0.880000) circle (0.360000); 80 | \node[] at (1.360000,0.880000) {$u_1$}; 81 | \draw[] (4.080000, 0.880000) circle (0.360000); 82 | \node[] at (4.080000,0.880000) {$u_2$}; 83 | \draw[fill=black] (1.360000, 0.000000) circle (0.080000); 84 | \draw[fill=black] (4.080000, 0.000000) circle (0.080000); 85 | \draw[fill=black] (0.000000, -1.240000) circle (0.080000); 86 | \draw[fill=black] (2.720000, -1.240000) circle (0.080000); 87 | \draw[fill=black] (5.440000, -1.240000) circle (0.080000); 88 | \draw[fill=black] (1.360000, 1.760000) circle (0.080000); 89 | \draw[fill=black] (4.080000, 1.760000) circle (0.080000); 90 | \draw[] (0.360000, 0.000000) -- (2.360000, 0.000000); 91 | \draw[] (3.080000, 0.000000) -- (5.080000, 0.000000); 92 | \draw[] (0.000000, -1.160000) -- (-0.000000, -0.360000); 93 | \draw[] (2.720000, -1.160000) -- (2.720000, -0.360000); 94 | \draw[] (5.440000, -1.160000) -- (5.440000, -0.360000); 95 | \draw[] (1.360000, 0.080000) -- (1.360000, 0.520000); 96 | \draw[] (1.360000, 1.680000) -- (1.360000, 1.240000); 97 | \draw[] (4.080000, 0.080000) -- (4.080000, 0.520000); 98 | \draw[] (4.080000, 1.680000) -- (4.080000, 1.240000); 99 | \draw[rounded corners=0.100000cm, fill=gray!20, draw=none] (0.700000, -0.916000) -- (2.100000, -0.916000) -- (2.100000, -1.564000) -- (0.700000, -1.564000) -- cycle; 100 | \draw[fill=gray!20, draw=none] (0.080000, -1.240000) -- (1.400000, -1.240000) -- (1.124224, -1.471404) -- cycle; 101 | \node[] at (1.400000,-1.240000) {$J_x(x_1)$}; 102 | \draw[rounded corners=0.100000cm, fill=gray!20, draw=none] (2.060000, 2.084000) -- (3.460000, 2.084000) -- (3.460000, 1.436000) -- (2.060000, 1.436000) -- cycle; 103 | \draw[fill=gray!20, draw=none] (1.440000, 1.760000) -- (2.760000, 1.760000) -- (2.484224, 1.528596) -- cycle; 104 | \node[] at (2.760000,1.760000) {$J_u(u_1)$}; 105 | \draw[rounded corners=0.100000cm, fill=gray!20, draw=none] (3.100000, -0.476000) -- (5.060000, -0.476000) -- (5.060000, -1.124000) -- (3.100000, -1.124000) -- cycle; 106 | \draw[fill=gray!20, draw=none] (4.080000, -0.080000) -- (4.080000, -0.800000) -- (3.848596, -0.524224) -- cycle; 107 | \node[] at (4.080000,-0.800000) {$p(x_3| x_2, u_2)$}; 108 | \draw[] (9.860000, 9.171899) circle (0.360000); 109 | \node[] at (9.860000,9.171899) {$T_1$}; 110 | \draw[] (12.580000, 9.171899) circle (0.360000); 111 | \node[] at (12.580000,9.171899) {$T_2$}; 112 | \draw[] (15.300000, 9.171899) circle (0.360000); 113 | \node[] at (15.300000,9.171899) {$T_3$}; 114 | \draw[] (15.300000, 10.691899) circle (0.360000); 115 | \node[] at (15.300000,10.691899) {$T_4$}; 116 | \draw[] (12.580000, 10.691899) circle (0.360000); 117 | \node[] at (12.580000,10.691899) {$T_5$}; 118 | \draw[fill=black] (11.220000, 9.171899) circle (0.080000); 119 | \draw[fill=black] (13.940000, 9.171899) circle (0.080000); 120 | \draw[fill=black] (8.500000, 9.171899) circle (0.080000); 121 | \draw[fill=black] (12.580000, 9.931899) circle (0.080000); 122 | \draw[fill=black] (15.300000, 9.931899) circle (0.080000); 123 | \draw[fill=black] (13.940000, 10.691899) circle (0.080000); 124 | \draw[] (10.220000, 9.171899) -- (12.220000, 9.171899); 125 | \draw[] (12.940000, 9.171899) -- (14.940000, 9.171899); 126 | \draw[] (8.580000, 9.171899) -- (9.500000, 9.171899); 127 | \draw[] (12.580000, 9.531899) -- (12.580000, 10.331899); 128 | \draw[] (15.300000, 9.531899) -- (15.300000, 10.331899); 129 | \draw[] (14.940000, 10.691899) -- (12.940000, 10.691899); 130 | \draw[rounded corners=0.100000cm, fill=gray!20, draw=none] (7.800000, 10.295899) -- (9.200000, 10.295899) -- (9.200000, 9.647899) -- (7.800000, 9.647899) -- cycle; 131 | \draw[fill=gray!20, draw=none] (8.500000, 9.251899) -- (8.500000, 9.971899) -- (8.731404, 9.696123) -- cycle; 132 | \node[] at (8.500000,9.971899) {$f_p(T_1)$}; 133 | \draw[rounded corners=0.100000cm, fill=gray!20, draw=none] (10.305000, 10.255899) -- (12.055000, 10.255899) -- (12.055000, 9.607899) -- (10.305000, 9.607899) -- cycle; 134 | \draw[fill=gray!20, draw=none] (12.500000, 9.931899) -- (11.180000, 9.931899) -- (11.455776, 10.163303) -- cycle; 135 | \node[] at (11.180000,9.931899) {$f_l(T_5, T_2)$}; 136 | \draw[rounded corners=0.100000cm, fill=gray!20, draw=none] (13.065000, 10.215899) -- (14.815000, 10.215899) -- (14.815000, 9.567899) -- (13.065000, 9.567899) -- cycle; 137 | \draw[fill=gray!20, draw=none] (13.940000, 10.611899) -- (13.940000, 9.891899) -- (13.708596, 10.167675) -- cycle; 138 | \node[] at (13.940000,9.891899) {$f_b(T_4, T_5)$}; 139 | \draw[] (9.860000, 4.585949) circle (0.360000); 140 | \node[] at (9.860000,4.585949) {$T_1$}; 141 | \draw[] (12.580000, 4.585949) circle (0.360000); 142 | \node[] at (12.580000,4.585949) {$T_2$}; 143 | \draw[] (15.300000, 4.585949) circle (0.360000); 144 | \node[] at (15.300000,4.585949) {$T_3$}; 145 | \draw[] (13.940000, 6.105949) circle (0.360000); 146 | \node[] at (13.940000,6.105949) {$l_4$}; 147 | \draw[] (11.220000, 6.105949) circle (0.360000); 148 | \node[] at (11.220000,6.105949) {$l_5$}; 149 | \draw[fill=black] (11.220000, 4.585949) circle (0.080000); 150 | \draw[fill=black] (13.940000, 4.585949) circle (0.080000); 151 | \draw[fill=black] (8.500000, 4.585949) circle (0.080000); 152 | \draw[fill=black] (10.676000, 5.497949) circle (0.080000); 153 | \draw[fill=black] (11.764000, 5.497949) circle (0.080000); 154 | \draw[fill=black] (13.396000, 5.497949) circle (0.080000); 155 | \draw[fill=black] (14.484000, 5.497949) circle (0.080000); 156 | \draw[fill=black] (12.308000, 5.497949) circle (0.080000); 157 | \draw[] (10.220000, 4.585949) -- (12.220000, 4.585949); 158 | \draw[] (12.940000, 4.585949) -- (14.940000, 4.585949); 159 | \draw[] (8.580000, 4.585949) -- (9.500000, 4.585949); 160 | \draw[] (10.100046, 4.854236) -- (10.979954, 5.837663); 161 | \draw[] (12.339954, 4.854236) -- (11.460046, 5.837663); 162 | \draw[] (12.820046, 4.854236) -- (13.699954, 5.837663); 163 | \draw[] (15.059954, 4.854236) -- (14.180046, 5.837663); 164 | \draw[] (10.197350, 4.711629) -- (13.602650, 5.980270); 165 | \draw[rounded corners=0.100000cm, fill=gray!20, draw=none] (8.706051, 6.811899) -- (10.666051, 6.811899) -- (10.666051, 6.163899) -- (8.706051, 6.163899) -- cycle; 166 | \draw[fill=gray!20, draw=none] (10.619431, 5.554518) -- (9.686051, 6.487899) -- (10.044681, 6.456523) -- cycle; 167 | \node[] at (9.686051,6.487899) {$f_{br}(T_1, l_5)$}; 168 | \draw[] (9.860000, 0.000000) circle (0.360000); 169 | \node[] at (9.860000,0.000000) {$C_1$}; 170 | \draw[] (12.580000, 0.000000) circle (0.360000); 171 | \node[] at (12.580000,0.000000) {$C_2$}; 172 | \draw[] (15.300000, 0.000000) circle (0.360000); 173 | \node[] at (15.300000,0.000000) {$C_3$}; 174 | \draw[] (13.940000, 1.520000) circle (0.360000); 175 | \node[] at (13.940000,1.520000) {$p_4$}; 176 | \draw[] (11.220000, 1.520000) circle (0.360000); 177 | \node[] at (11.220000,1.520000) {$p_5$}; 178 | \draw[fill=black] (10.676000, 0.912000) circle (0.080000); 179 | \draw[fill=black] (11.764000, 0.912000) circle (0.080000); 180 | \draw[fill=black] (13.396000, 0.912000) circle (0.080000); 181 | \draw[fill=black] (14.484000, 0.912000) circle (0.080000); 182 | \draw[fill=black] (12.308000, 0.912000) circle (0.080000); 183 | \draw[] (10.100046, 0.268287) -- (10.979954, 1.251713); 184 | \draw[] (12.339954, 0.268287) -- (11.460046, 1.251713); 185 | \draw[] (12.820046, 0.268287) -- (13.699954, 1.251713); 186 | \draw[] (15.059954, 0.268287) -- (14.180046, 1.251713); 187 | \draw[] (10.197350, 0.125679) -- (13.602650, 1.394321); 188 | \draw[rounded corners=0.100000cm, fill=gray!20, draw=none] (8.706051, 2.225949) -- (10.666051, 2.225949) -- (10.666051, 1.577949) -- (8.706051, 1.577949) -- cycle; 189 | \draw[fill=gray!20, draw=none] (10.619431, 0.968569) -- (9.686051, 1.901949) -- (10.044681, 1.870573) -- cycle; 190 | \node[] at (9.686051,1.901949) {$f_{rp}(C_1, p_5)$}; 191 | \end{tikzpicture} 192 | \end{document} 193 | -------------------------------------------------------------------------------- /examples/flowchart.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/negrinho/sane_tikz/fd6f291d9815613594d724678cb91ac9d412fbb7/examples/flowchart.pdf -------------------------------------------------------------------------------- /examples/flowchart.py: -------------------------------------------------------------------------------- 1 | import sane_tikz.core as stz 2 | import sane_tikz.formatting as fmt 3 | 4 | box_height = 1.0 5 | box_width = 1.6 6 | box_spacing = 1.1 7 | box_roundness = 0.1 8 | shaft_width = 0.5 9 | shaft_height = 0.4 10 | head_width = 0.35 11 | head_height = 0.8 12 | 13 | lst = [ 14 | "A", 15 | "B", 16 | "C", 17 | "D", 18 | "E", 19 | "F", 20 | ] 21 | 22 | 23 | def box_with_text(s): 24 | s_fmt = fmt.rounded_corners(box_roundness) 25 | return [ 26 | stz.rectangle([0, 0], [box_width, -box_height], s_fmt), 27 | stz.latex([box_width / 2.0, -box_height / 2.0], s) 28 | ] 29 | 30 | 31 | def arrow(): 32 | s_fmt = fmt.fill_color_with_no_line("lightgray") 33 | a = stz.arrow(shaft_width, shaft_height, head_width, head_height, -90.0, 34 | s_fmt) 35 | return a 36 | 37 | 38 | boxes = [box_with_text(s) for s in lst] 39 | stz.distribute_vertically_with_spacing(boxes[::-1], box_spacing) 40 | 41 | arrows = [arrow() for _ in range(len(lst) - 1)] 42 | for i in range(len(boxes) - 1): 43 | to_cs = stz.center_coords(boxes[i:i + 2]) 44 | from_cs = stz.center_coords(arrows[i]) 45 | stz.translate_to_coords(arrows[i], from_cs, to_cs) 46 | 47 | stz.draw_to_tikz_standalone([boxes, arrows], "flowchart.tex") 48 | -------------------------------------------------------------------------------- /examples/flowchart.tex: -------------------------------------------------------------------------------- 1 | \documentclass{standalone} 2 | \usepackage[T1]{fontenc}\usepackage{tikz} 3 | \usepackage{amsmath, amsfonts} 4 | \usetikzlibrary{arrows.meta} 5 | \begin{document} 6 | \begin{tikzpicture} 7 | \draw[rounded corners=0.100000cm] (0.000000, 10.500000) -- (1.600000, 10.500000) -- (1.600000, 9.500000) -- (0.000000, 9.500000) -- cycle; 8 | \node[] at (0.800000,10.000000) {A}; 9 | \draw[rounded corners=0.100000cm] (0.000000, 8.400000) -- (1.600000, 8.400000) -- (1.600000, 7.400000) -- (0.000000, 7.400000) -- cycle; 10 | \node[] at (0.800000,7.900000) {B}; 11 | \draw[rounded corners=0.100000cm] (0.000000, 6.300000) -- (1.600000, 6.300000) -- (1.600000, 5.300000) -- (0.000000, 5.300000) -- cycle; 12 | \node[] at (0.800000,5.800000) {C}; 13 | \draw[rounded corners=0.100000cm] (0.000000, 4.200000) -- (1.600000, 4.200000) -- (1.600000, 3.200000) -- (0.000000, 3.200000) -- cycle; 14 | \node[] at (0.800000,3.700000) {D}; 15 | \draw[rounded corners=0.100000cm] (0.000000, 2.100000) -- (1.600000, 2.100000) -- (1.600000, 1.100000) -- (0.000000, 1.100000) -- cycle; 16 | \node[] at (0.800000,1.600000) {E}; 17 | \draw[rounded corners=0.100000cm] (0.000000, 0.000000) -- (1.600000, 0.000000) -- (1.600000, -1.000000) -- (0.000000, -1.000000) -- cycle; 18 | \node[] at (0.800000,-0.500000) {F}; 19 | \draw[fill=lightgray, draw=none] (1.000000, 9.375000) -- (1.000000, 8.875000) -- (1.200000, 8.875000) -- (0.800000, 8.525000) -- (0.400000, 8.875000) -- (0.600000, 8.875000) -- (0.600000, 9.375000) -- cycle; 20 | \draw[fill=lightgray, draw=none] (1.000000, 7.275000) -- (1.000000, 6.775000) -- (1.200000, 6.775000) -- (0.800000, 6.425000) -- (0.400000, 6.775000) -- (0.600000, 6.775000) -- (0.600000, 7.275000) -- cycle; 21 | \draw[fill=lightgray, draw=none] (1.000000, 5.175000) -- (1.000000, 4.675000) -- (1.200000, 4.675000) -- (0.800000, 4.325000) -- (0.400000, 4.675000) -- (0.600000, 4.675000) -- (0.600000, 5.175000) -- cycle; 22 | \draw[fill=lightgray, draw=none] (1.000000, 3.075000) -- (1.000000, 2.575000) -- (1.200000, 2.575000) -- (0.800000, 2.225000) -- (0.400000, 2.575000) -- (0.600000, 2.575000) -- (0.600000, 3.075000) -- cycle; 23 | \draw[fill=lightgray, draw=none] (1.000000, 0.975000) -- (1.000000, 0.475000) -- (1.200000, 0.475000) -- (0.800000, 0.125000) -- (0.400000, 0.475000) -- (0.600000, 0.475000) -- (0.600000, 0.975000) -- cycle; 24 | \end{tikzpicture} 25 | \end{document} 26 | -------------------------------------------------------------------------------- /examples/lda.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/negrinho/sane_tikz/fd6f291d9815613594d724678cb91ac9d412fbb7/examples/lda.pdf -------------------------------------------------------------------------------- /examples/lda.py: -------------------------------------------------------------------------------- 1 | # reproduction of Figure 7 from http://www.jmlr.org/papers/volume3/blei03a/blei03a.pdf 2 | 3 | import sane_tikz.core as stz 4 | import sane_tikz.formatting as fmt 5 | 6 | node_radius = 0.35 7 | node_spacing = 2.4 * node_radius 8 | label_spacing = 0.3 9 | delta_angle = 10.0 10 | horizontal_plate_spacing = 0.5 11 | vertical_plate_spacing = 0.25 12 | plate_label_spacing = 0.24 13 | 14 | 15 | def connect_horizontally(e_from, e_to): 16 | s_fmt = fmt.arrow_heads("end") 17 | cs_from = stz.coords_from_bbox_with_fn(e_from, stz.right_center_coords) 18 | cs_to = stz.coords_from_bbox_with_fn(e_to, stz.left_center_coords) 19 | return stz.line_segment(cs_from, cs_to, s_fmt) 20 | 21 | 22 | def connect_diagonally(e_from, e_to): 23 | s_fmt = fmt.arrow_heads("end") 24 | from_center_cs = stz.center_coords(e_from) 25 | to_center_cs = stz.center_coords(e_to) 26 | return stz.line_segment_between_circles(from_center_cs, node_radius, -90.0, 27 | to_center_cs, node_radius, 28 | 180.0 - delta_angle, s_fmt) 29 | 30 | 31 | def label_below(e, expr): 32 | cs_ref = stz.coords_from_bbox_with_fn(e, stz.bottom_center_coords) 33 | cs = stz.translate_coords_vertically(cs_ref, -label_spacing) 34 | return stz.latex(cs, expr) 35 | 36 | 37 | def label_left(e, expr): 38 | cs_ref = stz.coords_from_bbox_with_fn(e, stz.left_center_coords) 39 | cs = stz.translate_coords_horizontally(cs_ref, -label_spacing) 40 | return stz.latex(cs, expr) 41 | 42 | 43 | def label_right(e, expr): 44 | cs_ref = stz.coords_from_bbox_with_fn(e, stz.right_center_coords) 45 | cs = stz.translate_coords_horizontally(cs_ref, label_spacing) 46 | return stz.latex(cs, expr) 47 | 48 | 49 | def plate(e_lst, expr): 50 | top_left_cs, bottom_right_cs = stz.bbox(e_lst) 51 | r = stz.rectangle_from_additive_resizing(top_left_cs, bottom_right_cs, 52 | 2.0 * horizontal_plate_spacing, 53 | 2.0 * vertical_plate_spacing) 54 | l_cs = stz.translate_coords_antidiagonally( 55 | stz.bbox(r)[1], -plate_label_spacing) 56 | l = stz.latex(l_cs, expr) 57 | return [r, l] 58 | 59 | 60 | alpha_c = stz.circle([0, 0], node_radius) 61 | theta_c = stz.circle([0, 0], node_radius) 62 | z_c = stz.circle([0, 0], node_radius) 63 | w_c = stz.circle([0, 0], node_radius) 64 | eta_c = stz.circle([0, 0], node_radius) 65 | beta_c = stz.circle([0, 0], node_radius) 66 | 67 | w_c["tikz_str"] = fmt.combine_tikz_strs( 68 | [w_c["tikz_str"], fmt.fill_color("gray")]) 69 | 70 | stz.distribute_horizontally_with_spacing([alpha_c, theta_c, z_c, w_c], 71 | node_spacing) 72 | stz.distribute_horizontally_with_spacing([eta_c, beta_c], node_spacing) 73 | stz.place_above_and_align_to_the_center([eta_c, beta_c], 74 | [alpha_c, theta_c, z_c, w_c], 75 | node_spacing) 76 | 77 | alpha_l = label_below(alpha_c, "$\\alpha$") 78 | theta_l = label_below(theta_c, "$\\theta$") 79 | z_l = label_below(z_c, "$z$") 80 | w_l = label_below(w_c, "$w$") 81 | eta_l = label_left(eta_c, "$\\eta$") 82 | beta_l = label_right(beta_c, "$\\beta$") 83 | 84 | connections = [ 85 | connect_horizontally(alpha_c, theta_c), 86 | connect_horizontally(theta_c, z_c), 87 | connect_horizontally(z_c, w_c), 88 | connect_horizontally(eta_c, beta_c), 89 | connect_diagonally(beta_c, w_c), 90 | ] 91 | 92 | p1 = plate([z_c, w_c, z_l, w_l], "$N$") 93 | p2 = plate([theta_c, theta_l, p1], "$M$") 94 | p3 = plate([beta_c, beta_l], "$k$") 95 | 96 | e = [ 97 | alpha_c, theta_c, z_c, w_c, eta_c, beta_c, alpha_l, theta_l, z_l, w_l, 98 | eta_l, beta_l, connections, p1, p2, p3 99 | ] 100 | 101 | stz.draw_to_tikz_standalone(e, "lda.tex") -------------------------------------------------------------------------------- /examples/lda.tex: -------------------------------------------------------------------------------- 1 | \documentclass{standalone} 2 | \usepackage[T1]{fontenc}\usepackage{tikz} 3 | \usepackage{amsmath, amsfonts} 4 | \usetikzlibrary{arrows.meta} 5 | \begin{document} 6 | \begin{tikzpicture} 7 | \draw[] (0.000000, 0.000000) circle (0.350000); 8 | \draw[] (1.540000, 0.000000) circle (0.350000); 9 | \draw[] (3.080000, 0.000000) circle (0.350000); 10 | \draw[, fill=gray] (4.620000, 0.000000) circle (0.350000); 11 | \draw[] (1.540000, 1.540000) circle (0.350000); 12 | \draw[] (3.080000, 1.540000) circle (0.350000); 13 | \node[] at (0.000000,-0.650000) {$\alpha$}; 14 | \node[] at (1.540000,-0.650000) {$\theta$}; 15 | \node[] at (3.080000,-0.650000) {$z$}; 16 | \node[] at (4.620000,-0.650000) {$w$}; 17 | \node[] at (0.890000,1.540000) {$\eta$}; 18 | \node[] at (3.730000,1.540000) {$\beta$}; 19 | \draw[-latex] (0.350000, 0.000000) -- (1.190000, 0.000000); 20 | \draw[-latex] (1.890000, 0.000000) -- (2.730000, 0.000000); 21 | \draw[-latex] (3.430000, 0.000000) -- (4.270000, 0.000000); 22 | \draw[-latex] (1.890000, 1.540000) -- (2.730000, 1.540000); 23 | \draw[-latex] (3.080000, 1.190000) -- (4.275317, 0.060777); 24 | \draw[] (2.230000, 0.600000) -- (5.470000, 0.600000) -- (5.470000, -0.900000) -- (2.230000, -0.900000) -- cycle; 25 | \node[] at (5.230000,-0.660000) {$N$}; 26 | \draw[] (0.690000, 0.850000) -- (5.970000, 0.850000) -- (5.970000, -1.150000) -- (0.690000, -1.150000) -- cycle; 27 | \node[] at (5.730000,-0.910000) {$M$}; 28 | \draw[] (2.230000, 2.140000) -- (4.230000, 2.140000) -- (4.230000, 0.940000) -- (2.230000, 0.940000) -- cycle; 29 | \node[] at (3.990000,1.180000) {$k$}; 30 | \end{tikzpicture} 31 | \end{document} 32 | -------------------------------------------------------------------------------- /examples/pentagon.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/negrinho/sane_tikz/fd6f291d9815613594d724678cb91ac9d412fbb7/examples/pentagon.pdf -------------------------------------------------------------------------------- /examples/pentagon.py: -------------------------------------------------------------------------------- 1 | # answer to latex exchange question: https://tex.stackexchange.com/questions/528863/how-do-you-name-nodes-vertices-with-this-type-of-code/528885#528885 2 | 3 | import sane_tikz.core as stz 4 | import sane_tikz.formatting as fmt 5 | 6 | label_spacing = 0.25 7 | pentagon_radius = 1.2 8 | x_axis_length = 4.0 9 | y_axis_length = 3.0 10 | extra_length = 0.4 11 | a_circle_radius = 0.08 12 | s_fmt = fmt.arrow_heads("end") 13 | f_fmt = fmt.line_and_fill_colors('black', 'black') 14 | 15 | cs = [ 16 | stz.coords_on_circle([0, 0], pentagon_radius, 90.0 + i * (360.0 / 5)) 17 | for i in range(5) 18 | ] 19 | e = stz.closed_path(cs) 20 | 21 | origin_cs = stz.translate_coords_horizontally(cs[2], -1.0) 22 | x_end_cs = stz.translate_coords_horizontally(origin_cs, x_axis_length) 23 | y_end_cs = stz.translate_coords_vertically(origin_cs, y_axis_length) 24 | x_start_cs = stz.translate_coords_horizontally(origin_cs, -extra_length) 25 | y_start_cs = stz.translate_coords_vertically(origin_cs, -extra_length) 26 | x_label_cs = stz.translate_coords_vertically(x_end_cs, -label_spacing) 27 | y_label_cs = stz.translate_coords_horizontally(y_end_cs, -label_spacing) 28 | origin_label_cs = stz.translate_coords_diagonally(origin_cs, -label_spacing) 29 | 30 | axes = [ 31 | stz.line_segment(x_start_cs, x_end_cs, s_fmt), 32 | stz.line_segment(y_start_cs, y_end_cs, s_fmt) 33 | ] 34 | 35 | labels = [ 36 | stz.latex([cs[0][0], cs[0][1] + label_spacing], "$C$"), 37 | stz.latex([cs[1][0] - label_spacing, cs[1][1]], "$B$"), 38 | stz.latex([cs[2][0], cs[2][1] - a_circle_radius - label_spacing], 39 | "$A(1, 0)$"), 40 | stz.latex([cs[3][0], cs[3][1] - label_spacing], "$E$"), 41 | stz.latex([cs[4][0] + label_spacing, cs[4][1]], "$D$"), 42 | stz.circle(cs[2], a_circle_radius, f_fmt), 43 | stz.latex(x_label_cs, "$x$"), 44 | stz.latex(y_label_cs, "$y$"), 45 | stz.latex(origin_label_cs, "$O$"), 46 | ] 47 | 48 | stz.draw_to_tikz_standalone([e, labels, axes], "pentagon.tex") 49 | -------------------------------------------------------------------------------- /examples/pentagon.tex: -------------------------------------------------------------------------------- 1 | \documentclass{standalone} 2 | \usepackage[T1]{fontenc}\usepackage{tikz} 3 | \usepackage{amsmath, amsfonts} 4 | \usetikzlibrary{arrows.meta} 5 | \begin{document} 6 | \begin{tikzpicture} 7 | \draw[] (0.000000, 1.200000) -- (-1.141268, 0.370820) -- (-0.705342, -0.970820) -- (0.705342, -0.970820) -- (1.141268, 0.370820) -- cycle; 8 | \node[] at (0.000000,1.450000) {$C$}; 9 | \node[] at (-1.391268,0.370820) {$B$}; 10 | \node[] at (-0.705342,-1.300820) {$A(1, 0)$}; 11 | \node[] at (0.705342,-1.220820) {$E$}; 12 | \node[] at (1.391268,0.370820) {$D$}; 13 | \draw[fill=black, draw=black] (-0.705342, -0.970820) circle (0.080000); 14 | \node[] at (2.294658,-1.220820) {$x$}; 15 | \node[] at (-1.955342,2.029180) {$y$}; 16 | \node[] at (-1.955342,-1.220820) {$O$}; 17 | \draw[-latex] (-2.105342, -0.970820) -- (2.294658, -0.970820); 18 | \draw[-latex] (-1.705342, -1.370820) -- (-1.705342, 2.029180); 19 | \end{tikzpicture} 20 | \end{document} 21 | -------------------------------------------------------------------------------- /examples/segments.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/negrinho/sane_tikz/fd6f291d9815613594d724678cb91ac9d412fbb7/examples/segments.pdf -------------------------------------------------------------------------------- /examples/segments.py: -------------------------------------------------------------------------------- 1 | import sane_tikz.core as stz 2 | 3 | label_spacing = 0.25 4 | tick_label_spacing = 0.25 5 | tick_length = 0.25 6 | segment_spacing = 0.6 7 | length_multiplier = 0.8 8 | 9 | 10 | def segment(length, label_str, left_tick_label_str, right_tick_label_str): 11 | seg = stz.line_segment([0, 0], [length, 0]) 12 | left_tick = stz.centered_vertical_line_segment([0, 0], tick_length) 13 | right_tick = stz.centered_vertical_line_segment([length, 0], tick_length) 14 | left_tick_label = stz.latex([0, 0], left_tick_label_str) 15 | right_tick_label = stz.latex([0, 0], right_tick_label_str) 16 | stz.place_above_and_align_to_the_center(left_tick_label, left_tick, 17 | tick_label_spacing) 18 | stz.place_above_and_align_to_the_center(right_tick_label, right_tick, 19 | tick_label_spacing) 20 | seg_label = stz.latex([-label_spacing, 0], label_str) 21 | return [ 22 | seg, left_tick, right_tick, left_tick_label, right_tick_label, seg_label 23 | ] 24 | 25 | 26 | segs = [ 27 | segment(length_multiplier * 5, "A", "0", "5"), 28 | segment(length_multiplier * 1, "B", "2", "3"), 29 | segment(length_multiplier * 3, "C", "1", "4") 30 | ] 31 | 32 | stz.distribute_vertically_with_spacing(segs[::-1], segment_spacing) 33 | stz.draw_to_tikz_standalone(segs, "segments.tex") 34 | -------------------------------------------------------------------------------- /examples/segments.tex: -------------------------------------------------------------------------------- 1 | \documentclass{standalone} 2 | \usepackage[T1]{fontenc}\usepackage{tikz} 3 | \usepackage{amsmath, amsfonts} 4 | \usetikzlibrary{arrows.meta} 5 | \begin{document} 6 | \begin{tikzpicture} 7 | \draw[] (0.000000, 2.200000) -- (4.000000, 2.200000); 8 | \draw[] (0.000000, 2.325000) -- (0.000000, 2.075000); 9 | \draw[] (4.000000, 2.325000) -- (4.000000, 2.075000); 10 | \node[] at (0.000000,2.575000) {0}; 11 | \node[] at (4.000000,2.575000) {5}; 12 | \node[] at (-0.250000,2.200000) {A}; 13 | \draw[] (0.000000, 1.100000) -- (0.800000, 1.100000); 14 | \draw[] (0.000000, 1.225000) -- (0.000000, 0.975000); 15 | \draw[] (0.800000, 1.225000) -- (0.800000, 0.975000); 16 | \node[] at (0.000000,1.475000) {2}; 17 | \node[] at (0.800000,1.475000) {3}; 18 | \node[] at (-0.250000,1.100000) {B}; 19 | \draw[] (0.000000, 0.000000) -- (2.400000, 0.000000); 20 | \draw[] (0.000000, 0.125000) -- (0.000000, -0.125000); 21 | \draw[] (2.400000, 0.125000) -- (2.400000, -0.125000); 22 | \node[] at (0.000000,0.375000) {1}; 23 | \node[] at (2.400000,0.375000) {4}; 24 | \node[] at (-0.250000,0.000000) {C}; 25 | \end{tikzpicture} 26 | \end{document} 27 | -------------------------------------------------------------------------------- /examples/transformer.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/negrinho/sane_tikz/fd6f291d9815613594d724678cb91ac9d412fbb7/examples/transformer.pdf -------------------------------------------------------------------------------- /examples/transformer.py: -------------------------------------------------------------------------------- 1 | import sane_tikz.core as stz 2 | import sane_tikz.formatting as fmt 3 | import numpy as np 4 | import math 5 | 6 | width = 2.5 7 | line_width = 3.0 * fmt.standard_line_width 8 | rectangle_roundness = 0.1 9 | connector_roundness = 0.2 10 | to_add_norm_spacing = 0.15 11 | per_line_height = 0.40 12 | percent_width_trident_spacing = 0.45 13 | plus_circle_radius = 0.2 14 | sine_circle_radius = 2 * plus_circle_radius 15 | spacing_between_text_and_arrows = 0.0 16 | arrow_length = 0.6 17 | residual_spacing = 2.0 18 | trident_alpha = 0.75 19 | trident_spacing = 0.4 20 | spacing_between_towers = 1.5 21 | bbox_spacing = 0.45 22 | bbox_roundness = 0.3 23 | 24 | name2color = { 25 | "emb_color": (252, 224, 225), 26 | "multi_head_attention_color": (252, 226, 187), 27 | "add_norm_color": (242, 243, 193), 28 | "ff_color": (194, 232, 247), 29 | "softmax_color": (203, 231, 207), 30 | "linear_color": (220, 223, 240), 31 | "gray_bbox_color": (243, 243, 244) 32 | } 33 | 34 | s_arr = fmt.combine_tikz_strs( 35 | [fmt.line_width(line_width), 36 | fmt.arrow_heads("end")]) 37 | 38 | s_lw = fmt.combine_tikz_strs([fmt.line_width(line_width)]) 39 | 40 | s_con = s_bbox = fmt.combine_tikz_strs([ 41 | fmt.arrow_heads("end"), 42 | fmt.line_width(line_width), 43 | fmt.rounded_corners(connector_roundness) 44 | ]) 45 | 46 | s_bbox = fmt.combine_tikz_strs([ 47 | fmt.fill_color("gray_bbox_color"), 48 | fmt.line_width(line_width), 49 | fmt.rounded_corners(bbox_roundness) 50 | ]) 51 | 52 | 53 | def trident_coords(e): 54 | top_left_cs, bottom_right_cs = stz.bbox(e) 55 | center_cs = stz.bottom_center_coords(top_left_cs, bottom_right_cs) 56 | left_cs = stz.translate_coords_horizontally(center_cs, 57 | -trident_alpha * width / 2.0) 58 | right_cs = stz.translate_coords_horizontally(center_cs, 59 | trident_alpha * width / 2.0) 60 | 61 | cs_lst = [left_cs, center_cs, right_cs] 62 | translated_cs_lst = [ 63 | stz.translate_coords_vertically(cs, -trident_spacing) for cs in cs_lst 64 | ] 65 | return cs_lst, translated_cs_lst 66 | 67 | 68 | def lst2str(s_lst): 69 | return " \\vspace{-0.05cm} \\linebreak ".join(s_lst) 70 | 71 | 72 | def rectangle(height, color_name): 73 | s_fmt = fmt.combine_tikz_strs([ 74 | fmt.line_width(line_width), 75 | fmt.fill_color(color_name), 76 | fmt.rounded_corners(rectangle_roundness) 77 | ]) 78 | return stz.rectangle_from_width_and_height([0, 0], height, width, s_fmt) 79 | 80 | 81 | def rectangle_with_text(color_name, s_lst): 82 | height = 0.1 + per_line_height * len(s_lst) 83 | s_width = fmt.combine_tikz_strs([fmt.text_width(width), "align=center"]) 84 | r = rectangle(height, color_name) 85 | cs = stz.center_coords(r) 86 | s = " \\vspace{-0.05cm} \\linebreak ".join(s_lst) 87 | t = stz.latex(cs, s, s_width) 88 | return [r, t] 89 | 90 | 91 | def rectangle_with_add_norm(color_name, s_lst): 92 | r1 = rectangle_with_text("add_norm_color", ["Add \\& Norm"]) 93 | r2 = rectangle_with_text(color_name, s_lst) 94 | 95 | top_left_cs, bottom_right_cs = stz.bbox(r2) 96 | cs = stz.translate_coords_vertically( 97 | stz.top_center_coords(top_left_cs, bottom_right_cs), 98 | to_add_norm_spacing) 99 | stz.translate_bbox_bottom_center_to_coords(r1, cs) 100 | c = connect_straight_vertical(r2, r1) 101 | return [r1, r2, c] 102 | 103 | 104 | def connect_straight_vertical(e_from, e_to): 105 | from_cs = stz.coords_from_bbox_with_fn(e_from, stz.top_center_coords) 106 | to_cs = stz.coords_from_bbox_with_fn(e_to, stz.bottom_center_coords) 107 | return stz.line_segment(from_cs, to_cs, s_lw) 108 | 109 | 110 | def connect_straight_horizontal(e_from, e_to): 111 | from_cs = stz.coords_from_bbox_with_fn(e_from, stz.right_center_coords) 112 | to_cs = stz.coords_from_bbox_with_fn(e_to, stz.left_center_coords) 113 | return stz.line_segment(from_cs, to_cs, s_lw) 114 | 115 | 116 | def connect_straight_with_arrow(e_from, e_to): 117 | from_cs = stz.coords_from_bbox_with_fn(e_from, stz.top_center_coords) 118 | to_cs = stz.coords_from_bbox_with_fn(e_to, stz.bottom_center_coords) 119 | return stz.line_segment(from_cs, to_cs, s_arr) 120 | 121 | 122 | def connect_residual(e_with_addnorm, bottom_spacing, side_spacing): 123 | from_cs = stz.coords_from_bbox_with_fn(e_with_addnorm, 124 | stz.bottom_center_coords) 125 | from_cs = stz.translate_coords_vertically(from_cs, -bottom_spacing) 126 | 127 | if side_spacing < 0: 128 | to_cs = stz.coords_from_bbox_with_fn(e_with_addnorm[0], 129 | stz.left_center_coords) 130 | else: 131 | to_cs = stz.coords_from_bbox_with_fn(e_with_addnorm[0], 132 | stz.right_center_coords) 133 | cs = stz.translate_coords_horizontally(from_cs, side_spacing) 134 | return stz.open_path([from_cs, cs, [cs[0], to_cs[1]], to_cs], s_con) 135 | 136 | 137 | def circle_with_sine(): 138 | r = sine_circle_radius 139 | alpha = 0.6 * r 140 | delta = 0.02 141 | circle = stz.circle([0, 0], r, s_lw) 142 | k = 2.0 * math.pi 143 | xs = np.linspace(0.0, k) 144 | ys = np.sin(xs) 145 | cs_lst = [] 146 | for x, y in zip(xs, ys): 147 | cs_lst.append([ 148 | stz.axis_value_to_canvas_value(-r + delta, 0.0, r - delta, k, x), 149 | stz.axis_value_to_canvas_value(-r + delta, -r / alpha, r - delta, 150 | r / alpha, y) 151 | ]) 152 | sine = stz.open_path(cs_lst, s_lw) 153 | return [circle, sine] 154 | 155 | 156 | def circle_with_plus(): 157 | r = plus_circle_radius 158 | circle = stz.circle([0, 0], r, s_lw) 159 | plus = [ 160 | stz.centered_horizontal_line_segment([0, 0], 1.6 * r, s_lw), 161 | stz.centered_vertical_line_segment([0, 0], 1.6 * r, s_lw), 162 | ] 163 | return [circle, plus] 164 | 165 | 166 | def arrow_in(e): 167 | to_cs = stz.coords_from_bbox_with_fn(e, stz.bottom_center_coords) 168 | from_cs = stz.translate_coords_vertically(to_cs, -arrow_length) 169 | return stz.line_segment(from_cs, to_cs, s_arr) 170 | 171 | 172 | def arrow_out(e): 173 | from_cs = stz.coords_from_bbox_with_fn(e, stz.top_center_coords) 174 | to_cs = stz.translate_coords_vertically(from_cs, arrow_length) 175 | return stz.line_segment(from_cs, to_cs, s_arr) 176 | 177 | 178 | ### left tower 179 | ier = rectangle_with_text("emb_color", ["Input", "Embedding"]) 180 | cl = circle_with_plus() 181 | sl = circle_with_sine() 182 | mha1_an = rectangle_with_add_norm("multi_head_attention_color", 183 | ["Multi-Head", "Attention"]) 184 | ff1_an = rectangle_with_add_norm("ff_color", ["Feed", "Forward"]) 185 | 186 | stz.place_above_and_align_to_the_center(cl, ier, 0.4) 187 | stz.place_to_the_left_and_align_to_the_center(sl, cl, 0.3) 188 | stz.place_above_and_align_to_the_center(mha1_an, cl, 1.33) 189 | stz.place_above_and_align_to_the_center(ff1_an, mha1_an, 1.0) 190 | 191 | ### right tower 192 | oer = rectangle_with_text("emb_color", ["Output", "Embedding"]) 193 | cr = circle_with_plus() 194 | sr = circle_with_sine() 195 | mha2_an = rectangle_with_add_norm("multi_head_attention_color", 196 | ["Multi-Head", "Attention"]) 197 | mmha_an = rectangle_with_add_norm("multi_head_attention_color", 198 | ["Masked", "Multi-Head", "Attention"]) 199 | ff2_an = rectangle_with_add_norm("ff_color", ["Feed", "Forward"]) 200 | linear = rectangle_with_text("linear_color", ["Linear"]) 201 | softmax = rectangle_with_text("softmax_color", ["Softmax"]) 202 | 203 | stz.place_to_the_right_and_align_to_the_bottom(oer, ier, spacing_between_towers) 204 | stz.place_above_and_align_to_the_center(cr, oer, 0.4) 205 | stz.place_to_the_right_and_align_to_the_center(sr, cr, 0.3) 206 | stz.place_above_and_align_to_the_center(mmha_an, cr, 1.33) 207 | stz.place_above_and_align_to_the_center(mha2_an, mmha_an, 1.0) 208 | stz.place_above_and_align_to_the_center(ff2_an, mha2_an, 1.0) 209 | stz.place_above_and_align_to_the_center(ff2_an, mha2_an, 1.0) 210 | stz.place_above_and_align_to_the_center(linear, ff2_an, 0.6) 211 | stz.place_above_and_align_to_the_center(softmax, linear, 0.6) 212 | 213 | ##### 214 | connections = [ 215 | connect_straight_with_arrow(mha1_an, ff1_an), 216 | connect_straight_with_arrow(mha2_an, ff2_an), 217 | connect_straight_with_arrow(ff2_an, linear), 218 | connect_straight_with_arrow(linear, softmax), 219 | connect_straight_with_arrow(ier, cl), 220 | connect_straight_with_arrow(cl, mha1_an), 221 | connect_straight_with_arrow(cr, mmha_an), 222 | connect_straight_with_arrow(oer, cr), 223 | connect_straight_horizontal(sl, cl), 224 | connect_straight_horizontal(cr, sr) 225 | ] 226 | 227 | connections.extend([ 228 | connect_residual(ff1_an, 0.6, -residual_spacing), 229 | connect_residual(mha1_an, 0.6, -residual_spacing), 230 | connect_residual(mmha_an, 0.6, residual_spacing), 231 | connect_residual(mha2_an, 0.6, residual_spacing), 232 | connect_residual(ff2_an, 0.6, residual_spacing) 233 | ]) 234 | 235 | ### bounding boxes 236 | b = stz.bbox([ff1_an, mha1_an, connections[-4]]) 237 | bb1 = stz.rectangle_from_additive_resizing(b[0], b[1], bbox_spacing, 238 | bbox_spacing, s_bbox) 239 | b = stz.bbox([ff2_an, mmha_an, connections[-2], connections[-3]]) 240 | bb2 = stz.rectangle_from_additive_resizing(b[0], b[1], bbox_spacing, 241 | bbox_spacing, s_bbox) 242 | 243 | ### trident connections 244 | tri_cs, translated_tri_cs = trident_coords(mha1_an) 245 | e1 = stz.open_path([ 246 | translated_tri_cs[1], 247 | stz.bottom_left_coords(translated_tri_cs[1], tri_cs[0]), tri_cs[0] 248 | ], s_con) 249 | e2 = stz.open_path([ 250 | translated_tri_cs[1], 251 | stz.bottom_right_coords(translated_tri_cs[1], tri_cs[2]), tri_cs[2] 252 | ], s_con) 253 | connections.extend([e1, e2]) 254 | 255 | tri_cs, translated_tri_cs = trident_coords(mmha_an) 256 | e1 = stz.open_path([ 257 | translated_tri_cs[1], 258 | stz.bottom_left_coords(translated_tri_cs[1], tri_cs[0]), tri_cs[0] 259 | ], s_con) 260 | e2 = stz.open_path([ 261 | translated_tri_cs[1], 262 | stz.bottom_right_coords(translated_tri_cs[1], tri_cs[2]), tri_cs[2] 263 | ], s_con) 264 | connections.extend([e1, e2]) 265 | 266 | tri_cs, translated_tri_cs = trident_coords(mha2_an) 267 | # the leftmost two 268 | from_cs = stz.coords_from_bbox_with_fn(ff1_an, stz.top_center_coords) 269 | mid_cs = stz.midway_coords(stz.bbox(bb1)[1], stz.bbox(bb2)[0]) 270 | to_cs = translated_tri_cs[0] 271 | cs = stz.translate_coords_vertically(from_cs, 1.0) 272 | e1 = stz.open_path([ 273 | from_cs, cs, [mid_cs[0], cs[1]], [mid_cs[0], to_cs[1]], 274 | translated_tri_cs[0], tri_cs[0] 275 | ], s_con) 276 | 277 | e2 = stz.open_path([ 278 | from_cs, cs, [mid_cs[0], cs[1]], [mid_cs[0], to_cs[1]], 279 | translated_tri_cs[1], tri_cs[1] 280 | ], s_con) 281 | 282 | # the rightmost one 283 | from_cs = stz.coords_from_bbox_with_fn(mmha_an, stz.top_center_coords) 284 | e3 = stz.open_path( 285 | [from_cs, translated_tri_cs[1], translated_tri_cs[2], tri_cs[2]], s_con) 286 | connections.extend([e1, e2, e3]) 287 | 288 | arrows = [arrow_in(ier), arrow_in(oer), arrow_out(softmax)] 289 | 290 | ### annotations 291 | # arrow text 292 | s_fmt = fmt.combine_tikz_strs( 293 | [fmt.text_width(width), "anchor=north", "align=center"]) 294 | cs = stz.translate_coords_vertically( 295 | stz.coords_from_bbox_with_fn(arrows[0], stz.bottom_center_coords), 296 | -spacing_between_text_and_arrows) 297 | a1 = stz.latex(cs, "Inputs", s_fmt) 298 | 299 | cs = stz.translate_coords_vertically( 300 | stz.coords_from_bbox_with_fn(arrows[1], stz.bottom_center_coords), 301 | -spacing_between_text_and_arrows) 302 | a2 = stz.latex(cs, lst2str(["Outputs", "(shifted right)"]), s_fmt) 303 | 304 | s_fmt = fmt.combine_tikz_strs( 305 | [fmt.text_width(width), "anchor=south", "align=center"]) 306 | 307 | cs = stz.translate_coords_vertically( 308 | stz.coords_from_bbox_with_fn(arrows[2], stz.top_center_coords), 309 | spacing_between_text_and_arrows) 310 | a3 = stz.latex(cs, lst2str(["Output", "Probabilities"]), s_fmt) 311 | 312 | # side text 313 | spacing = 0.2 314 | cs = stz.coords_from_bbox_with_fn(bb1, stz.left_center_coords) 315 | a4 = stz.latex([cs[0] - spacing, cs[1]], "$N\\times$", 316 | fmt.anchor("right_center")) 317 | cs = stz.coords_from_bbox_with_fn(bb2, stz.right_center_coords) 318 | a5 = stz.latex([cs[0] + spacing, cs[1]], "$N\\times$", 319 | fmt.anchor("left_center")) 320 | 321 | s_fn = lambda side: fmt.combine_tikz_strs( 322 | [fmt.text_width(2.0), fmt.anchor(side + "_center")]) 323 | cs = stz.coords_from_bbox_with_fn(sl, stz.left_center_coords) 324 | a6 = stz.latex([cs[0] + 0.3, cs[1]], lst2str(["Positional", "Encoding"]), 325 | s_fn("right")) 326 | cs = stz.coords_from_bbox_with_fn(sr, stz.right_center_coords) 327 | a7 = stz.latex([cs[0] + 0.2, cs[1]], lst2str(["Positional", "Encoding"]), 328 | s_fn("left")) 329 | 330 | annotations = [a1, a2, a3, a4, a5, a6, a7] 331 | 332 | # all 333 | e = [ 334 | bb1, bb2, ier, oer, mha1_an, mha2_an, mmha_an, ff1_an, ff2_an, linear, 335 | softmax, cl, cr, sl, sr, connections, arrows, annotations 336 | ] 337 | 338 | stz.draw_to_tikz_standalone(e, "transformer.tex", name2color) -------------------------------------------------------------------------------- /examples/transformer.tex: -------------------------------------------------------------------------------- 1 | \documentclass{standalone} 2 | \usepackage[T1]{fontenc}\usepackage{tikz} 3 | \usepackage{amsmath, amsfonts} 4 | \usetikzlibrary{arrows.meta} 5 | \begin{document} 6 | \begin{tikzpicture} 7 | \definecolor{emb_color}{RGB}{252,224,225} 8 | \definecolor{multi_head_attention_color}{RGB}{252,226,187} 9 | \definecolor{add_norm_color}{RGB}{242,243,193} 10 | \definecolor{ff_color}{RGB}{194,232,247} 11 | \definecolor{softmax_color}{RGB}{203,231,207} 12 | \definecolor{linear_color}{RGB}{220,223,240} 13 | \definecolor{gray_bbox_color}{RGB}{243,243,244} 14 | \draw[fill=gray_bbox_color, line width=0.046875cm, rounded corners=0.300000cm] (-0.975000, 6.455000) -- (2.725000, 6.455000) -- (2.725000, 1.305000) -- (-0.975000, 1.305000) -- cycle; 15 | \draw[fill=gray_bbox_color, line width=0.046875cm, rounded corners=0.300000cm] (3.775000, 9.405000) -- (7.475000, 9.405000) -- (7.475000, 1.305000) -- (3.775000, 1.305000) -- cycle; 16 | \draw[line width=0.046875cm, fill=emb_color, rounded corners=0.100000cm] (0.000000, 0.000000) -- (2.500000, 0.000000) -- (2.500000, -0.900000) -- (0.000000, -0.900000) -- cycle; 17 | \node[text width=2.500000cm, align=center] at (1.250000,-0.450000) {Input \vspace{-0.05cm} \linebreak Embedding}; 18 | \draw[line width=0.046875cm, fill=emb_color, rounded corners=0.100000cm] (4.000000, 0.000000) -- (6.500000, 0.000000) -- (6.500000, -0.900000) -- (4.000000, -0.900000) -- cycle; 19 | \node[text width=2.500000cm, align=center] at (5.250000,-0.450000) {Output \vspace{-0.05cm} \linebreak Embedding}; 20 | \draw[line width=0.046875cm, fill=add_norm_color, rounded corners=0.100000cm] (0.000000, 3.680000) -- (2.500000, 3.680000) -- (2.500000, 3.180000) -- (0.000000, 3.180000) -- cycle; 21 | \node[text width=2.500000cm, align=center] at (1.250000,3.430000) {Add \& Norm}; 22 | \draw[line width=0.046875cm, fill=multi_head_attention_color, rounded corners=0.100000cm] (0.000000, 3.030000) -- (2.500000, 3.030000) -- (2.500000, 2.130000) -- (0.000000, 2.130000) -- cycle; 23 | \node[text width=2.500000cm, align=center] at (1.250000,2.580000) {Multi-Head \vspace{-0.05cm} \linebreak Attention}; 24 | \draw[line width=0.046875cm] (1.250000, 3.030000) -- (1.250000, 3.180000); 25 | \draw[line width=0.046875cm, fill=add_norm_color, rounded corners=0.100000cm] (4.000000, 6.630000) -- (6.500000, 6.630000) -- (6.500000, 6.130000) -- (4.000000, 6.130000) -- cycle; 26 | \node[text width=2.500000cm, align=center] at (5.250000,6.380000) {Add \& Norm}; 27 | \draw[line width=0.046875cm, fill=multi_head_attention_color, rounded corners=0.100000cm] (4.000000, 5.980000) -- (6.500000, 5.980000) -- (6.500000, 5.080000) -- (4.000000, 5.080000) -- cycle; 28 | \node[text width=2.500000cm, align=center] at (5.250000,5.530000) {Multi-Head \vspace{-0.05cm} \linebreak Attention}; 29 | \draw[line width=0.046875cm] (5.250000, 5.980000) -- (5.250000, 6.130000); 30 | \draw[line width=0.046875cm, fill=add_norm_color, rounded corners=0.100000cm] (4.000000, 4.080000) -- (6.500000, 4.080000) -- (6.500000, 3.580000) -- (4.000000, 3.580000) -- cycle; 31 | \node[text width=2.500000cm, align=center] at (5.250000,3.830000) {Add \& Norm}; 32 | \draw[line width=0.046875cm, fill=multi_head_attention_color, rounded corners=0.100000cm] (4.000000, 3.430000) -- (6.500000, 3.430000) -- (6.500000, 2.130000) -- (4.000000, 2.130000) -- cycle; 33 | \node[text width=2.500000cm, align=center] at (5.250000,2.780000) {Masked \vspace{-0.05cm} \linebreak Multi-Head \vspace{-0.05cm} \linebreak Attention}; 34 | \draw[line width=0.046875cm] (5.250000, 3.430000) -- (5.250000, 3.580000); 35 | \draw[line width=0.046875cm, fill=add_norm_color, rounded corners=0.100000cm] (0.000000, 6.230000) -- (2.500000, 6.230000) -- (2.500000, 5.730000) -- (0.000000, 5.730000) -- cycle; 36 | \node[text width=2.500000cm, align=center] at (1.250000,5.980000) {Add \& Norm}; 37 | \draw[line width=0.046875cm, fill=ff_color, rounded corners=0.100000cm] (0.000000, 5.580000) -- (2.500000, 5.580000) -- (2.500000, 4.680000) -- (0.000000, 4.680000) -- cycle; 38 | \node[text width=2.500000cm, align=center] at (1.250000,5.130000) {Feed \vspace{-0.05cm} \linebreak Forward}; 39 | \draw[line width=0.046875cm] (1.250000, 5.580000) -- (1.250000, 5.730000); 40 | \draw[line width=0.046875cm, fill=add_norm_color, rounded corners=0.100000cm] (4.000000, 9.180000) -- (6.500000, 9.180000) -- (6.500000, 8.680000) -- (4.000000, 8.680000) -- cycle; 41 | \node[text width=2.500000cm, align=center] at (5.250000,8.930000) {Add \& Norm}; 42 | \draw[line width=0.046875cm, fill=ff_color, rounded corners=0.100000cm] (4.000000, 8.530000) -- (6.500000, 8.530000) -- (6.500000, 7.630000) -- (4.000000, 7.630000) -- cycle; 43 | \node[text width=2.500000cm, align=center] at (5.250000,8.080000) {Feed \vspace{-0.05cm} \linebreak Forward}; 44 | \draw[line width=0.046875cm] (5.250000, 8.530000) -- (5.250000, 8.680000); 45 | \draw[line width=0.046875cm, fill=linear_color, rounded corners=0.100000cm] (4.000000, 10.280000) -- (6.500000, 10.280000) -- (6.500000, 9.780000) -- (4.000000, 9.780000) -- cycle; 46 | \node[text width=2.500000cm, align=center] at (5.250000,10.030000) {Linear}; 47 | \draw[line width=0.046875cm, fill=softmax_color, rounded corners=0.100000cm] (4.000000, 11.380000) -- (6.500000, 11.380000) -- (6.500000, 10.880000) -- (4.000000, 10.880000) -- cycle; 48 | \node[text width=2.500000cm, align=center] at (5.250000,11.130000) {Softmax}; 49 | \draw[line width=0.046875cm] (1.250000, 0.600000) circle (0.200000); 50 | \draw[line width=0.046875cm] (1.410000, 0.600000) -- (1.090000, 0.600000); 51 | \draw[line width=0.046875cm] (1.250000, 0.760000) -- (1.250000, 0.440000); 52 | \draw[line width=0.046875cm] (5.250000, 0.600000) circle (0.200000); 53 | \draw[line width=0.046875cm] (5.410000, 0.600000) -- (5.090000, 0.600000); 54 | \draw[line width=0.046875cm] (5.250000, 0.760000) -- (5.250000, 0.440000); 55 | \draw[line width=0.046875cm] (0.350000, 0.600000) circle (0.400000); 56 | \draw[line width=0.046875cm] (-0.030000, 0.600000) -- (-0.014490, 0.629156) -- (0.001020, 0.657833) -- (0.016531, 0.685561) -- (0.032041, 0.711884) -- (0.047551, 0.736369) -- (0.063061, 0.758616) -- (0.078571, 0.778258) -- (0.094082, 0.794973) -- (0.109592, 0.808486) -- (0.125102, 0.818576) -- (0.140612, 0.825077) -- (0.156122, 0.827883) -- (0.171633, 0.826946) -- (0.187143, 0.822284) -- (0.202653, 0.813971) -- (0.218163, 0.802145) -- (0.233673, 0.786999) -- (0.249184, 0.768783) -- (0.264694, 0.747796) -- (0.280204, 0.724382) -- (0.295714, 0.698925) -- (0.311224, 0.671845) -- (0.326735, 0.643584) -- (0.342245, 0.614608) -- (0.357755, 0.585392) -- (0.373265, 0.556416) -- (0.388776, 0.528155) -- (0.404286, 0.501075) -- (0.419796, 0.475618) -- (0.435306, 0.452204) -- (0.450816, 0.431217) -- (0.466327, 0.413001) -- (0.481837, 0.397855) -- (0.497347, 0.386029) -- (0.512857, 0.377716) -- (0.528367, 0.373054) -- (0.543878, 0.372117) -- (0.559388, 0.374923) -- (0.574898, 0.381424) -- (0.590408, 0.391514) -- (0.605918, 0.405027) -- (0.621429, 0.421742) -- (0.636939, 0.441384) -- (0.652449, 0.463631) -- (0.667959, 0.488116) -- (0.683469, 0.514439) -- (0.698980, 0.542167) -- (0.714490, 0.570844) -- (0.730000, 0.600000); 57 | \draw[line width=0.046875cm] (6.150000, 0.600000) circle (0.400000); 58 | \draw[line width=0.046875cm] (5.770000, 0.600000) -- (5.785510, 0.629156) -- (5.801020, 0.657833) -- (5.816531, 0.685561) -- (5.832041, 0.711884) -- (5.847551, 0.736369) -- (5.863061, 0.758616) -- (5.878571, 0.778258) -- (5.894082, 0.794973) -- (5.909592, 0.808486) -- (5.925102, 0.818576) -- (5.940612, 0.825077) -- (5.956122, 0.827883) -- (5.971633, 0.826946) -- (5.987143, 0.822284) -- (6.002653, 0.813971) -- (6.018163, 0.802145) -- (6.033673, 0.786999) -- (6.049184, 0.768783) -- (6.064694, 0.747796) -- (6.080204, 0.724382) -- (6.095714, 0.698925) -- (6.111224, 0.671845) -- (6.126735, 0.643584) -- (6.142245, 0.614608) -- (6.157755, 0.585392) -- (6.173265, 0.556416) -- (6.188776, 0.528155) -- (6.204286, 0.501075) -- (6.219796, 0.475618) -- (6.235306, 0.452204) -- (6.250816, 0.431217) -- (6.266327, 0.413001) -- (6.281837, 0.397855) -- (6.297347, 0.386029) -- (6.312857, 0.377716) -- (6.328367, 0.373054) -- (6.343878, 0.372117) -- (6.359388, 0.374923) -- (6.374898, 0.381424) -- (6.390408, 0.391514) -- (6.405918, 0.405027) -- (6.421429, 0.421742) -- (6.436939, 0.441384) -- (6.452449, 0.463631) -- (6.467959, 0.488116) -- (6.483469, 0.514439) -- (6.498980, 0.542167) -- (6.514490, 0.570844) -- (6.530000, 0.600000); 59 | \draw[line width=0.046875cm, -latex] (1.250000, 3.680000) -- (1.250000, 4.680000); 60 | \draw[line width=0.046875cm, -latex] (5.250000, 6.630000) -- (5.250000, 7.630000); 61 | \draw[line width=0.046875cm, -latex] (5.250000, 9.180000) -- (5.250000, 9.780000); 62 | \draw[line width=0.046875cm, -latex] (5.250000, 10.280000) -- (5.250000, 10.880000); 63 | \draw[line width=0.046875cm, -latex] (1.250000, 0.000000) -- (1.250000, 0.400000); 64 | \draw[line width=0.046875cm, -latex] (1.250000, 0.800000) -- (1.250000, 2.130000); 65 | \draw[line width=0.046875cm, -latex] (5.250000, 0.800000) -- (5.250000, 2.130000); 66 | \draw[line width=0.046875cm, -latex] (5.250000, 0.000000) -- (5.250000, 0.400000); 67 | \draw[line width=0.046875cm] (0.750000, 0.600000) -- (1.050000, 0.600000); 68 | \draw[line width=0.046875cm] (5.450000, 0.600000) -- (5.750000, 0.600000); 69 | \draw[-latex, line width=0.046875cm, rounded corners=0.200000cm] (1.250000, 4.080000) -- (-0.750000, 4.080000) -- (-0.750000, 5.980000) -- (0.000000, 5.980000); 70 | \draw[-latex, line width=0.046875cm, rounded corners=0.200000cm] (1.250000, 1.530000) -- (-0.750000, 1.530000) -- (-0.750000, 3.430000) -- (0.000000, 3.430000); 71 | \draw[-latex, line width=0.046875cm, rounded corners=0.200000cm] (5.250000, 1.530000) -- (7.250000, 1.530000) -- (7.250000, 3.830000) -- (6.500000, 3.830000); 72 | \draw[-latex, line width=0.046875cm, rounded corners=0.200000cm] (5.250000, 4.480000) -- (7.250000, 4.480000) -- (7.250000, 6.380000) -- (6.500000, 6.380000); 73 | \draw[-latex, line width=0.046875cm, rounded corners=0.200000cm] (5.250000, 7.030000) -- (7.250000, 7.030000) -- (7.250000, 8.930000) -- (6.500000, 8.930000); 74 | \draw[-latex, line width=0.046875cm, rounded corners=0.200000cm] (1.250000, 1.730000) -- (0.312500, 1.730000) -- (0.312500, 2.130000); 75 | \draw[-latex, line width=0.046875cm, rounded corners=0.200000cm] (1.250000, 1.730000) -- (2.187500, 1.730000) -- (2.187500, 2.130000); 76 | \draw[-latex, line width=0.046875cm, rounded corners=0.200000cm] (5.250000, 1.730000) -- (4.312500, 1.730000) -- (4.312500, 2.130000); 77 | \draw[-latex, line width=0.046875cm, rounded corners=0.200000cm] (5.250000, 1.730000) -- (6.187500, 1.730000) -- (6.187500, 2.130000); 78 | \draw[-latex, line width=0.046875cm, rounded corners=0.200000cm] (1.250000, 6.230000) -- (1.250000, 7.230000) -- (3.250000, 7.230000) -- (3.250000, 4.680000) -- (4.312500, 4.680000) -- (4.312500, 5.080000); 79 | \draw[-latex, line width=0.046875cm, rounded corners=0.200000cm] (1.250000, 6.230000) -- (1.250000, 7.230000) -- (3.250000, 7.230000) -- (3.250000, 4.680000) -- (5.250000, 4.680000) -- (5.250000, 5.080000); 80 | \draw[-latex, line width=0.046875cm, rounded corners=0.200000cm] (5.250000, 4.080000) -- (5.250000, 4.680000) -- (6.187500, 4.680000) -- (6.187500, 5.080000); 81 | \draw[line width=0.046875cm, -latex] (1.250000, -1.500000) -- (1.250000, -0.900000); 82 | \draw[line width=0.046875cm, -latex] (5.250000, -1.500000) -- (5.250000, -0.900000); 83 | \draw[line width=0.046875cm, -latex] (5.250000, 11.380000) -- (5.250000, 11.980000); 84 | \node[text width=2.500000cm, anchor=north, align=center] at (1.250000,-1.500000) {Inputs}; 85 | \node[text width=2.500000cm, anchor=north, align=center] at (5.250000,-1.500000) {Outputs \vspace{-0.05cm} \linebreak (shifted right)}; 86 | \node[text width=2.500000cm, anchor=south, align=center] at (5.250000,11.980000) {Output \vspace{-0.05cm} \linebreak Probabilities}; 87 | \node[anchor=east] at (-1.175000,3.880000) {$N\times$}; 88 | \node[anchor=west] at (7.675000,5.355000) {$N\times$}; 89 | \node[text width=2.000000cm, anchor=east] at (0.250000,0.600000) {Positional \vspace{-0.05cm} \linebreak Encoding}; 90 | \node[text width=2.000000cm, anchor=west] at (6.750000,0.600000) {Positional \vspace{-0.05cm} \linebreak Encoding}; 91 | \end{tikzpicture} 92 | \end{document} 93 | -------------------------------------------------------------------------------- /examples/tree.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/negrinho/sane_tikz/fd6f291d9815613594d724678cb91ac9d412fbb7/examples/tree.pdf -------------------------------------------------------------------------------- /examples/tree.py: -------------------------------------------------------------------------------- 1 | # reproduction of https://en.wikipedia.org/wiki/Binary_search_algorithm#/media/File:Binary_search_tree_search_4.svg 2 | 3 | import sane_tikz.core as stz 4 | import sane_tikz.formatting as fmt 5 | 6 | node_radius = 0.30 7 | vertical_node_spacing = 1.4 * node_radius 8 | first_level_horizontal_node_spacing = 1.8 9 | arrow_angle = 30.0 10 | bbox_spacing = 0.1 11 | label_spacing = 0.4 12 | line_width = 1.2 * fmt.standard_line_width 13 | 14 | s_lw = fmt.line_width(line_width) 15 | 16 | fn = lambda expr: [ 17 | stz.circle([0, 0], node_radius, s_lw), 18 | stz.latex([0, 0], expr) 19 | ] 20 | 21 | 22 | def place(e, lst): 23 | delta = 0.0 24 | for i, sign in enumerate(lst): 25 | delta += sign * (node_radius + first_level_horizontal_node_spacing / 26 | (2 * (i + 1.0))) 27 | stz.translate_horizontally(e, delta) 28 | 29 | 30 | def connect(e_from, e_to, color_name="black"): 31 | s_fmt = fmt.combine_tikz_strs( 32 | [fmt.arrow_heads("end"), 33 | fmt.line_color(color_name), s_lw]) 34 | from_cs = stz.center_coords(e_from) 35 | to_cs = stz.center_coords(e_to) 36 | out_angle = stz.vector_to_angle([from_cs, to_cs]) 37 | in_angle = out_angle + 180.0 38 | return stz.line_segment_between_circles(from_cs, node_radius, out_angle, 39 | to_cs, node_radius, in_angle, s_fmt) 40 | 41 | 42 | def dashed_bbox(e_lst): 43 | s_fmt = fmt.combine_tikz_strs([fmt.line_style("dashed"), s_lw]) 44 | top_left_cs, bottom_right_cs = stz.bbox(e_lst) 45 | return stz.rectangle_from_additive_resizing(top_left_cs, bottom_right_cs, 46 | 2.0 * bbox_spacing, 47 | 2.0 * bbox_spacing, s_fmt) 48 | 49 | 50 | def label_right(e, expr): 51 | cs = stz.coords_from_bbox_with_fn(e, stz.right_center_coords) 52 | cs = stz.translate_coords(cs, label_spacing, 0.1) 53 | return stz.latex(cs, "\\scriptsize{%s}" % expr) 54 | 55 | 56 | def label_left(e, expr): 57 | cs = stz.coords_from_bbox_with_fn(e, stz.left_center_coords) 58 | cs = stz.translate_coords(cs, -label_spacing, 0.1) 59 | return stz.latex(cs, "\\scriptsize{%s}" % expr) 60 | 61 | 62 | nodes = [] 63 | for i in [8, 3, 10, 1, 6, 14, 4, 7, 13]: 64 | if i == 4: 65 | s = "\\textbf{%s}" % str(i) 66 | else: 67 | s = str(i) 68 | nodes.append(fn(s)) 69 | stz.distribute_vertically_with_spacing( 70 | [nodes[0:1], nodes[1:3], nodes[3:6], 71 | nodes[6:9]][::-1], vertical_node_spacing) 72 | 73 | place(nodes[1], [-1]) 74 | place(nodes[2], [1]) 75 | place(nodes[3], [-1, -1]) 76 | place(nodes[4], [-1, 1]) 77 | place(nodes[5], [1, 1]) 78 | place(nodes[6], [-1, 1, -1]) 79 | place(nodes[7], [-1, 1, 1]) 80 | place(nodes[8], [1, 1, -1]) 81 | 82 | connections = [ 83 | connect(nodes[0], nodes[1], "blue"), 84 | connect(nodes[0], nodes[2]), 85 | connect(nodes[1], nodes[3]), 86 | connect(nodes[1], nodes[4], "blue"), 87 | connect(nodes[2], nodes[5]), 88 | connect(nodes[4], nodes[6], "blue"), 89 | connect(nodes[4], nodes[7]), 90 | connect(nodes[5], nodes[8]), 91 | ] 92 | 93 | nodes[-3][0]["tikz_str"] = fmt.combine_tikz_strs( 94 | [nodes[-3][0]["tikz_str"], 95 | fmt.line_and_fill_colors("mygreen", "mygreen")]) 96 | nodes[-3][1]["tikz_str"] = fmt.combine_tikz_strs( 97 | [nodes[-3][0]["tikz_str"], "text=white"]) 98 | 99 | bb1 = dashed_bbox([nodes[6]]) 100 | bb2 = dashed_bbox([bb1, nodes[4], nodes[7]]) 101 | bb3 = dashed_bbox([bb2, nodes[1], nodes[3]]) 102 | bboxes = [bb1, bb2, bb3] 103 | 104 | labels = [ 105 | label_left(nodes[0], "4 < 8"), 106 | label_left(nodes[1], "4 > 3"), 107 | label_left(nodes[4], "4 < 6"), 108 | ] 109 | 110 | name2color = {"mygreen": (2, 129, 0)} 111 | 112 | e = [nodes, connections, bboxes, labels] 113 | stz.draw_to_tikz_standalone(e, "tree.tex", name2color) -------------------------------------------------------------------------------- /examples/tree.tex: -------------------------------------------------------------------------------- 1 | \documentclass{standalone} 2 | \usepackage[T1]{fontenc}\usepackage{tikz} 3 | \usepackage{amsmath, amsfonts} 4 | \usetikzlibrary{arrows.meta} 5 | \begin{document} 6 | \begin{tikzpicture} 7 | \definecolor{mygreen}{RGB}{2,129,0} 8 | \draw[line width=0.018750cm] (0.000000, 0.000000) circle (0.300000); 9 | \node[] at (0.000000,0.000000) {8}; 10 | \draw[line width=0.018750cm] (-1.200000, -1.020000) circle (0.300000); 11 | \node[] at (-1.200000,-1.020000) {3}; 12 | \draw[line width=0.018750cm] (1.200000, -1.020000) circle (0.300000); 13 | \node[] at (1.200000,-1.020000) {10}; 14 | \draw[line width=0.018750cm] (-1.950000, -2.040000) circle (0.300000); 15 | \node[] at (-1.950000,-2.040000) {1}; 16 | \draw[line width=0.018750cm] (-0.450000, -2.040000) circle (0.300000); 17 | \node[] at (-0.450000,-2.040000) {6}; 18 | \draw[line width=0.018750cm] (1.950000, -2.040000) circle (0.300000); 19 | \node[] at (1.950000,-2.040000) {14}; 20 | \draw[line width=0.018750cm, fill=mygreen, draw=mygreen] (-1.050000, -3.060000) circle (0.300000); 21 | \node[line width=0.018750cm, fill=mygreen, draw=mygreen, text=white] at (-1.050000,-3.060000) {\textbf{4}}; 22 | \draw[line width=0.018750cm] (0.150000, -3.060000) circle (0.300000); 23 | \node[] at (0.150000,-3.060000) {7}; 24 | \draw[line width=0.018750cm] (1.350000, -3.060000) circle (0.300000); 25 | \node[] at (1.350000,-3.060000) {13}; 26 | \draw[-latex, draw=blue, line width=0.018750cm] (-0.228582, -0.194295) -- (-0.971418, -0.825705); 27 | \draw[-latex, draw=black, line width=0.018750cm] (0.228582, -0.194295) -- (0.971418, -0.825705); 28 | \draw[-latex, draw=black, line width=0.018750cm] (-1.377717, -1.261695) -- (-1.772283, -1.798305); 29 | \draw[-latex, draw=blue, line width=0.018750cm] (-1.022283, -1.261695) -- (-0.627717, -1.798305); 30 | \draw[-latex, draw=black, line width=0.018750cm] (1.377717, -1.261695) -- (1.772283, -1.798305); 31 | \draw[-latex, draw=blue, line width=0.018750cm] (-0.602106, -2.298580) -- (-0.897894, -2.801420); 32 | \draw[-latex, draw=black, line width=0.018750cm] (-0.297894, -2.298580) -- (-0.002106, -2.801420); 33 | \draw[-latex, draw=black, line width=0.018750cm] (1.797894, -2.298580) -- (1.502106, -2.801420); 34 | \draw[dashed, line width=0.018750cm] (-1.450000, -2.660000) -- (-0.650000, -2.660000) -- (-0.650000, -3.460000) -- (-1.450000, -3.460000) -- cycle; 35 | \draw[dashed, line width=0.018750cm] (-1.550000, -1.640000) -- (0.550000, -1.640000) -- (0.550000, -3.560000) -- (-1.550000, -3.560000) -- cycle; 36 | \draw[dashed, line width=0.018750cm] (-2.350000, -0.620000) -- (0.650000, -0.620000) -- (0.650000, -3.660000) -- (-2.350000, -3.660000) -- cycle; 37 | \node[] at (-0.700000,0.100000) {\scriptsize{4 < 8}}; 38 | \node[] at (-1.900000,-0.920000) {\scriptsize{4 > 3}}; 39 | \node[] at (-1.150000,-1.940000) {\scriptsize{4 < 6}}; 40 | \end{tikzpicture} 41 | \end{document} 42 | -------------------------------------------------------------------------------- /examples/xlnet.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/negrinho/sane_tikz/fd6f291d9815613594d724678cb91ac9d412fbb7/examples/xlnet.pdf -------------------------------------------------------------------------------- /examples/xlnet.py: -------------------------------------------------------------------------------- 1 | # Reproduction of Figure 1 (top left) https://arxiv.org/pdf/1906.08237.pdf 2 | 3 | import sane_tikz.core as stz 4 | import sane_tikz.formatting as fmt 5 | 6 | square_side = 0.85 7 | rectangle_width = 1.4 8 | roundness_in_cm = 0.1 9 | line_width = 2.0 * fmt.standard_line_width 10 | opacity_level = 0.5 11 | horizontal_spacing = 1.0 12 | vertical_spacing = 1.0 13 | legend_spacing = 0.5 14 | 15 | name2color = { 16 | "my_grey": (217, 217, 217), 17 | "my_yellow": (255, 212, 76), 18 | "my_blue": (1, 176, 240), 19 | "my_green": (50, 192, 115), 20 | "my_red": (255, 102, 102) 21 | } 22 | 23 | m_fmt = fmt.line_and_fill_colors("my_grey", "my_grey") 24 | x1_fmt = fmt.line_and_fill_colors("my_yellow", "my_yellow") 25 | x2_fmt = fmt.line_and_fill_colors("my_blue", "my_blue") 26 | x3_fmt = fmt.line_and_fill_colors("my_green", "my_green") 27 | x4_fmt = fmt.line_and_fill_colors("my_red", "my_red") 28 | xs_fmt = [x1_fmt, x2_fmt, x3_fmt, x4_fmt] 29 | 30 | h_green_rfmt = fmt.combine_tikz_strs( 31 | [fmt.line_width(2.0 * line_width), 32 | fmt.line_color("my_green")]) 33 | h_grey_rfmt = fmt.line_color("my_grey") 34 | h_grey_lfmt = fmt.text_color("my_grey") 35 | 36 | 37 | def rectangle_with_latex(width, expr, rectangle_tikz_str="", latex_tikz_str=""): 38 | r_fmt = fmt.combine_tikz_strs([ 39 | # fmt.alignment("center"), 40 | fmt.rounded_corners(roundness_in_cm), 41 | fmt.line_width(line_width), 42 | rectangle_tikz_str 43 | ]) 44 | l_fmt = fmt.combine_tikz_strs([latex_tikz_str]) 45 | r = stz.rectangle_from_width_and_height([0, 0], square_side, width, r_fmt) 46 | l = stz.latex(stz.center_coords(r), expr, l_fmt) 47 | return [r, l] 48 | 49 | 50 | def sq_fn(expr, square_tikz_str="", latex_tikz_str=""): 51 | return rectangle_with_latex(square_side, expr, square_tikz_str, 52 | latex_tikz_str) 53 | 54 | 55 | def rct_fn(expr, rectangle_tikz_str="", latex_tikz_str=""): 56 | return rectangle_with_latex(rectangle_width, expr, rectangle_tikz_str, 57 | latex_tikz_str) 58 | 59 | 60 | def connect(e_from, e_to): 61 | cs_from = stz.coords_from_bbox_with_fn(e_from, stz.top_center_coords) 62 | cs_to = stz.coords_from_bbox_with_fn(e_to, stz.bottom_center_coords) 63 | s_fmt = fmt.combine_tikz_strs( 64 | [fmt.line_width(line_width), 65 | fmt.arrow_heads("end")]) 66 | return stz.line_segment(cs_from, cs_to, s_fmt) 67 | 68 | 69 | xs = [sq_fn("$x_%d$" % (i + 1,), xs_fmt[i]) for i in range(4)] 70 | hs1 = [ 71 | sq_fn("$h_%d^{(1)}$" % (i + 1,), h_grey_rfmt if i != 2 else h_green_rfmt, 72 | h_grey_lfmt if i != 2 else "") for i in range(4) 73 | ] 74 | hs2 = [ 75 | sq_fn("$h_%d^{(2)}$" % (i + 1,), h_grey_rfmt if i != 2 else h_green_rfmt, 76 | h_grey_lfmt if i != 2 else "") for i in range(4) 77 | ] 78 | m1, m2 = [rct_fn("$\\text{mem}^{(%d)}$" % (i + 1,), m_fmt) for i in range(2)] 79 | x_out = [sq_fn("$x_3$", x3_fmt)] 80 | 81 | row1 = [m1] + xs 82 | row2 = [m2] + hs1 83 | 84 | stz.distribute_horizontally_with_spacing([m1] + xs, horizontal_spacing) 85 | stz.distribute_horizontally_with_spacing([m2] + hs1, horizontal_spacing) 86 | stz.distribute_horizontally_with_spacing(hs2, horizontal_spacing) 87 | stz.distribute_vertically_with_spacing([row1, row2, hs2], vertical_spacing) 88 | stz.align_rights([row1, row2, hs2], 0) 89 | 90 | stz.place_above_and_align_to_the_center(x_out, hs2[2], vertical_spacing) 91 | 92 | legend = stz.latex( 93 | [0, 0], 94 | "Factorization order: $3 \\rightarrow 2 \\rightarrow 4 \\rightarrow 1$") 95 | stz.place_below_and_align_to_the_center(legend, xs, legend_spacing) 96 | 97 | connections = [ 98 | connect(m1, hs1[2]), 99 | connect(m2, hs2[2]), 100 | connect(hs1[2], hs2[2]), 101 | connect(hs2[2], x_out) 102 | ] 103 | 104 | e = [row1, row2, hs2, x_out, connections, legend] 105 | stz.draw_to_tikz_standalone(e, "xlnet.tex", name2color) 106 | -------------------------------------------------------------------------------- /examples/xlnet.tex: -------------------------------------------------------------------------------- 1 | \documentclass{standalone} 2 | \usepackage[T1]{fontenc}\usepackage{tikz} 3 | \usepackage{amsmath, amsfonts} 4 | \usetikzlibrary{arrows.meta} 5 | \begin{document} 6 | \begin{tikzpicture} 7 | \definecolor{my_yellow}{RGB}{255,212,76} 8 | \definecolor{my_green}{RGB}{50,192,115} 9 | \definecolor{my_red}{RGB}{255,102,102} 10 | \definecolor{my_blue}{RGB}{1,176,240} 11 | \definecolor{my_grey}{RGB}{217,217,217} 12 | \draw[rounded corners=0.100000cm, line width=0.031250cm, fill=my_grey, draw=my_grey] (-8.800000, -3.700000) -- (-7.400000, -3.700000) -- (-7.400000, -4.550000) -- (-8.800000, -4.550000) -- cycle; 13 | \node[] at (-8.100000,-4.125000) {$\text{mem}^{(1)}$}; 14 | \draw[rounded corners=0.100000cm, line width=0.031250cm, fill=my_yellow, draw=my_yellow] (-6.400000, -3.700000) -- (-5.550000, -3.700000) -- (-5.550000, -4.550000) -- (-6.400000, -4.550000) -- cycle; 15 | \node[] at (-5.975000,-4.125000) {$x_1$}; 16 | \draw[rounded corners=0.100000cm, line width=0.031250cm, fill=my_blue, draw=my_blue] (-4.550000, -3.700000) -- (-3.700000, -3.700000) -- (-3.700000, -4.550000) -- (-4.550000, -4.550000) -- cycle; 17 | \node[] at (-4.125000,-4.125000) {$x_2$}; 18 | \draw[rounded corners=0.100000cm, line width=0.031250cm, fill=my_green, draw=my_green] (-2.700000, -3.700000) -- (-1.850000, -3.700000) -- (-1.850000, -4.550000) -- (-2.700000, -4.550000) -- cycle; 19 | \node[] at (-2.275000,-4.125000) {$x_3$}; 20 | \draw[rounded corners=0.100000cm, line width=0.031250cm, fill=my_red, draw=my_red] (-0.850000, -3.700000) -- (0.000000, -3.700000) -- (0.000000, -4.550000) -- (-0.850000, -4.550000) -- cycle; 21 | \node[] at (-0.425000,-4.125000) {$x_4$}; 22 | \draw[rounded corners=0.100000cm, line width=0.031250cm, fill=my_grey, draw=my_grey] (-8.800000, -1.850000) -- (-7.400000, -1.850000) -- (-7.400000, -2.700000) -- (-8.800000, -2.700000) -- cycle; 23 | \node[] at (-8.100000,-2.275000) {$\text{mem}^{(2)}$}; 24 | \draw[rounded corners=0.100000cm, line width=0.031250cm, draw=my_grey] (-6.400000, -1.850000) -- (-5.550000, -1.850000) -- (-5.550000, -2.700000) -- (-6.400000, -2.700000) -- cycle; 25 | \node[text=my_grey] at (-5.975000,-2.275000) {$h_1^{(1)}$}; 26 | \draw[rounded corners=0.100000cm, line width=0.031250cm, draw=my_grey] (-4.550000, -1.850000) -- (-3.700000, -1.850000) -- (-3.700000, -2.700000) -- (-4.550000, -2.700000) -- cycle; 27 | \node[text=my_grey] at (-4.125000,-2.275000) {$h_2^{(1)}$}; 28 | \draw[rounded corners=0.100000cm, line width=0.031250cm, line width=0.062500cm, draw=my_green] (-2.700000, -1.850000) -- (-1.850000, -1.850000) -- (-1.850000, -2.700000) -- (-2.700000, -2.700000) -- cycle; 29 | \node[] at (-2.275000,-2.275000) {$h_3^{(1)}$}; 30 | \draw[rounded corners=0.100000cm, line width=0.031250cm, draw=my_grey] (-0.850000, -1.850000) -- (0.000000, -1.850000) -- (0.000000, -2.700000) -- (-0.850000, -2.700000) -- cycle; 31 | \node[text=my_grey] at (-0.425000,-2.275000) {$h_4^{(1)}$}; 32 | \draw[rounded corners=0.100000cm, line width=0.031250cm, draw=my_grey] (-6.400000, 0.000000) -- (-5.550000, 0.000000) -- (-5.550000, -0.850000) -- (-6.400000, -0.850000) -- cycle; 33 | \node[text=my_grey] at (-5.975000,-0.425000) {$h_1^{(2)}$}; 34 | \draw[rounded corners=0.100000cm, line width=0.031250cm, draw=my_grey] (-4.550000, 0.000000) -- (-3.700000, 0.000000) -- (-3.700000, -0.850000) -- (-4.550000, -0.850000) -- cycle; 35 | \node[text=my_grey] at (-4.125000,-0.425000) {$h_2^{(2)}$}; 36 | \draw[rounded corners=0.100000cm, line width=0.031250cm, line width=0.062500cm, draw=my_green] (-2.700000, 0.000000) -- (-1.850000, 0.000000) -- (-1.850000, -0.850000) -- (-2.700000, -0.850000) -- cycle; 37 | \node[] at (-2.275000,-0.425000) {$h_3^{(2)}$}; 38 | \draw[rounded corners=0.100000cm, line width=0.031250cm, draw=my_grey] (-0.850000, 0.000000) -- (0.000000, 0.000000) -- (0.000000, -0.850000) -- (-0.850000, -0.850000) -- cycle; 39 | \node[text=my_grey] at (-0.425000,-0.425000) {$h_4^{(2)}$}; 40 | \draw[rounded corners=0.100000cm, line width=0.031250cm, fill=my_green, draw=my_green] (-2.700000, 1.850000) -- (-1.850000, 1.850000) -- (-1.850000, 1.000000) -- (-2.700000, 1.000000) -- cycle; 41 | \node[] at (-2.275000,1.425000) {$x_3$}; 42 | \draw[line width=0.031250cm, -latex] (-8.100000, -3.700000) -- (-2.275000, -2.700000); 43 | \draw[line width=0.031250cm, -latex] (-8.100000, -1.850000) -- (-2.275000, -0.850000); 44 | \draw[line width=0.031250cm, -latex] (-2.275000, -1.850000) -- (-2.275000, -0.850000); 45 | \draw[line width=0.031250cm, -latex] (-2.275000, 0.000000) -- (-2.275000, 1.000000); 46 | \node[] at (-3.200000,-5.050000) {Factorization order: $3 \rightarrow 2 \rightarrow 4 \rightarrow 1$}; 47 | \end{tikzpicture} 48 | \end{document} 49 | -------------------------------------------------------------------------------- /sane_tikz/formatting.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | 4 | def combine_tikz_strs(lst): 5 | return ", ".join(lst) 6 | 7 | 8 | def line_width(width_in_cm): 9 | return "line width=%fcm" % width_in_cm 10 | 11 | 12 | def fill_color(color_name): 13 | return "fill=%s" % color_name 14 | 15 | 16 | def line_and_fill_colors(line_color_name, fill_color_name): 17 | return combine_tikz_strs( 18 | [fill_color(fill_color_name), 19 | line_color(line_color_name)]) 20 | 21 | 22 | def fill_color_with_no_line(color_name): 23 | return combine_tikz_strs([fill_color(color_name), no_line()]) 24 | 25 | 26 | def text_color(color_name): 27 | return "text=%s" % color_name 28 | 29 | 30 | def rounded_corners(radius_in_cm): 31 | return "rounded corners=%fcm" % radius_in_cm 32 | 33 | 34 | def line_color(color_name): 35 | return "draw=%s" % color_name 36 | 37 | 38 | def no_line(): 39 | return "draw=none" 40 | 41 | 42 | def no_fill(): 43 | return "fill=none" 44 | 45 | 46 | def fill_opacity(alpha): 47 | return "fill opacity=%f" % alpha 48 | 49 | 50 | def line_opacity(alpha): 51 | return "line opacity=%f" % alpha 52 | 53 | 54 | def line_and_fill_opacities(line_alpha, fill_alpha): 55 | return combine_tikz_strs( 56 | [fill_opacity(fill_alpha), 57 | line_opacity(line_alpha)]) 58 | 59 | 60 | def line_style(s): 61 | assert s == "dashed" or s == "dotted" or s == "solid" 62 | return s 63 | 64 | 65 | def arrow_heads(s): 66 | if s == 'both': 67 | return "latex-latex" 68 | elif s == "start": 69 | return "latex-" 70 | elif s == "end": 71 | return "-latex" 72 | else: 73 | raise ValueError 74 | 75 | 76 | def text_width(width_in_cm): 77 | return "text width=%fcm" % width_in_cm 78 | 79 | 80 | def orientation(angle_in_degrees): 81 | return "rotate=%f" % angle_in_degrees 82 | 83 | 84 | def alignment(s): 85 | valid_opts = {"center", "left", "right"} 86 | assert s in valid_opts 87 | return "align=%s" % s 88 | 89 | 90 | # down, left, right, 91 | # north, south, west, east, 92 | # north east, north west, south east, south west 93 | def anchor(s): 94 | valid_opts = [ 95 | "left_center", "right_center", "top_center", "bottom_center", 96 | "top_left", "top_right", "bottom_left", "bottom_right" 97 | ] 98 | assert s in valid_opts 99 | 100 | tikz_opts = [ 101 | "west", "east", "north", "south", "north west", "north east", 102 | "south west", "south east" 103 | ] 104 | 105 | return "anchor=%s" % tikz_opts[valid_opts.index(s)] 106 | 107 | 108 | standard_line_width = 1.0 / 64 109 | 110 | #===> Colors 111 | # useful links: 112 | # - https://www.kennethmoreland.com/color-advice/ 113 | # - https://seaborn.pydata.org/tutorial/color_palettes.html 114 | # - https://matplotlib.org/3.1.0/tutorials/colors/colormaps.html 115 | 116 | 117 | def convert_fractional_to_integral_colormap(cmap): 118 | return [tuple([int(round(255 * x)) for x in xs]) for xs in cmap] 119 | 120 | 121 | def shade_color(rgb, alpha): 122 | return tuple([int(round((1.0 - alpha) * x, 0)) for x in rgb]) 123 | 124 | 125 | def tint_color(rgb, alpha): 126 | return tuple( 127 | [int(round(255.0 * alpha + (1.0 - alpha) * x, 0)) for x in rgb]) 128 | 129 | 130 | def mix_colors(rgb_start, rgb_end, alpha): 131 | return tuple([ 132 | int(round(alpha * rgb_end[i] + (1.0 - alpha) * rgb_start, 0)) 133 | for i in range(3) 134 | ]) 135 | 136 | 137 | # For the following four color maps. 138 | 139 | # New matplotlib colormaps by Nathaniel J. Smith, Stefan van der Walt, 140 | # and (in the case of viridis) Eric Firing. 141 | # 142 | # This file and the colormaps in it are released under the CC0 license / 143 | # public domain dedication. We would appreciate credit if you use or 144 | # redistribute these colormaps, but do not impose any legal restrictions. 145 | # 146 | # To the extent possible under law, the persons who associated CC0 with 147 | # mpl-colormaps have waived all copyright and related or neighboring rights 148 | # to mpl-colormaps. 149 | # 150 | # You should have received a copy of the CC0 legalcode along with this 151 | # work. If not, see . 152 | 153 | 154 | def gray_colormap(): 155 | return [(i, i, i) for i in range(256)] 156 | 157 | 158 | def magma_colormap(): 159 | return [ 160 | (0, 0, 4), 161 | (1, 0, 5), 162 | (1, 1, 6), 163 | (1, 1, 8), 164 | (2, 1, 9), 165 | (2, 2, 11), 166 | (2, 2, 13), 167 | (3, 3, 15), 168 | (3, 3, 18), 169 | (4, 4, 20), 170 | (5, 4, 22), 171 | (6, 5, 24), 172 | (6, 5, 26), 173 | (7, 6, 28), 174 | (8, 7, 30), 175 | (9, 7, 32), 176 | (10, 8, 34), 177 | (11, 9, 36), 178 | (12, 9, 38), 179 | (13, 10, 41), 180 | (14, 11, 43), 181 | (16, 11, 45), 182 | (17, 12, 47), 183 | (18, 13, 49), 184 | (19, 13, 52), 185 | (20, 14, 54), 186 | (21, 14, 56), 187 | (22, 15, 59), 188 | (24, 15, 61), 189 | (25, 16, 63), 190 | (26, 16, 66), 191 | (28, 16, 68), 192 | (29, 17, 71), 193 | (30, 17, 73), 194 | (32, 17, 75), 195 | (33, 17, 78), 196 | (34, 17, 80), 197 | (36, 18, 83), 198 | (37, 18, 85), 199 | (39, 18, 88), 200 | (41, 17, 90), 201 | (42, 17, 92), 202 | (44, 17, 95), 203 | (45, 17, 97), 204 | (47, 17, 99), 205 | (49, 17, 101), 206 | (51, 16, 103), 207 | (52, 16, 105), 208 | (54, 16, 107), 209 | (56, 16, 108), 210 | (57, 15, 110), 211 | (59, 15, 112), 212 | (61, 15, 113), 213 | (63, 15, 114), 214 | (64, 15, 116), 215 | (66, 15, 117), 216 | (68, 15, 118), 217 | (69, 16, 119), 218 | (71, 16, 120), 219 | (73, 16, 120), 220 | (74, 16, 121), 221 | (76, 17, 122), 222 | (78, 17, 123), 223 | (79, 18, 123), 224 | (81, 18, 124), 225 | (82, 19, 124), 226 | (84, 19, 125), 227 | (86, 20, 125), 228 | (87, 21, 126), 229 | (89, 21, 126), 230 | (90, 22, 126), 231 | (92, 22, 127), 232 | (93, 23, 127), 233 | (95, 24, 127), 234 | (96, 24, 128), 235 | (98, 25, 128), 236 | (100, 26, 128), 237 | (101, 26, 128), 238 | (103, 27, 128), 239 | (104, 28, 129), 240 | (106, 28, 129), 241 | (107, 29, 129), 242 | (109, 29, 129), 243 | (110, 30, 129), 244 | (112, 31, 129), 245 | (114, 31, 129), 246 | (115, 32, 129), 247 | (117, 33, 129), 248 | (118, 33, 129), 249 | (120, 34, 129), 250 | (121, 34, 130), 251 | (123, 35, 130), 252 | (124, 35, 130), 253 | (126, 36, 130), 254 | (128, 37, 130), 255 | (129, 37, 129), 256 | (131, 38, 129), 257 | (132, 38, 129), 258 | (134, 39, 129), 259 | (136, 39, 129), 260 | (137, 40, 129), 261 | (139, 41, 129), 262 | (140, 41, 129), 263 | (142, 42, 129), 264 | (144, 42, 129), 265 | (145, 43, 129), 266 | (147, 43, 128), 267 | (148, 44, 128), 268 | (150, 44, 128), 269 | (152, 45, 128), 270 | (153, 45, 128), 271 | (155, 46, 127), 272 | (156, 46, 127), 273 | (158, 47, 127), 274 | (160, 47, 127), 275 | (161, 48, 126), 276 | (163, 48, 126), 277 | (165, 49, 126), 278 | (166, 49, 125), 279 | (168, 50, 125), 280 | (170, 51, 125), 281 | (171, 51, 124), 282 | (173, 52, 124), 283 | (174, 52, 123), 284 | (176, 53, 123), 285 | (178, 53, 123), 286 | (179, 54, 122), 287 | (181, 54, 122), 288 | (183, 55, 121), 289 | (184, 55, 121), 290 | (186, 56, 120), 291 | (188, 57, 120), 292 | (189, 57, 119), 293 | (191, 58, 119), 294 | (192, 58, 118), 295 | (194, 59, 117), 296 | (196, 60, 117), 297 | (197, 60, 116), 298 | (199, 61, 115), 299 | (200, 62, 115), 300 | (202, 62, 114), 301 | (204, 63, 113), 302 | (205, 64, 113), 303 | (207, 64, 112), 304 | (208, 65, 111), 305 | (210, 66, 111), 306 | (211, 67, 110), 307 | (213, 68, 109), 308 | (214, 69, 108), 309 | (216, 69, 108), 310 | (217, 70, 107), 311 | (219, 71, 106), 312 | (220, 72, 105), 313 | (222, 73, 104), 314 | (223, 74, 104), 315 | (224, 76, 103), 316 | (226, 77, 102), 317 | (227, 78, 101), 318 | (228, 79, 100), 319 | (229, 80, 100), 320 | (231, 82, 99), 321 | (232, 83, 98), 322 | (233, 84, 98), 323 | (234, 86, 97), 324 | (235, 87, 96), 325 | (236, 88, 96), 326 | (237, 90, 95), 327 | (238, 91, 94), 328 | (239, 93, 94), 329 | (240, 95, 94), 330 | (241, 96, 93), 331 | (242, 98, 93), 332 | (242, 100, 92), 333 | (243, 101, 92), 334 | (244, 103, 92), 335 | (244, 105, 92), 336 | (245, 107, 92), 337 | (246, 108, 92), 338 | (246, 110, 92), 339 | (247, 112, 92), 340 | (247, 114, 92), 341 | (248, 116, 92), 342 | (248, 118, 92), 343 | (249, 120, 93), 344 | (249, 121, 93), 345 | (249, 123, 93), 346 | (250, 125, 94), 347 | (250, 127, 94), 348 | (250, 129, 95), 349 | (251, 131, 95), 350 | (251, 133, 96), 351 | (251, 135, 97), 352 | (252, 137, 97), 353 | (252, 138, 98), 354 | (252, 140, 99), 355 | (252, 142, 100), 356 | (252, 144, 101), 357 | (253, 146, 102), 358 | (253, 148, 103), 359 | (253, 150, 104), 360 | (253, 152, 105), 361 | (253, 154, 106), 362 | (253, 155, 107), 363 | (254, 157, 108), 364 | (254, 159, 109), 365 | (254, 161, 110), 366 | (254, 163, 111), 367 | (254, 165, 113), 368 | (254, 167, 114), 369 | (254, 169, 115), 370 | (254, 170, 116), 371 | (254, 172, 118), 372 | (254, 174, 119), 373 | (254, 176, 120), 374 | (254, 178, 122), 375 | (254, 180, 123), 376 | (254, 182, 124), 377 | (254, 183, 126), 378 | (254, 185, 127), 379 | (254, 187, 129), 380 | (254, 189, 130), 381 | (254, 191, 132), 382 | (254, 193, 133), 383 | (254, 194, 135), 384 | (254, 196, 136), 385 | (254, 198, 138), 386 | (254, 200, 140), 387 | (254, 202, 141), 388 | (254, 204, 143), 389 | (254, 205, 144), 390 | (254, 207, 146), 391 | (254, 209, 148), 392 | (254, 211, 149), 393 | (254, 213, 151), 394 | (254, 215, 153), 395 | (254, 216, 154), 396 | (253, 218, 156), 397 | (253, 220, 158), 398 | (253, 222, 160), 399 | (253, 224, 161), 400 | (253, 226, 163), 401 | (253, 227, 165), 402 | (253, 229, 167), 403 | (253, 231, 169), 404 | (253, 233, 170), 405 | (253, 235, 172), 406 | (252, 236, 174), 407 | (252, 238, 176), 408 | (252, 240, 178), 409 | (252, 242, 180), 410 | (252, 244, 182), 411 | (252, 246, 184), 412 | (252, 247, 185), 413 | (252, 249, 187), 414 | (252, 251, 189), 415 | (252, 253, 191), 416 | ] 417 | 418 | 419 | def inferno_colormap(): 420 | return [ 421 | (0, 0, 4), 422 | (1, 0, 5), 423 | (1, 1, 6), 424 | (1, 1, 8), 425 | (2, 1, 10), 426 | (2, 2, 12), 427 | (2, 2, 14), 428 | (3, 2, 16), 429 | (4, 3, 18), 430 | (4, 3, 20), 431 | (5, 4, 23), 432 | (6, 4, 25), 433 | (7, 5, 27), 434 | (8, 5, 29), 435 | (9, 6, 31), 436 | (10, 7, 34), 437 | (11, 7, 36), 438 | (12, 8, 38), 439 | (13, 8, 41), 440 | (14, 9, 43), 441 | (16, 9, 45), 442 | (17, 10, 48), 443 | (18, 10, 50), 444 | (20, 11, 52), 445 | (21, 11, 55), 446 | (22, 11, 57), 447 | (24, 12, 60), 448 | (25, 12, 62), 449 | (27, 12, 65), 450 | (28, 12, 67), 451 | (30, 12, 69), 452 | (31, 12, 72), 453 | (33, 12, 74), 454 | (35, 12, 76), 455 | (36, 12, 79), 456 | (38, 12, 81), 457 | (40, 11, 83), 458 | (41, 11, 85), 459 | (43, 11, 87), 460 | (45, 11, 89), 461 | (47, 10, 91), 462 | (49, 10, 92), 463 | (50, 10, 94), 464 | (52, 10, 95), 465 | (54, 9, 97), 466 | (56, 9, 98), 467 | (57, 9, 99), 468 | (59, 9, 100), 469 | (61, 9, 101), 470 | (62, 9, 102), 471 | (64, 10, 103), 472 | (66, 10, 104), 473 | (68, 10, 104), 474 | (69, 10, 105), 475 | (71, 11, 106), 476 | (73, 11, 106), 477 | (74, 12, 107), 478 | (76, 12, 107), 479 | (77, 13, 108), 480 | (79, 13, 108), 481 | (81, 14, 108), 482 | (82, 14, 109), 483 | (84, 15, 109), 484 | (85, 15, 109), 485 | (87, 16, 110), 486 | (89, 16, 110), 487 | (90, 17, 110), 488 | (92, 18, 110), 489 | (93, 18, 110), 490 | (95, 19, 110), 491 | (97, 19, 110), 492 | (98, 20, 110), 493 | (100, 21, 110), 494 | (101, 21, 110), 495 | (103, 22, 110), 496 | (105, 22, 110), 497 | (106, 23, 110), 498 | (108, 24, 110), 499 | (109, 24, 110), 500 | (111, 25, 110), 501 | (113, 25, 110), 502 | (114, 26, 110), 503 | (116, 26, 110), 504 | (117, 27, 110), 505 | (119, 28, 109), 506 | (120, 28, 109), 507 | (122, 29, 109), 508 | (124, 29, 109), 509 | (125, 30, 109), 510 | (127, 30, 108), 511 | (128, 31, 108), 512 | (130, 32, 108), 513 | (132, 32, 107), 514 | (133, 33, 107), 515 | (135, 33, 107), 516 | (136, 34, 106), 517 | (138, 34, 106), 518 | (140, 35, 105), 519 | (141, 35, 105), 520 | (143, 36, 105), 521 | (144, 37, 104), 522 | (146, 37, 104), 523 | (147, 38, 103), 524 | (149, 38, 103), 525 | (151, 39, 102), 526 | (152, 39, 102), 527 | (154, 40, 101), 528 | (155, 41, 100), 529 | (157, 41, 100), 530 | (159, 42, 99), 531 | (160, 42, 99), 532 | (162, 43, 98), 533 | (163, 44, 97), 534 | (165, 44, 96), 535 | (166, 45, 96), 536 | (168, 46, 95), 537 | (169, 46, 94), 538 | (171, 47, 94), 539 | (173, 48, 93), 540 | (174, 48, 92), 541 | (176, 49, 91), 542 | (177, 50, 90), 543 | (179, 50, 90), 544 | (180, 51, 89), 545 | (182, 52, 88), 546 | (183, 53, 87), 547 | (185, 53, 86), 548 | (186, 54, 85), 549 | (188, 55, 84), 550 | (189, 56, 83), 551 | (191, 57, 82), 552 | (192, 58, 81), 553 | (193, 58, 80), 554 | (195, 59, 79), 555 | (196, 60, 78), 556 | (198, 61, 77), 557 | (199, 62, 76), 558 | (200, 63, 75), 559 | (202, 64, 74), 560 | (203, 65, 73), 561 | (204, 66, 72), 562 | (206, 67, 71), 563 | (207, 68, 70), 564 | (208, 69, 69), 565 | (210, 70, 68), 566 | (211, 71, 67), 567 | (212, 72, 66), 568 | (213, 74, 65), 569 | (215, 75, 63), 570 | (216, 76, 62), 571 | (217, 77, 61), 572 | (218, 78, 60), 573 | (219, 80, 59), 574 | (221, 81, 58), 575 | (222, 82, 56), 576 | (223, 83, 55), 577 | (224, 85, 54), 578 | (225, 86, 53), 579 | (226, 87, 52), 580 | (227, 89, 51), 581 | (228, 90, 49), 582 | (229, 92, 48), 583 | (230, 93, 47), 584 | (231, 94, 46), 585 | (232, 96, 45), 586 | (233, 97, 43), 587 | (234, 99, 42), 588 | (235, 100, 41), 589 | (235, 102, 40), 590 | (236, 103, 38), 591 | (237, 105, 37), 592 | (238, 106, 36), 593 | (239, 108, 35), 594 | (239, 110, 33), 595 | (240, 111, 32), 596 | (241, 113, 31), 597 | (241, 115, 29), 598 | (242, 116, 28), 599 | (243, 118, 27), 600 | (243, 120, 25), 601 | (244, 121, 24), 602 | (245, 123, 23), 603 | (245, 125, 21), 604 | (246, 126, 20), 605 | (246, 128, 19), 606 | (247, 130, 18), 607 | (247, 132, 16), 608 | (248, 133, 15), 609 | (248, 135, 14), 610 | (248, 137, 12), 611 | (249, 139, 11), 612 | (249, 140, 10), 613 | (249, 142, 9), 614 | (250, 144, 8), 615 | (250, 146, 7), 616 | (250, 148, 7), 617 | (251, 150, 6), 618 | (251, 151, 6), 619 | (251, 153, 6), 620 | (251, 155, 6), 621 | (251, 157, 7), 622 | (252, 159, 7), 623 | (252, 161, 8), 624 | (252, 163, 9), 625 | (252, 165, 10), 626 | (252, 166, 12), 627 | (252, 168, 13), 628 | (252, 170, 15), 629 | (252, 172, 17), 630 | (252, 174, 18), 631 | (252, 176, 20), 632 | (252, 178, 22), 633 | (252, 180, 24), 634 | (251, 182, 26), 635 | (251, 184, 29), 636 | (251, 186, 31), 637 | (251, 188, 33), 638 | (251, 190, 35), 639 | (250, 192, 38), 640 | (250, 194, 40), 641 | (250, 196, 42), 642 | (250, 198, 45), 643 | (249, 199, 47), 644 | (249, 201, 50), 645 | (249, 203, 53), 646 | (248, 205, 55), 647 | (248, 207, 58), 648 | (247, 209, 61), 649 | (247, 211, 64), 650 | (246, 213, 67), 651 | (246, 215, 70), 652 | (245, 217, 73), 653 | (245, 219, 76), 654 | (244, 221, 79), 655 | (244, 223, 83), 656 | (244, 225, 86), 657 | (243, 227, 90), 658 | (243, 229, 93), 659 | (242, 230, 97), 660 | (242, 232, 101), 661 | (242, 234, 105), 662 | (241, 236, 109), 663 | (241, 237, 113), 664 | (241, 239, 117), 665 | (241, 241, 121), 666 | (242, 242, 125), 667 | (242, 244, 130), 668 | (243, 245, 134), 669 | (243, 246, 138), 670 | (244, 248, 142), 671 | (245, 249, 146), 672 | (246, 250, 150), 673 | (248, 251, 154), 674 | (249, 252, 157), 675 | (250, 253, 161), 676 | (252, 255, 164), 677 | ] 678 | 679 | 680 | def plasma_colormap(): 681 | return [ 682 | (13, 8, 135), 683 | (16, 7, 136), 684 | (19, 7, 137), 685 | (22, 7, 138), 686 | (25, 6, 140), 687 | (27, 6, 141), 688 | (29, 6, 142), 689 | (32, 6, 143), 690 | (34, 6, 144), 691 | (36, 6, 145), 692 | (38, 5, 145), 693 | (40, 5, 146), 694 | (42, 5, 147), 695 | (44, 5, 148), 696 | (46, 5, 149), 697 | (47, 5, 150), 698 | (49, 5, 151), 699 | (51, 5, 151), 700 | (53, 4, 152), 701 | (55, 4, 153), 702 | (56, 4, 154), 703 | (58, 4, 154), 704 | (60, 4, 155), 705 | (62, 4, 156), 706 | (63, 4, 156), 707 | (65, 4, 157), 708 | (67, 3, 158), 709 | (68, 3, 158), 710 | (70, 3, 159), 711 | (72, 3, 159), 712 | (73, 3, 160), 713 | (75, 3, 161), 714 | (76, 2, 161), 715 | (78, 2, 162), 716 | (80, 2, 162), 717 | (81, 2, 163), 718 | (83, 2, 163), 719 | (85, 2, 164), 720 | (86, 1, 164), 721 | (88, 1, 164), 722 | (89, 1, 165), 723 | (91, 1, 165), 724 | (92, 1, 166), 725 | (94, 1, 166), 726 | (96, 1, 166), 727 | (97, 0, 167), 728 | (99, 0, 167), 729 | (100, 0, 167), 730 | (102, 0, 167), 731 | (103, 0, 168), 732 | (105, 0, 168), 733 | (106, 0, 168), 734 | (108, 0, 168), 735 | (110, 0, 168), 736 | (111, 0, 168), 737 | (113, 0, 168), 738 | (114, 1, 168), 739 | (116, 1, 168), 740 | (117, 1, 168), 741 | (119, 1, 168), 742 | (120, 1, 168), 743 | (122, 2, 168), 744 | (123, 2, 168), 745 | (125, 3, 168), 746 | (126, 3, 168), 747 | (128, 4, 168), 748 | (129, 4, 167), 749 | (131, 5, 167), 750 | (132, 5, 167), 751 | (134, 6, 166), 752 | (135, 7, 166), 753 | (136, 8, 166), 754 | (138, 9, 165), 755 | (139, 10, 165), 756 | (141, 11, 165), 757 | (142, 12, 164), 758 | (143, 13, 164), 759 | (145, 14, 163), 760 | (146, 15, 163), 761 | (148, 16, 162), 762 | (149, 17, 161), 763 | (150, 19, 161), 764 | (152, 20, 160), 765 | (153, 21, 159), 766 | (154, 22, 159), 767 | (156, 23, 158), 768 | (157, 24, 157), 769 | (158, 25, 157), 770 | (160, 26, 156), 771 | (161, 27, 155), 772 | (162, 29, 154), 773 | (163, 30, 154), 774 | (165, 31, 153), 775 | (166, 32, 152), 776 | (167, 33, 151), 777 | (168, 34, 150), 778 | (170, 35, 149), 779 | (171, 36, 148), 780 | (172, 38, 148), 781 | (173, 39, 147), 782 | (174, 40, 146), 783 | (176, 41, 145), 784 | (177, 42, 144), 785 | (178, 43, 143), 786 | (179, 44, 142), 787 | (180, 46, 141), 788 | (181, 47, 140), 789 | (182, 48, 139), 790 | (183, 49, 138), 791 | (184, 50, 137), 792 | (186, 51, 136), 793 | (187, 52, 136), 794 | (188, 53, 135), 795 | (189, 55, 134), 796 | (190, 56, 133), 797 | (191, 57, 132), 798 | (192, 58, 131), 799 | (193, 59, 130), 800 | (194, 60, 129), 801 | (195, 61, 128), 802 | (196, 62, 127), 803 | (197, 64, 126), 804 | (198, 65, 125), 805 | (199, 66, 124), 806 | (200, 67, 123), 807 | (201, 68, 122), 808 | (202, 69, 122), 809 | (203, 70, 121), 810 | (204, 71, 120), 811 | (204, 73, 119), 812 | (205, 74, 118), 813 | (206, 75, 117), 814 | (207, 76, 116), 815 | (208, 77, 115), 816 | (209, 78, 114), 817 | (210, 79, 113), 818 | (211, 81, 113), 819 | (212, 82, 112), 820 | (213, 83, 111), 821 | (213, 84, 110), 822 | (214, 85, 109), 823 | (215, 86, 108), 824 | (216, 87, 107), 825 | (217, 88, 106), 826 | (218, 90, 106), 827 | (218, 91, 105), 828 | (219, 92, 104), 829 | (220, 93, 103), 830 | (221, 94, 102), 831 | (222, 95, 101), 832 | (222, 97, 100), 833 | (223, 98, 99), 834 | (224, 99, 99), 835 | (225, 100, 98), 836 | (226, 101, 97), 837 | (226, 102, 96), 838 | (227, 104, 95), 839 | (228, 105, 94), 840 | (229, 106, 93), 841 | (229, 107, 93), 842 | (230, 108, 92), 843 | (231, 110, 91), 844 | (231, 111, 90), 845 | (232, 112, 89), 846 | (233, 113, 88), 847 | (233, 114, 87), 848 | (234, 116, 87), 849 | (235, 117, 86), 850 | (235, 118, 85), 851 | (236, 119, 84), 852 | (237, 121, 83), 853 | (237, 122, 82), 854 | (238, 123, 81), 855 | (239, 124, 81), 856 | (239, 126, 80), 857 | (240, 127, 79), 858 | (240, 128, 78), 859 | (241, 129, 77), 860 | (241, 131, 76), 861 | (242, 132, 75), 862 | (243, 133, 75), 863 | (243, 135, 74), 864 | (244, 136, 73), 865 | (244, 137, 72), 866 | (245, 139, 71), 867 | (245, 140, 70), 868 | (246, 141, 69), 869 | (246, 143, 68), 870 | (247, 144, 68), 871 | (247, 145, 67), 872 | (247, 147, 66), 873 | (248, 148, 65), 874 | (248, 149, 64), 875 | (249, 151, 63), 876 | (249, 152, 62), 877 | (249, 154, 62), 878 | (250, 155, 61), 879 | (250, 156, 60), 880 | (250, 158, 59), 881 | (251, 159, 58), 882 | (251, 161, 57), 883 | (251, 162, 56), 884 | (252, 163, 56), 885 | (252, 165, 55), 886 | (252, 166, 54), 887 | (252, 168, 53), 888 | (252, 169, 52), 889 | (253, 171, 51), 890 | (253, 172, 51), 891 | (253, 174, 50), 892 | (253, 175, 49), 893 | (253, 177, 48), 894 | (253, 178, 47), 895 | (253, 180, 47), 896 | (253, 181, 46), 897 | (254, 183, 45), 898 | (254, 184, 44), 899 | (254, 186, 44), 900 | (254, 187, 43), 901 | (254, 189, 42), 902 | (254, 190, 42), 903 | (254, 192, 41), 904 | (253, 194, 41), 905 | (253, 195, 40), 906 | (253, 197, 39), 907 | (253, 198, 39), 908 | (253, 200, 39), 909 | (253, 202, 38), 910 | (253, 203, 38), 911 | (252, 205, 37), 912 | (252, 206, 37), 913 | (252, 208, 37), 914 | (252, 210, 37), 915 | (251, 211, 36), 916 | (251, 213, 36), 917 | (251, 215, 36), 918 | (250, 216, 36), 919 | (250, 218, 36), 920 | (249, 220, 36), 921 | (249, 221, 37), 922 | (248, 223, 37), 923 | (248, 225, 37), 924 | (247, 226, 37), 925 | (247, 228, 37), 926 | (246, 230, 38), 927 | (246, 232, 38), 928 | (245, 233, 38), 929 | (245, 235, 39), 930 | (244, 237, 39), 931 | (243, 238, 39), 932 | (243, 240, 39), 933 | (242, 242, 39), 934 | (241, 244, 38), 935 | (241, 245, 37), 936 | (240, 247, 36), 937 | (240, 249, 33), 938 | ] 939 | 940 | 941 | def viridis_colormap(): 942 | return [ 943 | (68, 1, 84), 944 | (68, 2, 86), 945 | (69, 4, 87), 946 | (69, 5, 89), 947 | (70, 7, 90), 948 | (70, 8, 92), 949 | (70, 10, 93), 950 | (70, 11, 94), 951 | (71, 13, 96), 952 | (71, 14, 97), 953 | (71, 16, 99), 954 | (71, 17, 100), 955 | (71, 19, 101), 956 | (72, 20, 103), 957 | (72, 22, 104), 958 | (72, 23, 105), 959 | (72, 24, 106), 960 | (72, 26, 108), 961 | (72, 27, 109), 962 | (72, 28, 110), 963 | (72, 29, 111), 964 | (72, 31, 112), 965 | (72, 32, 113), 966 | (72, 33, 115), 967 | (72, 35, 116), 968 | (72, 36, 117), 969 | (72, 37, 118), 970 | (72, 38, 119), 971 | (72, 40, 120), 972 | (72, 41, 121), 973 | (71, 42, 122), 974 | (71, 44, 122), 975 | (71, 45, 123), 976 | (71, 46, 124), 977 | (71, 47, 125), 978 | (70, 48, 126), 979 | (70, 50, 126), 980 | (70, 51, 127), 981 | (70, 52, 128), 982 | (69, 53, 129), 983 | (69, 55, 129), 984 | (69, 56, 130), 985 | (68, 57, 131), 986 | (68, 58, 131), 987 | (68, 59, 132), 988 | (67, 61, 132), 989 | (67, 62, 133), 990 | (66, 63, 133), 991 | (66, 64, 134), 992 | (66, 65, 134), 993 | (65, 66, 135), 994 | (65, 68, 135), 995 | (64, 69, 136), 996 | (64, 70, 136), 997 | (63, 71, 136), 998 | (63, 72, 137), 999 | (62, 73, 137), 1000 | (62, 74, 137), 1001 | (62, 76, 138), 1002 | (61, 77, 138), 1003 | (61, 78, 138), 1004 | (60, 79, 138), 1005 | (60, 80, 139), 1006 | (59, 81, 139), 1007 | (59, 82, 139), 1008 | (58, 83, 139), 1009 | (58, 84, 140), 1010 | (57, 85, 140), 1011 | (57, 86, 140), 1012 | (56, 88, 140), 1013 | (56, 89, 140), 1014 | (55, 90, 140), 1015 | (55, 91, 141), 1016 | (54, 92, 141), 1017 | (54, 93, 141), 1018 | (53, 94, 141), 1019 | (53, 95, 141), 1020 | (52, 96, 141), 1021 | (52, 97, 141), 1022 | (51, 98, 141), 1023 | (51, 99, 141), 1024 | (50, 100, 142), 1025 | (50, 101, 142), 1026 | (49, 102, 142), 1027 | (49, 103, 142), 1028 | (49, 104, 142), 1029 | (48, 105, 142), 1030 | (48, 106, 142), 1031 | (47, 107, 142), 1032 | (47, 108, 142), 1033 | (46, 109, 142), 1034 | (46, 110, 142), 1035 | (46, 111, 142), 1036 | (45, 112, 142), 1037 | (45, 113, 142), 1038 | (44, 113, 142), 1039 | (44, 114, 142), 1040 | (44, 115, 142), 1041 | (43, 116, 142), 1042 | (43, 117, 142), 1043 | (42, 118, 142), 1044 | (42, 119, 142), 1045 | (42, 120, 142), 1046 | (41, 121, 142), 1047 | (41, 122, 142), 1048 | (41, 123, 142), 1049 | (40, 124, 142), 1050 | (40, 125, 142), 1051 | (39, 126, 142), 1052 | (39, 127, 142), 1053 | (39, 128, 142), 1054 | (38, 129, 142), 1055 | (38, 130, 142), 1056 | (38, 130, 142), 1057 | (37, 131, 142), 1058 | (37, 132, 142), 1059 | (37, 133, 142), 1060 | (36, 134, 142), 1061 | (36, 135, 142), 1062 | (35, 136, 142), 1063 | (35, 137, 142), 1064 | (35, 138, 141), 1065 | (34, 139, 141), 1066 | (34, 140, 141), 1067 | (34, 141, 141), 1068 | (33, 142, 141), 1069 | (33, 143, 141), 1070 | (33, 144, 141), 1071 | (33, 145, 140), 1072 | (32, 146, 140), 1073 | (32, 146, 140), 1074 | (32, 147, 140), 1075 | (31, 148, 140), 1076 | (31, 149, 139), 1077 | (31, 150, 139), 1078 | (31, 151, 139), 1079 | (31, 152, 139), 1080 | (31, 153, 138), 1081 | (31, 154, 138), 1082 | (30, 155, 138), 1083 | (30, 156, 137), 1084 | (30, 157, 137), 1085 | (31, 158, 137), 1086 | (31, 159, 136), 1087 | (31, 160, 136), 1088 | (31, 161, 136), 1089 | (31, 161, 135), 1090 | (31, 162, 135), 1091 | (32, 163, 134), 1092 | (32, 164, 134), 1093 | (33, 165, 133), 1094 | (33, 166, 133), 1095 | (34, 167, 133), 1096 | (34, 168, 132), 1097 | (35, 169, 131), 1098 | (36, 170, 131), 1099 | (37, 171, 130), 1100 | (37, 172, 130), 1101 | (38, 173, 129), 1102 | (39, 173, 129), 1103 | (40, 174, 128), 1104 | (41, 175, 127), 1105 | (42, 176, 127), 1106 | (44, 177, 126), 1107 | (45, 178, 125), 1108 | (46, 179, 124), 1109 | (47, 180, 124), 1110 | (49, 181, 123), 1111 | (50, 182, 122), 1112 | (52, 182, 121), 1113 | (53, 183, 121), 1114 | (55, 184, 120), 1115 | (56, 185, 119), 1116 | (58, 186, 118), 1117 | (59, 187, 117), 1118 | (61, 188, 116), 1119 | (63, 188, 115), 1120 | (64, 189, 114), 1121 | (66, 190, 113), 1122 | (68, 191, 112), 1123 | (70, 192, 111), 1124 | (72, 193, 110), 1125 | (74, 193, 109), 1126 | (76, 194, 108), 1127 | (78, 195, 107), 1128 | (80, 196, 106), 1129 | (82, 197, 105), 1130 | (84, 197, 104), 1131 | (86, 198, 103), 1132 | (88, 199, 101), 1133 | (90, 200, 100), 1134 | (92, 200, 99), 1135 | (94, 201, 98), 1136 | (96, 202, 96), 1137 | (99, 203, 95), 1138 | (101, 203, 94), 1139 | (103, 204, 92), 1140 | (105, 205, 91), 1141 | (108, 205, 90), 1142 | (110, 206, 88), 1143 | (112, 207, 87), 1144 | (115, 208, 86), 1145 | (117, 208, 84), 1146 | (119, 209, 83), 1147 | (122, 209, 81), 1148 | (124, 210, 80), 1149 | (127, 211, 78), 1150 | (129, 211, 77), 1151 | (132, 212, 75), 1152 | (134, 213, 73), 1153 | (137, 213, 72), 1154 | (139, 214, 70), 1155 | (142, 214, 69), 1156 | (144, 215, 67), 1157 | (147, 215, 65), 1158 | (149, 216, 64), 1159 | (152, 216, 62), 1160 | (155, 217, 60), 1161 | (157, 217, 59), 1162 | (160, 218, 57), 1163 | (162, 218, 55), 1164 | (165, 219, 54), 1165 | (168, 219, 52), 1166 | (170, 220, 50), 1167 | (173, 220, 48), 1168 | (176, 221, 47), 1169 | (178, 221, 45), 1170 | (181, 222, 43), 1171 | (184, 222, 41), 1172 | (186, 222, 40), 1173 | (189, 223, 38), 1174 | (192, 223, 37), 1175 | (194, 223, 35), 1176 | (197, 224, 33), 1177 | (200, 224, 32), 1178 | (202, 225, 31), 1179 | (205, 225, 29), 1180 | (208, 225, 28), 1181 | (210, 226, 27), 1182 | (213, 226, 26), 1183 | (216, 226, 25), 1184 | (218, 227, 25), 1185 | (221, 227, 24), 1186 | (223, 227, 24), 1187 | (226, 228, 24), 1188 | (229, 228, 25), 1189 | (231, 228, 25), 1190 | (234, 229, 26), 1191 | (236, 229, 27), 1192 | (239, 229, 28), 1193 | (241, 229, 29), 1194 | (244, 230, 30), 1195 | (246, 230, 32), 1196 | (248, 230, 33), 1197 | (251, 231, 35), 1198 | (253, 231, 37), 1199 | ] 1200 | 1201 | 1202 | # not about the licensing of this. keeping it for now. 1203 | def google_slides_named_colors(): 1204 | return { 1205 | # row 1 1206 | "black": (0, 0, 0), 1207 | "dark_grey_4": (67, 67, 67), 1208 | "dark_grey_3": (102, 102, 102), 1209 | "dark_grey_2": (153, 153, 153), 1210 | "grey": (183, 183, 183), 1211 | "light_grey_1": (204, 204, 204), 1212 | "light_grey_2": (217, 217, 217), 1213 | "light_grey_3": (239, 239, 239), 1214 | "white": (255, 255, 255), 1215 | # row 2 1216 | "red_berry": (151, 3, 0), 1217 | "red": (245, 8, 2), 1218 | "orange": (247, 153, 4), 1219 | "yellow": (253, 255, 1), 1220 | "green": (74, 255, 0), 1221 | "cyan": (83, 255, 255), 1222 | "cornflower_blue": (74, 134, 232), 1223 | "blue": (38, 1, 255), 1224 | "purple": (153, 1, 254), 1225 | "magenta": (247, 0, 255), 1226 | # row 3 1227 | "light_red_berry_3": (230, 184, 175), 1228 | "light_red_3": (244, 204, 205), 1229 | "light_orange_3": (252, 229, 205), 1230 | "light_yellow_3": (253, 242, 204), 1231 | "light_green_3": (217, 234, 211), 1232 | "light_cyan_3": (208, 224, 228), 1233 | "light_cornflower_blue_3": (202, 218, 248), 1234 | "light_blue_3": (208, 226, 243), 1235 | "light_purple_3": (217, 210, 233), 1236 | "light_magenta_3": (234, 209, 220), 1237 | # row 4 1238 | "light_red_berry_2": (221, 125, 106), 1239 | "light_red_2": (234, 153, 153), 1240 | "light_orange_2": (249, 203, 156), 1241 | "light_yellow_2": (252, 230, 153), 1242 | "light_green_2": (182, 215, 168), 1243 | "light_cyan_2": (162, 196, 201), 1244 | "light_cornflower_blue_2": (164, 194, 244), 1245 | "light_blue_2": (159, 197, 232), 1246 | "light_purple_2": (180, 167, 214), 1247 | "light_magenta_2": (213, 166, 189), 1248 | # row 5 1249 | "light_red_berry_1": (204, 65, 37), 1250 | "light_red_1": (224, 101, 102), 1251 | "light_orange_1": (246, 179, 107), 1252 | "light_yellow_1": (251, 218, 101), 1253 | "light_green_1": (147, 196, 124), 1254 | "light_cyan_1": (118, 165, 175), 1255 | "light_cornflower_blue_1": (109, 157, 235), 1256 | "light_blue_1": (111, 168, 220), 1257 | "light_purple_1": (142, 123, 195), 1258 | "light_magenta_1": (194, 123, 160), 1259 | # row 6 1260 | "dark_red_berry_1": (166, 28, 0), 1261 | "dark_red_1": (205, 5, 0), 1262 | "dark_orange_1": (230, 144, 56), 1263 | "dark_yellow_1": (241, 194, 51), 1264 | "dark_green_1": (106, 168, 78), 1265 | "dark_cyan_1": (69, 129, 142), 1266 | "dark_cornflower_blue_1": (60, 120, 216), 1267 | "dark_blue_1": (61, 132, 198), 1268 | "dark_purple_1": (103, 77, 167), 1269 | "dark_magenta_1": (166, 77, 120), 1270 | # row 7 1271 | "dark_red_berry_2": (132, 33, 11), 1272 | "dark_red_2": (153, 3, 0), 1273 | "dark_orange_2": (180, 94, 6), 1274 | "dark_yellow_2": (191, 144, 0), 1275 | "dark_green_2": (56, 118, 29), 1276 | "dark_cyan_2": (21, 79, 92), 1277 | "dark_cornflower_blue_2": (36, 85, 204), 1278 | "dark_blue_2": (28, 82, 148), 1279 | "dark_purple_2": (53, 29, 116), 1280 | "dark_magenta_2": (115, 27, 70), 1281 | # row 8 1282 | "dark_red_berry_3": (91, 15, 0), 1283 | "dark_red_3": (101, 1, 0), 1284 | "dark_orange_3": (120, 63, 4), 1285 | "dark_yellow_3": (127, 96, 0), 1286 | "dark_green_3": (39, 78, 18), 1287 | "dark_cyan_3": (12, 52, 61), 1288 | "dark_cornflower_blue_3": (28, 68, 134), 1289 | "dark_blue_3": (15, 55, 99), 1290 | "dark_purple_3": (32, 18, 77), 1291 | "dark_magenta_3": (76, 16, 48) 1292 | } 1293 | 1294 | 1295 | def seaborn_colors(): 1296 | # https://seaborn.pydata.org/tutorial/color_palettes.html 1297 | return [(76, 113, 176), (221, 131, 82), (85, 168, 103), (129, 113, 179), 1298 | (147, 120, 96), (218, 139, 195), (140, 140, 140), (205, 185, 115), 1299 | (100, 181, 205)] 1300 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | 3 | setup(name='sane_tikz', 4 | version='0.1', 5 | description='Python to TikZ transpiler', 6 | long_description=open('tutorial.md', 'r', encoding='utf-8').read(), 7 | long_description_content_type='text/markdown', 8 | url='http://github.com/negrinho/sane_tikz', 9 | author='Renato Negrinho', 10 | author_email='renato.negrinho@gmail.com', 11 | license='MIT', 12 | packages=find_packages(include=["sane_tikz*"]), 13 | python_requires='>=3.6', 14 | install_requires=["numpy"], 15 | classifiers=[ 16 | 'Intended Audience :: Science/Research', 17 | 'Development Status :: 3 - Alpha', 18 | 'License :: OSI Approved :: MIT License', 19 | 'Programming Language :: Python :: 3.6', 20 | "Topic :: Scientific/Engineering :: Visualization" 21 | ]) -------------------------------------------------------------------------------- /tutorial.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Overview 4 | 5 | `sane_tikz` follows a draw-and-place philosophy. 6 | You draw on the canvas and then use functionality to place the visual elements. 7 | There is no distinction between auxiliary code that you write and the code of `sane_tikz` so always consider creating functions to help you accomplish things when creating your figures. 8 | 9 | Every program starts with 10 | ``` 11 | import sane_tikz as stz 12 | import formatting as fmt 13 | ``` 14 | which imports the drawing, grouping, alignment, distribution, and coordinate computation functionalities of the library. 15 | `formatting` contains functionality to generate the TikZ formatting strings that are used for different purposes (e.g., making lines dashed or dotted, or changing the opacity of a fill). 16 | Eventually, every example ends with a call to `stz.draw_to_tikz_standalone` which generates the code for a TikZ figure to a file. 17 | This draw function unpacks a visual element into its components and draws them individually. 18 | 19 | Perhaps the most useful concept in `sane_tikz` is grouping. 20 | If you have visual elements `e1` and `e2`, you can group them to create a new visual element `e_grouped = [e1, e2]`, i.e., by wrapping the visual elements in a list. 21 | The new element `e_grouped` will be manipulated as a visual element in its own right, meaning that its bounding box is updated accordingly, and therefore all functions that rely on bounding box computations have their behavior updated. 22 | The order that elements are grouped matters when drawing them to the canvas. 23 | A visual element is decomposed into its sub-elements (if any) by going top to bottom and left to right. 24 | Every element can be eventually decomposed down to basic visual elements such as math equations, line segments, circles, rectangles, and so on. 25 | This recursive decomposition can be inspected in the `stz.draw_to_tikz` function which is used by the `stz.draw_to_tikz_standalone`. 26 | This means that we can impose a drawing ordering simply by ordering the elements correctly in the grouping. 27 | In the call to `stz.draw_to_tikz_standalone`, all the elements of the figure are grouped. 28 | Oftentimes for figures, there is no particular ordering that must be imposed because the sub-elements don't overlap. 29 | 30 | Other important concepts are moving existing elements and computing coordinates of interest. 31 | 32 | # Simple example 33 | 34 | The following example is drawn by the code below, which will be broken down into pieces for explaining its purpose. 35 | This code corresponds to [this](https://github.com/negrinho/sane_tikz/blob/master/examples/pentagon.pdf) figure. 36 | 37 | Importing the library and defining some basic values for specifying the figure. 38 | In examples, we often use this format which allows us to change some high-level characteristics of the figure and regenerate the output. 39 | This is great compared to what you would need to do in a WYSIWYG editor to change high-level aspects of the figure (e.g., spacing or line width). 40 | ``` 41 | import sane_tikz as stz 42 | import formatting as fmt 43 | 44 | label_spacing = 0.25 45 | pentagon_radius = 1.2 46 | x_axis_length = 4.0 47 | y_axis_length = 3.0 48 | extra_length = 0.4 49 | a_circle_radius = 0.08 50 | s_fmt = fmt.arrow_heads("end") 51 | f_fmt = fmt.line_and_fill_colors('black', 'black') 52 | ``` 53 | 54 | This defines the coordinates of the vertices of the pentagon and finally generates the representation for the pentagon through the call to `stz.closed_path`. 55 | ``` 56 | cs = [ 57 | stz.coords_on_circle([0, 0], pentagon_radius, 90.0 + i * (360.0 / 5)) 58 | for i in range(5) 59 | ] 60 | e = stz.closed_path(cs) 61 | ``` 62 | 63 | This is the computation of the coordinates for placing various labels in the figure. 64 | Note that the computation of these coordinates is done with respect to the vertices of the pentagon by translating them in appropriate directions. 65 | ``` 66 | origin_cs = stz.translate_coords_horizontally(cs[2], -1.0) 67 | x_end_cs = stz.translate_coords_horizontally(origin_cs, x_axis_length) 68 | y_end_cs = stz.translate_coords_vertically(origin_cs, y_axis_length) 69 | x_start_cs = stz.translate_coords_horizontally(origin_cs, -extra_length) 70 | y_start_cs = stz.translate_coords_vertically(origin_cs, -extra_length) 71 | x_label_cs = stz.translate_coords_vertically(x_end_cs, -label_spacing) 72 | y_label_cs = stz.translate_coords_horizontally(y_end_cs, -label_spacing) 73 | origin_label_cs = stz.translate_coords_diagonally(origin_cs, -label_spacing) 74 | ``` 75 | 76 | Create the representation of the axes. 77 | Note that they are grouped together. 78 | A formatting string is used to create a line segment with an arrowhead. 79 | See `formatting` for other options. 80 | ``` 81 | axes = [ 82 | stz.line_segment(x_start_cs, x_end_cs, s_fmt), 83 | stz.line_segment(y_start_cs, y_end_cs, s_fmt) 84 | ] 85 | ``` 86 | 87 | Creates the representations of the labels in the figure along with a filled circle on point A. 88 | ``` 89 | labels = [ 90 | stz.latex([cs[0][0], cs[0][1] + label_spacing], "$C$"), 91 | stz.latex([cs[1][0] - label_spacing, cs[1][1]], "$B$"), 92 | stz.latex([cs[2][0], cs[2][1] - a_circle_radius - label_spacing], 93 | "$A(1, 0)$"), 94 | stz.latex([cs[3][0], cs[3][1] - label_spacing], "$E$"), 95 | stz.latex([cs[4][0] + label_spacing, cs[4][1]], "$D$"), 96 | stz.circle(cs[2], a_circle_radius, f_fmt), 97 | stz.latex(x_label_cs, "$x$"), 98 | stz.latex(y_label_cs, "$y$"), 99 | stz.latex(origin_label_cs, "$O$"), 100 | ] 101 | ``` 102 | 103 | Finally, all the elements in the figure are grouped into a single one (i.e., `[e, axes, labels]`, which represents the pentagon, the axes, and the labels, respectively). 104 | The compilation of this figure into TikZ code is done by `stz.draw_to_tikz_standalone`. 105 | The resulting tex file can then be compiled by a Latex compiler (e.g., pdflatex) to generate the visual output (see [here](https://github.com/negrinho/sane_tikz/blob/master/examples/pentagon.tex) for the result for this figure). 106 | All figures are drawn in a lazy fashion, where first we define the representation of the figure in terms of basic visual elements and then compile them to TikZ code. 107 | This allows us to define visual elements and move them around before generating the final visual output. 108 | Grouping is a very powerful feature. 109 | For example, in the call below, we could have omitted all labels by simply passing `[e, axes]` instead of `[e, axes, labels]`. 110 | We are also free to keep adding elements and generating new figures with them, even after the call to `stz.draw_to_tikz_standalone`. 111 | This makes it easy to generate many related figures. 112 | ``` 113 | stz.draw_to_tikz_standalone([e, labels, axes], "pentagon.tex") 114 | ``` 115 | 116 | # Design overview 117 | 118 | ## Naming 119 | 120 | We often prefix or suffix variable names with `cs` when they refer to coordinates, which are simply a list with a pair of numbers, which is a coordinate of a point in the canvas. 121 | Functions that return coordinates often contain the substring `coords` in their names, e.g., `stz.translate_coords_horizontally` and `stz.coords_on_circle`. 122 | These functions are often useful for computing coordinates of interest, such as coordinates on a circle, on a line segment, or on a rectangle. 123 | For example, if you wanted the coordinates that are 45 degrees outside the origin at a distance of 5cm, you would call `stz.coords_on_circle([0, 0], 5.0, 45.0)`, which would output the desired values. 124 | These functions mimic some of the hand drawing procedures that you do with a ruler, compass, and protractor. 125 | 126 | For visual elements, we often use the variable `e` (or `e_lst`) to denote them. 127 | These are elements that can eventually be converted to a TikZ representation. 128 | Contrary to coordinates, there isn't a single substring that appears in a function name when it produces elements to be drawn. 129 | Examples of this are `stz.circle` and `stz.line_segment`. 130 | These do not draw directly an element, simply they return a representation of the element to be drawn (i.e., a representation from which the TikZ string representing the object can be drawn). 131 | The representation of an element to draw is, if we are talking about the most basic elements, a dictionary from strings to values that contains enough information to generate the TikZ representation for that element, and if more complex, a list of nested lists containing many visual elements (i.e., these are created through grouping). 132 | 133 | ## Grouping 134 | 135 | Grouping is one of the most important functionalities of the language, and one of the most powerful, especially when combined with the placement and alignment functionalities that use bounding box computations. 136 | Grouping corresponds to lumping various elements into a new element. 137 | This is done easily by wrapping the elements into a list and passing the list around. 138 | This new element will function as an element in its own right with respect to bounding box computations. 139 | 140 | ## Translation and alignment 141 | 142 | Given various elements, often regular such as multiple circles of the same size, there is often the need of aligning them (horizontally or vertically) or distributing them (horizontally or vertically). 143 | These needs are met by functions that take visual elements (grouped or not) and translate them around to implement the desired transformation. 144 | Note that these functions have side-effects, meaning that the state of the visual elements passed to the functions will change to implement the desired transformations. 145 | Translation and alignment functions operate on visual elements (grouped or not) and usually have movement-related terms in their function name (e.g., `translate`, `place`, `align`, and `distribute`). 146 | The fact that they take elements can often be determined by the names of arguments of the functions, e.g., `e` or `e_lst`. 147 | Some functions take reference elements that are used to compute quantities that are then used to specify a placement, e.g., `place_above_and_align_to_the_center` takes `e`, `e_ref`, and `spacing`; `e` is the element to be placed above `e_ref` such that the bounding boxes of `e` and `e_ref` are at a distance `spacing` from each other and their centers are aligned; only `e` is moved with respect to `e_ref`. 148 | Many functions of this type exist such as `place_below_and_align_to_the_center`, `distribute_vertically_with_spacing`, any many more. 149 | I recommend reading the source code for these functions which are often short and rely on high-level functionality (see immediately below for one example). 150 | ``` 151 | def distribute_vertically_with_spacing(e_lst, spacing): 152 | for i in range(1, len(e_lst)): 153 | e = e_lst[i] 154 | e_prev = e_lst[i - 1] 155 | cs = bbox(e)[1] 156 | cs_prev = bbox(e_prev)[0] 157 | delta_y = cs_prev[1] - cs[1] + spacing 158 | translate(e, 0, delta_y) 159 | ``` 160 | 161 | There exist also functions of this type that work over coordinates rather than elements (i.e., they take coordinates). 162 | These functions usually have `cs` in the name of the arguments and `coords` in the name of the function (e.g., `translate_coords_horizontally`). 163 | 164 | ## Bounding boxes 165 | 166 | Bounding boxes are convenient summaries when working with figures. 167 | They are used widely in translation and alignment functionalities. 168 | The figures are summarized into a pair of coordinates of the top left corner and the bottom right corner of the bounding box. 169 | The computation of the bounding box for an element is done by ungrouping recursively an element until it is expressed into basic elements for which we can compute the bounding box and then put back together through logic on how to combine multiple bounding boxes into a single bounding box (see `stz.bbox`). 170 | This function is widely used, both in functionality within sane_tikz (e.g., `place_to_the_right`, `distribute_vertically_with_spacing`, and many others) and in drawing specific figures. 171 | Bounding box computation may fail in cases where the grouped element contains a basic element which doesn’t yet have functionality to compute its bounding box. 172 | 173 | ## Coordinates 174 | 175 | Coordinates are the starting point for much of what is done in this library. 176 | Coordinates are used in specifying different visual elements, for example rectangles (i.e., `stz.rectangle` which is specified through the coordinates of the top left corner and the bottom corner and an optional formatting string (e.g., for changing the colors of the line or the fill)). Examples of functions in this category are 177 | `coords_on_circle`, `antipodal_coords`, `coords_on_ellipse`, `coords_on_rectangle`, `coords_on_line_segment`, `coords_on_line_segment`, `coords_on_line_with_x_value`, `coords_on_line_with_y_value`, `coords_from_deltas`, and `coords_on_grid`. 178 | Coordinate computation is also important for moving elements to specific places. 179 | 180 | Ocasionally, coordinates are computed with respect to other elements or other coordinates, e.g., `center_coords` and `coords_from_bbox_fn` compute the coordinates of the center of the bounding box of an element and the coordinates that are the output of a function of the coordinates of the bounding box, respectively. 181 | 182 | ## LaTex support 183 | 184 | Latex typesetting is accomplished through `stz.latex` which takes both a string (in math mode or otherwise) and the coordinates of where that string is to be placed. 185 | Formatting options using `anchor` and `alignment` are often useful for specifying the placement of the string relative to the coordinates specified. 186 | This implementation allows to write LaTex code in a fairly transparent way, e.g., any string that would be possible to write in math mode (between `$` or `$$`) is valid and so are environments (although additional trial and error may be necessary here in case errors are thrown). 187 | The conversion of the LaTex string to the TiKz code is fairly transparent as it is done through a node placed at the coordinates specified. 188 | 189 | ## Formatting 190 | 191 | Most formatting is delegated to the `formatting` library. 192 | The functionality of this library was designed to help generate TikZ formatting strings given a set of options. 193 | These can be options for fill, line width, line style, opacity, defining new colors, using color maps, and so on. 194 | Multiple formatting strings can be combined into a single one using `fmt.combine_tikz_strs`. 195 | This string is then passed as an argument (often called `tikz_str` in the function signature) to define appropriate options (e.g., in `stz.rectangle`). 196 | There is little enforcement of the correctness of the string; the functions there serve mostly as a way of making clear what are the most common options available and providing guidance in assigning values to them. 197 | `formatting` is not comprehensive; any valid formatting string that you would use in TikZ is valid and can be plugged in directly, rather than going through functions in `formatting`. 198 | See the figures in the example folder for more information about their usage. 199 | 200 | # A more complex example 201 | 202 | Here is an explanation for [tree.py](https://github.com/negrinho/sane_tikz/blob/master/examples/tree.py) which produces [tree.pdf](https://github.com/negrinho/sane_tikz/blob/master/examples/tree.pdf). 203 | This example shows the use of many of the functionalities discussed in this tutorial such as grouping, placement, and coordinate computation. 204 | ``` 205 | # reproduction of https://en.wikipedia.org/wiki/Binary_search_algorithm#/media/File:Binary_search_tree_search_4.svg 206 | 207 | import sane_tikz as stz 208 | import formatting as fmt 209 | ``` 210 | 211 | Basic formatting options for the figure. 212 | Changes to the figure can be accomplished by changing the values for these parameters and regenerating the TikZ code. 213 | ``` 214 | node_radius = 0.30 215 | vertical_node_spacing = 1.4 * node_radius 216 | first_level_horizontal_node_spacing = 1.8 217 | arrow_angle = 30.0 218 | bbox_spacing = 0.1 219 | label_spacing = 0.4 220 | line_width = 1.2 * fmt.standard_line_width 221 | 222 | s_lw = fmt.line_width(line_width) 223 | ``` 224 | 225 | Auxiliary function to draw a circle with Latex annotation at `(0, 0)`. 226 | ``` 227 | fn = lambda expr: [ 228 | stz.circle([0, 0], node_radius, s_lw), 229 | stz.latex([0, 0], expr) 230 | ] 231 | ``` 232 | 233 | Auxiliary function to place the node horizontally in its place. 234 | ``` 235 | def place(e, lst): 236 | delta = 0.0 237 | for i, sign in enumerate(lst): 238 | delta += sign * (node_radius + first_level_horizontal_node_spacing / 239 | (2 * (i + 1.0))) 240 | stz.translate_horizontally(e, delta) 241 | ``` 242 | 243 | Auxiliary function to connect two nodes (with optional color for line). `line_segment_between_circles` returns a line segment that you can draw. 244 | ``` 245 | def connect(e_from, e_to, color_name="black"): 246 | s_fmt = fmt.combine_tikz_strs( 247 | [fmt.arrow_heads("end"), 248 | fmt.line_color(color_name), s_lw]) 249 | from_cs = stz.center_coords(e_from) 250 | to_cs = stz.center_coords(e_to) 251 | out_angle = stz.vector_to_angle([from_cs, to_cs]) 252 | in_angle = out_angle + 180.0 253 | return stz.line_segment_between_circles(from_cs, node_radius, out_angle, 254 | to_cs, node_radius, in_angle, s_fmt) 255 | ``` 256 | 257 | Auxiliary function to compute the bounding box of `e_lst` and expand it additivively to draw the dashed bounding box. 258 | ``` 259 | def dashed_bbox(e_lst): 260 | s_fmt = fmt.combine_tikz_strs([fmt.line_style("dashed"), s_lw]) 261 | top_left_cs, bottom_right_cs = stz.bbox(e_lst) 262 | return stz.rectangle_from_additive_resizing(top_left_cs, bottom_right_cs, 263 | 2.0 * bbox_spacing, 264 | 2.0 * bbox_spacing, s_fmt) 265 | ``` 266 | 267 | Auxiliary function to label a node to the left and the right at some spacing from it. 268 | ``` 269 | def label_right(e, expr): 270 | cs = stz.coords_from_bbox_with_fn(e, stz.right_center_coords) 271 | cs = stz.translate_coords(cs, label_spacing, 0.1) 272 | return stz.latex(cs, "\\scriptsize{%s}" % expr) 273 | 274 | def label_left(e, expr): 275 | cs = stz.coords_from_bbox_with_fn(e, stz.left_center_coords) 276 | cs = stz.translate_coords(cs, -label_spacing, 0.1) 277 | return stz.latex(cs, "\\scriptsize{%s}" % expr) 278 | ``` 279 | 280 | Creates all the nodes. 281 | They aren't yet in the right positions. 282 | ``` 283 | nodes = [] 284 | for i in [8, 3, 10, 1, 6, 14, 4, 7, 13]: 285 | if i == 4: 286 | s = "\\textbf{%s}" % str(i) 287 | else: 288 | s = str(i) 289 | nodes.append(fn(s)) 290 | ``` 291 | 292 | Distributes them vertically. 293 | Note that the nodes are grouped by level. 294 | ``` 295 | stz.distribute_vertically_with_spacing( 296 | [nodes[0:1], nodes[1:3], nodes[3:6], nodes[6:9]][::-1], vertical_node_spacing) 297 | ``` 298 | 299 | Fixes the horizontal spacing between the nodes of the tree at each level. 300 | ``` 301 | place(nodes[1], [-1]) 302 | place(nodes[2], [1]) 303 | place(nodes[3], [-1, -1]) 304 | place(nodes[4], [-1, 1]) 305 | place(nodes[5], [1, 1]) 306 | place(nodes[6], [-1, 1, -1]) 307 | place(nodes[7], [-1, 1, 1]) 308 | place(nodes[8], [1, 1, -1]) 309 | ``` 310 | 311 | Draws all the connections. 312 | ``` 313 | connections = [ 314 | connect(nodes[0], nodes[1], "blue"), 315 | connect(nodes[0], nodes[2]), 316 | connect(nodes[1], nodes[3]), 317 | connect(nodes[1], nodes[4], "blue"), 318 | connect(nodes[2], nodes[5]), 319 | connect(nodes[4], nodes[6], "blue"), 320 | connect(nodes[4], nodes[7]), 321 | connect(nodes[5], nodes[8]), 322 | ] 323 | ``` 324 | 325 | Highlight the node that you care about by changing the TikZ formatting string for it. 326 | (Kind of low-level, but can be done by accessing directly the dictionary representations of the basic visual elements). 327 | ``` 328 | nodes[-3][0]["tikz_str"] = fmt.combine_tikz_strs( 329 | [nodes[-3][0]["tikz_str"], 330 | fmt.line_and_fill_colors("mygreen", "mygreen")]) 331 | nodes[-3][1]["tikz_str"] = fmt.combine_tikz_strs( 332 | [nodes[-3][0]["tikz_str"], "text=white"]) 333 | ``` 334 | 335 | Draw the dashed boxes, which will be in the right places. 336 | ``` 337 | bb1 = dashed_bbox([nodes[6]]) 338 | bb2 = dashed_bbox([bb1, nodes[4], nodes[7]]) 339 | bb3 = dashed_bbox([bb2, nodes[1], nodes[3]]) 340 | bboxes = [bb1, bb2, bb3] 341 | ``` 342 | 343 | Draw the labels. 344 | ``` 345 | labels = [ 346 | label_left(nodes[0], "4 < 8"), 347 | label_left(nodes[1], "4 > 3"), 348 | label_left(nodes[4], "4 < 6"), 349 | ] 350 | ``` 351 | 352 | Define the colors that you going to use in the figure in RGB. 353 | These are then passed in `draw_to_tikz_standalone` to specify the user-defined colors used in the figure. 354 | ``` 355 | name2color = {"mygreen": (2, 129, 0)} 356 | ``` 357 | 358 | Grouping all the visual elements of the figure. 359 | This is really powerful in general, e.g., you can compute the coordinates of the group by simply doing `stz.bbox([nodes, connections, bboxes, labels])`. 360 | ``` 361 | e = [nodes, connections, bboxes, labels] 362 | ``` 363 | 364 | Finally, compile to TikZ, i.e., generate the TikZ code. 365 | If any user-defined colors are needed for the figure, they need to be defined through a string to RGB tuple dictionary passed to the function (i.e., `name2color`). 366 | ``` 367 | stz.draw_to_tikz_standalone(e, "tree.tex", name2color) 368 | ``` 369 | 370 | Two recurring patterns we have observed above are the creation of auxiliary functions that take arguments corresponding to some parametrization of a visual element and then return the visual element in the right place (e.g., `dashed_bbox` and `connect`) and functions that take existing visual elements and place them in the right place (often as a function of some parametrization, e.g., `place`. 371 | These functions could be very well present in the main library `sane_tikz`. 372 | The main deciding factor in developing a function in a user file or in a library file is its expected widespread use. 373 | If we expect a function to be useful for a wide variety of figures, then we include it in the main library. 374 | Otherwise, it is kept in the local file for the figure. 375 | 376 | Additional examples are available in the [examples](https://github.com/negrinho/sane_tikz/tree/master/examples) folder. 377 | Inspecting the intermediate states of the figures should also give insight about what each function accomplishes, both in terms of creating new visual elements and of moving existing elements to the right place. 378 | --------------------------------------------------------------------------------