Why Does Pyplot.plot() Create An Additional Rectangle With Width=1, Height=1?
Solution 1:
You would not want to mess with all the children of the axes to get those of interest. If there are only bar plots in the axes, ax.patches
gives you the rectangles in the axes.
Concerning the labeling of the bars, the linked article may not be the best choice. It argues to calculate the distance of the label manually, which is not really useful. Instead you would just offset the annotation by some points compared to the bar top, using the argument textcoords="offset points"
to plt.annotation
.
import pandas as pd
import matplotlib.pyplot as plt
df = pd.DataFrame({'City': ['Berlin', 'Munich', 'Hamburg'],
'Population': [3426354, 1260391, 1739117]})
df = df.set_index('City')
ax = df.plot(kind='bar')
defautolabel(rects, ax):
for rect in rects:
x = rect.get_x() + rect.get_width()/2.
y = rect.get_height()
ax.annotate("{}".format(y), (x,y), xytext=(0,5), textcoords="offset points",
ha='center', va='bottom')
autolabel(ax.patches,ax)
ax.margins(y=0.1)
plt.show()
Finally note that using the shapes in the plot to create the annotations may still not be the optimal choice. Instead why not using the data itself?
import pandas as pd
import matplotlib.pyplot as plt
df = pd.DataFrame({'City': ['Berlin', 'Munich', 'Hamburg'],
'Population': [3426354, 1260391, 1739117]})
ax = df.plot(x = "City", y="Population", kind='bar')
defautolabel(s, ax=None, name=""):
x = s.name
y = s[name]
ax.annotate("{}".format(y), (x,y), xytext=(0,5), textcoords="offset points",
ha='center', va='bottom')
df.apply(autolabel, axis=1, ax=ax, name="Population")
ax.margins(y=0.1)
plt.show()
This produces the same plot as above.
Solution 2:
The fourth Rectangle is the bounding box for the Axis subplot. This is an artifact of the way Pyplot handles bounding boxes, it's not specific to Pandas. For example, plotting with regular Pyplot:
f, ax = plt.subplots()
ax.bar(range(3), df.Population.values)
rects = [rect for rect in ax.get_children() ifisinstance(rect, mpl.patches.Rectangle)]
for r in rects:
print(r)
Still results in four Rectangles:
Rectangle(-0.4,0;0.8x3.42635e+06)
Rectangle(0.6,0;0.8x1.26039e+06)
Rectangle(1.6,0;0.8x1.73912e+06)
Rectangle(0,0;1x1)
There's a line in the Pyplot tight layout docs which refers to this extra Rectangle (and also why its coordinates are (0,0),(1,1)
. It refers to a rect parameter:
...which specifies the bounding box that the subplots will be fit inside. The coordinates must be in normalized figure coordinates and the default is (0, 0, 1, 1).
There's probably a more official section of the Matplotlib documentation that describes this architecture more thoroughly, but I find those docs difficult to navigate, this is the best I could come up with.
Post a Comment for "Why Does Pyplot.plot() Create An Additional Rectangle With Width=1, Height=1?"