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