Curso matplotlib - Elementos auxiliares (Anotações)
O plt.annotate() já foi utilizado anteriormente, mas não foi estudado a fundo. Em geral, esta é a melhor forma de adicionar texto nos gráficos, especialmente se o este texto estiver relacionado a algum ponto do gráfico.
O elemento plt.annotate() recebe pelo menos dois parâmetros, sendo o primeiro parâmetro o text, que é o texto que será anotado (que deve ser uma str), e o segundo é o parâmetro xy, que é deve ser uma tuple de dois elementos (int ou float) com os valores de x e y referentes a posição onde o texto será anotado.
Por exemplo:
plt.figure(figsize=(8,6))
plt.scatter(x,y)
plt.annotate("minha anotação", (x[0], y[0]))
plt.show()
Figura 1 - Gráfico de dispersão com texto inserido com o plt.annotate().

Entretanto, o parâmetro xy define onde a anotação inicia. O parâmetro utilizado para definir onde o texto é realmente inserido é o parâmetro xytext, que também recebe uma tuple com as coordenadas xy.
Por exemplo, passando o mesmo valor para xy e xytext, obtemos o mesmo resultado obtido anteriormente (Figura 1):
plt.figure(figsize=(8,6))
plt.scatter(x,y)
plt.annotate("minha anotação", (x[0], y[0]), xytext=(x[0],y[0]))
plt.show()
Figura 2 - Gráfico de dispersão com texto inserido com o plt.annotate().

Mas ao passar valores diferentes para xy e xytext, obtemos um comportamento diferente:
plt.figure(figsize=(8,6))
plt.scatter(x,y)
plt.annotate("minha anotação", (x[0], y[0]), xytext=(x[0] + 0.3,y[0] + 0.5))
plt.show()
Figura 3 - Gráfico de dispersão com texto inserido com o plt.annotate().

Annotações com setas
Este espaço “vazio” é importante para a adição de elementos entre os pontos definidos como xy e xytext. Por exemplo, podemos adicionar uma seta dentro de plt.annotate(), passando o parâmetro arrowprops.
Este parâmetro recebe um dict com uma série de keys para inserir a seta. Para alterar a espessura dessa seta, passamos um número (int ou float) através da key width:
plt.figure(figsize=(8,6))
plt.scatter(x,y)
plt.annotate("minha anotação", (x[0], y[0]), xytext=(x[0] + 0.3,y[0] + 0.5),
arrowprops={'width': 2})
plt.show()
Figura 4 - Gráfico de dispersão com texto com flecha inserido com o plt.annotate().

Espessura da ponta da seta
Para alterar a espessura da cabeça da seta, passamos um número (int ou float) para a key headwidth:
plt.figure(figsize=(8,6))
plt.scatter(x,y)
plt.annotate("minha anotação", (x[0], y[0]), xytext=(x[0] + 0.3,y[0] + 0.5),
arrowprops={'width': 2, 'headwidth': 20})
plt.show()
Figura 5 - Gráfico de dispersão com texto com flecha inserido com o plt.annotate().

Comprimento da ponta seta
Para alterar o comprimento da cabeça da seta, passamos um número (int ou float) para a key headlength:
plt.figure(figsize=(8,6))
plt.scatter(x,y)
plt.annotate("minha anotação", (x[0], y[0]), xytext=(x[0] + 0.3,y[0] + 0.5),
arrowprops={'width': 2, 'headwidth': 20, 'headlength': 20})
plt.show()
Figura 6 - Gráfico de dispersão com texto com flecha inserido com o plt.annotate().

Espaçamento entre o início e fim da seta
Podemos ainda adicionar um espaçamento nos limites do elemento, de forma a evitar que a seta fique exatamente em cima do ponto. Fazemos isso passando um número (int ou float) para a key shrink:
plt.figure(figsize=(8,6))
plt.scatter(x,y)
plt.annotate("minha anotação", (x[0], y[0]), xytext=(x[0] + 0.3,y[0] + 0.5),
arrowprops={'width': 2, 'headwidth': 20, 'headlength': 20, 'shrink': 0.1,})
plt.show()
Figura 7 - Gráfico de dispersão com texto com flecha inserido com o plt.annotate().

Outras edições
Para alterar a cor, espessura da linha, estilo de linha, etc, utilizamos os parâmetros normalmente que vimos anteriormente, como o facecolor, linestyle,linewidth, etc. Por exemplo:
plt.figure(figsize=(8,6))
plt.scatter(x,y)
plt.annotate("minha anotação", (x[0], y[0]), xytext=(x[0] + 2,y[0] + 1.5),
arrowprops={'width': 1, 'headwidth': 20, 'headlength': 20, 'shrink': 0.01,
'facecolor': 'k', 'linewidth': 2, 'linestyle': ':'})
plt.show()
Figura 8 - Gráfico de dispersão com texto com flecha inserido com o plt.annotate().

Estilos pré definidos
Temos a opção de passar a key arrowstyle que tem uma série de values pré-definidos com estilos. Entretanto, ao utilizar esta key, não podemos passar as key widht, headwidht, headlength e shrink.
Por exemplo:
plt.figure(figsize=(8,6))
plt.scatter(x,y)
plt.annotate("minha anotação", (x[0], y[0]), xytext=(x[0] + .3, y[0] + 0.5),
arrowprops={'arrowstyle': '-['})
plt.show()
Figura 9 - Gráfico de dispersão com texto com flecha inserido com o plt.annotate().

Todos os estilos disponíveis estão exemplificados na figura abaixo, sendo que o valor anotado é o nome do estilo que deve ser passado como value para a key arrowstyle.

Click aqui para acessar o notebook utilizado para desenhar a imagem acima.
Um detalhe importante ao utilizar a anotação com setas, é a direção das setas, especialmente quando queremos que a seta seja paralela aos eixos. Por exemplo:
plt.figure(figsize=(8,6))
plt.scatter(x,y)
plt.annotate("minha anotação", xy=(x[1], y[1]), xytext=(x[2] + .3, y[1]),
arrowprops={'arrowstyle': '->'})
plt.show()
Figura 10 - Gráfico de dispersão com texto com flecha inserido com o plt.annotate().

Observe que, apesar dos valores de y em xy e em xytext serem os mesmos (y[1]) a linha da seta não é paralela ao eixo x. Para confirmar isto, vou adicionar uma reta paralela ao eixo x em y[1]:
plt.figure(figsize=(8,6))
plt.scatter(x,y)
plt.annotate("minha anotação", xy=(x[1], y[1]), xytext=(x[2] + .3, y[1]),
arrowprops={'arrowstyle': '->'})
plt.axhline(y=y[1], xmin=0, xmax=1)
plt.show()
Figura 11 - Gráfico de dispersão com texto com flecha inserido com o plt.annotate().

Isto acontece pois a seta é direcionada ao ponto xy vinda do centro do texto. Como a base do texto é o ponto setado em xytext, temos esta pequena inclinação.
Para contornar isto, basta passar o parâmetro va (de vertical alignment) em plt.annotate() como center:
plt.figure(figsize=(8,6))
plt.scatter(x,y)
plt.annotate("minha anotação", xy=(x[1], y[1]), xytext=(x[2] + .3, y[1]), va='center',
arrowprops={'arrowstyle': '->'})
plt.axhline(y=y[1], xmin=0, xmax=1)
plt.show()
Figura 12 - Gráfico de dispersão com texto com flecha inserido com o plt.annotate().

Maiores detalhes sobre este “problema” nesta thread no github.
Mais detalhes na sobre o plt.annotate()na documentação.