Make border of Label, bbox or axes.text flush with spines of Graph in python matplotlib

for a certain manuscript i need to position my label of the Graph exactly in the right or left top corner. The label needs a border with the same thickness as the spines of the graph. Currently i do it like this:

import matplotlib.pyplot as plt
import numpy as np
my_dpi=96
xposr_box=0.975 
ypos_box=0.94
nrows=3
Mytext="label"
GLOBAL_LINEWIDTH=2
fig, axes = plt.subplots(nrows=nrows, sharex=True, sharey=True, figsize=
               (380/my_dpi, 400/my_dpi), dpi=my_dpi)
fig.subplots_adjust(hspace=0.0001)
colors = ('k', 'r', 'b')
for ax, color in zip(axes, colors):
    data = np.random.random(1) * np.random.random(10)
    ax.plot(data, marker='o', linestyle='none', color=color)

for ax in ['top','bottom','left','right']:
    for idata in range(0,nrows):
        axes[idata].spines[ax].set_linewidth(GLOBAL_LINEWIDTH)


axes[0].text(xposr_box, ypos_box , Mytext, color='black',fontsize=8,
             horizontalalignment='right',verticalalignment='top', transform=axes[0].transAxes,
             bbox=dict(facecolor='white', edgecolor='black',linewidth=GLOBAL_LINEWIDTH)) 

plt.savefig("Label_test.png",format='png', dpi=600,transparent=True)

Image1

So i control the position of the box with the parameters:

xposr_box=0.975 
ypos_box=0.94

If i change the width of my plot, the position of my box also changes, but it should always have the top and right ( or left) spine directly on top of the graphs spines:

import matplotlib.pyplot as plt
import numpy as np
my_dpi=96
xposr_box=0.975 
ypos_box=0.94
nrows=3
Mytext="label"
GLOBAL_LINEWIDTH=2
fig, axes = plt.subplots(nrows=nrows, sharex=True, sharey=True, figsize=
               (500/my_dpi, 400/my_dpi), dpi=my_dpi)
fig.subplots_adjust(hspace=0.0001)
colors = ('k', 'r', 'b')
for ax, color in zip(axes, colors):
    data = np.random.random(1) * np.random.random(10)
    ax.plot(data, marker='o', linestyle='none', color=color)

for ax in ['top','bottom','left','right']:
    for idata in range(0,nrows):
        axes[idata].spines[ax].set_linewidth(GLOBAL_LINEWIDTH)


axes[0].text(xposr_box, ypos_box , Mytext, color='black',fontsize=8,
             horizontalalignment='right',verticalalignment='top',transform=axes[0].transAxes,
             bbox=dict(facecolor='white', edgecolor='black',linewidth=GLOBAL_LINEWIDTH)) 

plt.savefig("Label_test.png",format='png', dpi=600,transparent=True)

Image2

This should also be the case if the image is narrower not wider as in this example.I would like to avoid doing this manually. Is there a way to always position it where it should? Independent on the width and height of the plot
and the amount of stacked Graphs?

Solution:

The problem is that the position of a text element is relative to the text’s extent, not to its surrounding box. While it would in principle be possible to calculate the border padding and position the text such that it sits at coordinates (1,1)-borderpadding, this is rather cumbersome since (1,1) is in axes coordinates and borderpadding in figure points.

There is however a nice alternative, using matplotlib.offsetbox.AnchoredText. This creates a textbox which can be placed easily relative the the axes, using the location parameters like a legend, e.g. loc="upper right". Using a zero padding around that text box directly places it on top of the axes spines.

from matplotlib.offsetbox import AnchoredText
txt = AnchoredText("text", loc="upper right", pad=0.4, borderpad=0, )
ax.add_artist(txt)

A complete example:

import matplotlib.pyplot as plt
from matplotlib.offsetbox import AnchoredText
import numpy as np

my_dpi=96
nrows=3
Mytext="label"
plt.rcParams["axes.linewidth"] = 2
plt.rcParams["patch.linewidth"] = 2

fig, axes = plt.subplots(nrows=nrows, sharex=True, sharey=True, figsize=
               (500./my_dpi, 400./my_dpi), dpi=my_dpi)
fig.subplots_adjust(hspace=0.0001)
colors = ('k', 'r', 'b')
for ax, color in zip(axes, colors):
    data = np.random.random(1) * np.random.random(10)
    ax.plot(data, marker='o', linestyle='none', color=color)

txt = AnchoredText(Mytext, loc="upper right", 
                   pad=0.4, borderpad=0, prop={"fontsize":8})
axes[0].add_artist(txt)

plt.show()

enter image description here

Python matplotlib clockwise pie charts

I am playing a bit with Python and its matplotlib library, how can I create the following chart so that the first slice starts from the top and goes to the right (clockwise) instead of going to the left (counter clockwise):

enter image description here

Code:

import matplotlib.pyplot as plt
import re
import math

# The slices will be ordered and plotted counter-clockwise if startangle=90.
sizes = [175, 50, 25, 50]
total = sum(sizes)
print('TOTAL:')
print(total)
print('')
percentages = list(map(lambda x: str((x/(total * 1.00)) * 100) + '%', sizes))

print('PERCENTAGES:')
print(percentages)
backToFloat = list(map(lambda x: float(re.sub("%$", "", x)), percentages))
print('')

print('PERCENTAGES BACK TO FLOAT:')
print(backToFloat)
print('')

print('SUM OF PERCENTAGES')
print(str(sum(backToFloat)))
print('')
labels = percentages
colors = ['blue', 'red', 'green', 'orange']
patches, texts = plt.pie(sizes, colors=colors, startangle=-270)


plt.legend(patches, labels, loc="best")
# Set aspect ratio to be equal so that pie is drawn as a circle.
plt.axis('equal')
plt.tight_layout()
plt.show()

Solution:

To specify fractions direction of the pie chart, you must set the counterclock parameter to True or False (value is True by default). For your need, you must replace:

patches, texts = plt.pie(sizes, colors=colors, startangle=-270)

with:

patches, texts = plt.pie(sizes, counterclock=False, colors=colors, startangle=-270)

Python: ax.text not displaying in saved PDF

I am creating a figure with some text (example here: a sin curve with some text on the side) in an ipython notebook. The plot and text show up inline in my notebook, but when I save the figure I only see the plot and not the text. I’ve reproduced the problem with this example code:

import numpy as np
import matplotlib.pyplot as plt

fig,ax = plt.subplots(1)
x = np.linspace(0, 2*np.pi, 100)
y = np.sin(x)
ax.plot(x, y)
ax.text(8,0.9,'Some Text Here',multialignment='left', linespacing=2.)
plt.savefig('sin.pdf')

How can I see the text in the saved pdf?

Solution:

Figures shown in jupyter notebook are saved png images. They are saved with the option bbox_inches="tight".

In order to produce a pdf which looks exactly the same as the png in the notebook, you also need to use this option.

plt.savefig('sin.pdf', bbox_inches="tight")

The reason is that the coordinates (8,0.9) are outside the figure. So the text won’t appear in the saved version of it (It wouldn’t appear in an interactive figure either). The option bbox_inches="tight" expands or shrinks the saved range to include all elements of the canvas. Using this option is indeed useful for easily including elements which are outside the plot without having to care about figure size, margins and coordinates at all.

A final note: You are specifying the text’s position in data coordinates. This is usually undesired, because it makes the text’s position dependent on what data is shown in the axes. Instead it would make sense to specify it in axes coordiantes,

ax.text(1.1, .9, 'Some Text Here', va="top", transform=ax.transAxes)

such that it always sits at position (1.1,.9) with respect to the axes.