0

I would like to have an "annotation track" in Matplotlib, similar to similar functionality as in audio editing software - here an example from Audacity:

audacity

Basically, there are markers for regions that are labeled with text - and they are placed in a separate track, below - which is the "annotation track".

I came up with an example for something similar in Matplotlib:

import matplotlib as mpl
import matplotlib.pyplot as plt
from scipy import signal
import numpy as np

fig = plt.figure()
subplotpars = dict(left = 0.05, right=0.98, top=0.84, bottom=0.05, wspace=0.1)
gs = mpl.gridspec.GridSpec(2, 1, height_ratios=[9, 1], **subplotpars)
ax1 = fig.add_subplot(gs[0])
ax2 = fig.add_subplot(gs[1], sharex=ax1)
fig.subplots_adjust(hspace=0) # Remove horizontal space between axes

time_end = 100
num_elems = 10000
t_x = np.linspace(0, time_end, num_elems, endpoint=True)
sig_y_first = np.random.normal(0,1,num_elems)
# via https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.butter.html:
sos = signal.butter(N=10, Wn=15, btype='lowpass', fs=4000, output='sos') #
sig_y_filt = signal.sosfilt(sos, sig_y_first)
scalerA = np.linspace(0, 0.5, num_elems, endpoint=True)
scalerB =  np.linspace(8, 0, num_elems, endpoint=True)
sig_y = np.multiply(sig_y_filt, scalerB) + np.multiply(sig_y_first, scalerA)

ax1.plot(t_x, sig_y)

xranges_bounds = [10, 100]
prev_xbound = 0
for ix, xbound in enumerate(xranges_bounds):
  ax2.annotate("", (prev_xbound, 0.5), (xbound, 0.5), arrowprops={'arrowstyle':'<->'})
  ax2.text(prev_xbound + (xbound-prev_xbound)/2, 0.5, "the {:02d} range".format(ix+1))
  prev_xbound = xbound

plt.show()

The code results with:

matplotlib

I could find a better algo for centering the text labels, but in particular, what I am looking for, and quite really figure out, is:

  • The textual labels should be "boxed" (with a line/stroke outline around the words, and possibly a different background color) - as well as centered
  • In case the zoom level is such, that the visible region is too narrow to allow the entire text in the label to be printed (as is the case with "the 01 range"), I should just get a narrow box (with either no text; just the first few character(s) of the text; or "...") that fits - and the full text would be shown once the zoom level is large enough, so the width of the range is enough for the entire text.

Is there something like this already for Matplotlib?

sdbbs
  • 3,071
  • 3
  • 21
  • 58
  • 1
    this might help https://stackoverflow.com/questions/14531346/how-to-add-a-text-into-a-rectangle/14532863#14532863 – Paul H Dec 03 '21 at 16:56

0 Answers0