diff --git a/figures/BP_text.svg b/figures/BP_text.svg new file mode 100644 index 0000000..6a5336e --- /dev/null +++ b/figures/BP_text.svg @@ -0,0 +1,24 @@ + + + + + + + + 2025-11-27T16:19:24.150236 + image/svg+xml + + + Matplotlib v3.10.5, https://matplotlib.org/ + + + + + + + + + + diff --git a/figures/HP_text.svg b/figures/HP_text.svg new file mode 100644 index 0000000..0442f98 --- /dev/null +++ b/figures/HP_text.svg @@ -0,0 +1,24 @@ + + + + + + + + 2025-11-27T16:19:25.433661 + image/svg+xml + + + Matplotlib v3.10.5, https://matplotlib.org/ + + + + + + + + + + diff --git a/figures/LP_text.svg b/figures/LP_text.svg new file mode 100644 index 0000000..92cdd91 --- /dev/null +++ b/figures/LP_text.svg @@ -0,0 +1,24 @@ + + + + + + + + 2025-11-27T16:19:25.024292 + image/svg+xml + + + Matplotlib v3.10.5, https://matplotlib.org/ + + + + + + + + + + diff --git a/figures/ascending_text.svg b/figures/ascending_text.svg new file mode 100644 index 0000000..ef4a79d --- /dev/null +++ b/figures/ascending_text.svg @@ -0,0 +1,24 @@ + + + + + + + + 2025-11-27T16:19:26.727815 + image/svg+xml + + + Matplotlib v3.10.5, https://matplotlib.org/ + + + + + + + + + + diff --git a/figures/brain_text.svg b/figures/brain_text.svg new file mode 100644 index 0000000..c7cb738 --- /dev/null +++ b/figures/brain_text.svg @@ -0,0 +1,24 @@ + + + + + + + + 2025-11-27T16:19:27.490158 + image/svg+xml + + + Matplotlib v3.10.5, https://matplotlib.org/ + + + + + + + + + + diff --git a/figures/interneurons_text.svg b/figures/interneurons_text.svg new file mode 100644 index 0000000..b8f89cc --- /dev/null +++ b/figures/interneurons_text.svg @@ -0,0 +1,24 @@ + + + + + + + + 2025-11-27T16:19:26.496410 + image/svg+xml + + + Matplotlib v3.10.5, https://matplotlib.org/ + + + + + + + + + + diff --git a/figures/neuronal_circuit_sketch.svg b/figures/neuronal_circuit_sketch.svg new file mode 100644 index 0000000..f94e3a5 --- /dev/null +++ b/figures/neuronal_circuit_sketch.svg @@ -0,0 +1,376 @@ + + + + diff --git a/figures/receptors_text.svg b/figures/receptors_text.svg new file mode 100644 index 0000000..080c087 --- /dev/null +++ b/figures/receptors_text.svg @@ -0,0 +1,24 @@ + + + + + + + + 2025-11-27T16:19:26.217264 + image/svg+xml + + + Matplotlib v3.10.5, https://matplotlib.org/ + + + + + + + + + + diff --git a/figures/threshold_text.svg b/figures/threshold_text.svg new file mode 100644 index 0000000..ba69cc2 --- /dev/null +++ b/figures/threshold_text.svg @@ -0,0 +1,24 @@ + + + + + + + + 2025-11-27T16:19:26.979087 + image/svg+xml + + + Matplotlib v3.10.5, https://matplotlib.org/ + + + + + + + + + + diff --git a/figures/tympanum_text.svg b/figures/tympanum_text.svg new file mode 100644 index 0000000..6e19773 --- /dev/null +++ b/figures/tympanum_text.svg @@ -0,0 +1,24 @@ + + + + + + + + 2025-11-27T16:19:25.816378 + image/svg+xml + + + Matplotlib v3.10.5, https://matplotlib.org/ + + + + + + + + + + diff --git a/python/save_latex_texts.py b/python/save_latex_texts.py new file mode 100644 index 0000000..b6c7052 --- /dev/null +++ b/python/save_latex_texts.py @@ -0,0 +1,194 @@ +import matplotlib.pyplot as plt + +plt.rcParams['text.usetex'] = True +plt.rcParams['font.family'] = 'computer modern roman' +plt.rcParams['mathtext.fontset'] = 'cm' +plt.rcParams['mathtext.default'] = 'regular' + +# Targets: +texts = { + 'BP': ('BP', 25), + 'LP': ('LP', 25), + 'HP': ('HP', 25), + 'tympanum': ('Tympanal\nMembrane', 13), + 'receptors': ('Receptor\nNeurons', 13), + 'interneurons': ('Local\nInterneurons', 13), + 'ascending': ('Ascending\nNeurons', 13), + 'threshold': ('Threshold\nNonlinearity', 13), + 'brain': ('Central\nBrain', 13), +} + +# Settings: +show_figs = True + +fig_props = { + 'figsize': (1, 1), + 'facecolor': 'none', + 'edgecolor': 'none', + 'frameon': False, + 'rasterized': True, + } + +ax_props = { + 'facecolor': 'none', + 'frame_on': False, + 'rasterized': True, + } + +text_props = { + 'color': 'k', + 'x': 0.5, + 'y': 0.5, + 'ha': 'center', + 'va': 'center', + 'rasterized': True, + } + +# Prepare variables: +grid_props = dict(left=0, right=1, top=1, bottom=0) + +# Save each target string: +for name, (text, fs) in texts.items(): + # print(f'Saving text figure for: {name}') + # print(name, text, fs) + fig, ax = plt.subplots(1, 1, gridspec_kw=grid_props, **fig_props) + ax.set(**ax_props) + ax.axis('off') + ax.text(s=text, fontsize=fs, **text_props) + fig.savefig(f'../figures/{name}_text.svg', + bbox_inches='tight', pad_inches=0) + if show_figs: + plt.show() + plt.close(fig) + + + + +def text_box(ax, text, xy, width, height, transform=None, + ha='center', va='center', **kwargs): + """ Maximizes fontsize of text to fit into a given bounding box. + Calculated fontsize depends on the aspect ratio of the bounding box, + the aspect ratio and alignment of the text, and the resolution and size + of the underlying figure. Text is not updated when resizing the figure. + + Parameters + ---------- + ax : matplotlib axes object + Target subplot to annotate the text. + text : str + Text to fit into the specified bounding box under the given alignments. + xy : tuple of floats or ints (2,) + Text position in the coordinate system specified by transform. + width : float or int + Rectangle width in the coordinate system specified by transform. + height : float or int + Rectangle height in the coordinate system specified by transform. + transform : matplotlib transform, optional + Underlying coordinate system of the bounding box. Determines the + interpretation of xy, width, and height. Falls back to data coordinates + if unspecified. The default is None. + ha : str, optional + Horizontal alignment of bounding box and text relative to the given xy. + The default is 'center'. + va : str, optional + Vertical alignment of bounding box and text relative to the given xy. + The default is 'center'. + **kwargs : dict, optional + Additional keyword arguments passed to ax.annotate() for specifying + different font properties of the returned text object. + + Returns + ------- + t : matplotlib text object + Annotated text object with adjusted fontsize to fit the bounding box. + """ + # Input interpretation: + if transform is None: + transform = ax.transData + fig = ax.get_figure() + x, y = xy + # Alignment-specific anchor points: + x_align1, x_align2 = { + 'center': (x - width / 2, x + width / 2), + 'left': (x, x + width), + 'right': (x - width, x), + }[ha] + y_align1, y_align2 = { + 'center': (y - height / 2, y + height / 2), + 'bottom': (y, y + height), + 'top': (y - height, y), + }[va] + # Anchor points in pixel: + left_corner = transform.transform((x_align1, y_align1)) + right_corner = transform.transform((x_align2, y_align2)) + # Bounding rectangle size in pixel: + pixel_width = right_corner[0] - left_corner[0] + pixel_height = right_corner[1] - left_corner[1] + # Adjust fontsize to box height (inch): + dpi = fig.dpi + rect_height = pixel_height / dpi + fs_initial = rect_height * 72 + # Plot first draft of the text: + t = ax.annotate(text, xy, ha=ha, va=va, xycoords=transform, **kwargs) + t.set_fontsize(fs_initial) + # Adjust fontsize to box width (inch): + bbox = t.get_window_extent(fig.canvas.get_renderer()) + fs_adjusted = fs_initial * pixel_width / bbox.width + t.set_fontsize(fs_adjusted) + return t + + +def text_graph(text, save_str=None, size=None, ax=None, show=False, + close=False, **kwargs): + """ Turns entire subplot into a text box that displays the given text. + Fontsize is maximized to fit the available bounding box. Text is always + centered in the subplot. Meant for creating scalable text elements that + comply with the style of other plot elements, especially for posters. + + Parameters + ---------- + text : str + Text to be displayed. Can be multiline. Text fontsize is maximized by + text_box() to fit a bounding box that covers the entire axes area. + save_str : str, optional + If specified, saves the underlying figure under the given path. For + best results, use a vector format such as .svg). The default is None. + size : tuple of floats or ints (2,), optional + If specified, creates a new figure with given size in inches and a + single subplot. Indirectly controls the aspect ratio of the text box. + Must be specified if ax is None. The default is None. + ax : matplotlib axes object, optional + If specified, the target subplot to turn into a text box. Can be used + to set more properties such as the background color of the text box. + Must be specified if size is None. The default is None. + show : bool, optional + If True, displays the figure before returning. Else, returns without + showing the figure. The default is False. + **kwargs : dict, optional + Keyword arguments passed to text_box() and further to ax.annotate() for + specifying additional font properties of the displayed text. + + Raises + ------ + ValueError + Breaks if neither size nor ax is specified to define a target subplot. + """ + # Input interpretation: + if size is not None: + fig, ax = plt.subplots(figsize=size) + elif ax is not None: + fig = ax.get_figure() + else: + raise ValueError('Either size or ax must be specified.') + # Turn drawable area of axes into a single text box: + text_box(ax, text, (0.5, 0.5), 1, 1, ax.transAxes, **kwargs) + # Hide other axes elements: + ax.xaxis.set_visible(False) + ax.yaxis.set_visible(False) + ax.spines[:].set_visible(False) + # Return options: + if save_str is not None: + fig.savefig(save_str, bbox_inches='tight') + if show: + plt.show() + return None \ No newline at end of file