51

I am plotting two time series and computing varies indices for them.

How to write these indices for these plots outside the plot using annotation or text in python?

Below is my code

import matplotlib.pyplot as plt

obs_graph=plt.plot(obs_df['cms'], '-r', label='Observed')
plt.legend(loc='best')
plt.hold(True)
sim_graph=plt.plot(sim_df['cms'], '-g', label="Simulated")
plt.legend(loc='best')
plt.ylabel('Daily Discharge (m^3/s)')
plt.xlabel('Year')
plt.title('Observed vs Simulated Daily Discharge')
textstr = 'NSE=%.2f\nRMSE=%.2f\n'%(NSE, RMSE)
# print textstr
plt.text(2000, 2000, textstr, fontsize=14)
plt.grid(True)
plt.show()

I want to print teststr outside the plots. Here is the current plot:

plot

Trenton McKinney
  • 56,955
  • 33
  • 144
  • 158
dsbisht
  • 1,025
  • 4
  • 13
  • 24
  • 5
    Next time, please provide some [reproducible](https://stackoverflow.com/help/minimal-reproducible-example) code (i.e., don't reference a DataFrame that only you have access to). – Nathaniel Jones Jul 23 '20 at 00:58

4 Answers4

112

It's probably best to define the position in figure coordinates instead of data coordinates as you'd probably not want the text to change its position when changing the data.

Using figure coordinates can be done either by specifying the figure transform (fig.transFigure)

plt.text(0.02, 0.5, textstr, fontsize=14, transform=plt.gcf().transFigure)

or by using the text method of the figure instead of that of the axes.

plt.gcf().text(0.02, 0.5, textstr, fontsize=14)

In both cases the coordinates to place the text are in figure coordinates, where (0,0) is the bottom left and (1,1) is the top right of the figure.

At the end you still may want to provide some extra space for the text to fit next to the axes, using plt.subplots_adjust(left=0.3) or so.

ImportanceOfBeingErnest
  • 321,279
  • 53
  • 665
  • 712
8

Looks like the text is there but it lies outside of the figure boundary. Use subplots_adjust() to make room for the text:

import matplotlib.pyplot as plt

textstr = 'NSE=%.2f\nRMSE=%.2f\n'%(1, 2)
plt.xlim(2002, 2008)
plt.ylim(0, 4500)
# print textstr
plt.text(2000, 2000, textstr, fontsize=14)
plt.grid(True)
plt.subplots_adjust(left=0.25)
plt.show()

enter image description here

MB-F
  • 22,770
  • 4
  • 61
  • 116
  • I could not see the text even after using 'subplots_adjust()'. Do I need to define `xlim` and `ylim`? – dsbisht Feb 24 '17 at 10:21
  • Nope, i used those to get the same axis range without your data. Do you see the text if you run my example? Maybe different versions of Matplotlib? I use version 1.5.2 (on Python 3, but that should be irrelevant). You can also play with different values of `left`, `right`, `top`, and `bottom` - maybe the text is somewhere else. – MB-F Feb 24 '17 at 10:28
  • I tried top,left,bottom and right, but could not find the text. I am using Python 2.7.11 and matplotlib version 1.5.1. Yes I can see the text in your example. I have uploaded my file in edit, could you lease check them with my code. – dsbisht Feb 24 '17 at 10:58
  • Sorry, I don't have access to Python until after the weekend. I suggest you start with a working example and add your stuff piece by piece until it stops working. Then fix that part :) – MB-F Feb 24 '17 at 16:27
  • Thanks buddy, I did it. Eventually :) – dsbisht Feb 27 '17 at 04:52
  • 2
    Good to hear! You could share your solution as another answer to help others who run into the same problem in the future. – MB-F Feb 27 '17 at 06:59
  • I could not print the textscr outside the plot, but could placed it inside the plot using `plt.figtext(0.15,0.58, textstr, fontsize=14, bbox=dict(facecolor='wheat', alpha=0.5))` – dsbisht Feb 27 '17 at 07:14
  • @dsbisht Please provide your solution so others can benefit – KansaiRobot Nov 21 '22 at 11:53
4

According to Matplotlib version 3.3.4 documentation, you can use the figtext method:

matplotlib.pyplot.figtext(x, y, s, fontdict=None, **kwargs)

or in your case

plt.figtext(0.02, 0.5, textstr, fontsize=14)

It seems to give the same result as one of the answer by @ImportanceOfBeingErnest, i.e. :

plt.gcf().text(0.02, 0.5, textstr, fontsize=14) 

I have used both commands with Matplobib version 3.3.1.

Sun Bear
  • 7,594
  • 11
  • 56
  • 102
0

Use bbox

If you want the box to be outside the plot, and not to be cropped when saving the figure, you have to use bbox. Here is a minimal working example:

import numpy as np
import matplotlib.pyplot as plt

fig, ax = plt.subplots(1, 1, figsize=(8, 4))
x = np.random.normal(loc=15.0, scale=2.0, size=10000)
mu = np.mean(x)
sigma = np.std(x)

my_text = '- Estimated quantities -\n'
my_text += fr'$\mu=${mu:.3f}' + '\n' + fr'$\sigma=${sigma:.3f}'

ax.hist(x, bins=100)
props = dict(boxstyle='round', facecolor='grey', alpha=0.15)  # bbox features
ax.text(1.03, 0.98, my_text, transform=ax.transAxes, fontsize=12, verticalalignment='top', bbox=props)
plt.tight_layout()
plt.show()

Histogram with box outside frame

More details here: https://matplotlib.org/3.3.4/gallery/recipes/placing_text_boxes.html

Florian Lalande
  • 494
  • 4
  • 13