4

For all types plots I've seen so far, matplotlib will automatically center them when no xlim(), ylim() values are given. Example:

import matplotlib.pyplot as plt
A_pts = [(162.5, 137.5), (211.0, 158.3), (89.6, 133.7)]
ax = plt.subplot(111)
ax.scatter(*A_pts)
plt.show()

enter image description here

But when I plot a Polygon

ax = plt.subplot(111)
triangle = plt.Polygon(A_pts, fill=None, edgecolor='r')
ax.add_patch(triangle)
plt.show()

the plot window is shown with limits [0, 1] for both axis, which results in the polygon not being visible. I have to explicitly pass proper limits so that it will show in the plot window

ax.set_xlim(80, 250)
ax.set_ylim(120, 170)

Is this by design or am I missing something?

Gabriel
  • 40,504
  • 73
  • 230
  • 404
  • Have you tried `ax.relim()` and `ax.autoscale_view()` (from [here](http://stackoverflow.com/a/11039268/3026320))? I mean, it could be by design, being a more "basic" kind of way to plot data on the graph. – berna1111 Apr 03 '17 at 15:04
  • 1
    I know there are ways to pass limits to the plot, I'm wondering why `matplotlib` will not do it by default for this type of plot when it does for (as far as I can tell) all other types. – Gabriel Apr 03 '17 at 15:06
  • 2
    I think it is by design, since `add_patch` is not really a *plotting* function, so much as an artist control function. Things like `scatter` actually make the artists from data you pass in - `add_patch` doesn't make the artist, it just puts it into the Axes object. – Ajean Apr 03 '17 at 15:50
  • 2
    @Ajean is right. Once you're using `add_patch` you're at the one of the lowest levels of the public API and we're assuming that you're taking full control of the figure. – Paul H Apr 03 '17 at 16:00
  • Thank you for the explanation guys, it sounds very reasonable. @Ajean, could you turn your cmmt into an answer so I can accept it? – Gabriel Apr 03 '17 at 16:03
  • Did so, with extra info from @PaulH 's comment. – Ajean Apr 03 '17 at 16:07

2 Answers2

12

When adding a patch, the data limits of the axes are changed, which you can see by printing ax.dataLim.bounds. However, add_patch does not call the automlimits function, while most other plotting commands do.

This means you can either set the limits of the plot manually (as in the question) or you can just call ax.autoscale_view() to adjust the limits. The latter has of course the advantage that you don't need to determine the limits beforehands and that the margins are preserved.

import matplotlib.pyplot as plt
pts = [(162, 137), (211, 158), (89, 133)]
ax = plt.subplot(111)
triangle = plt.Polygon(pts, fill=None, edgecolor='r')
ax.add_patch(triangle)
print ax.dataLim.bounds

ax.autoscale_view()
plt.show() 

Once you would add some other plot which does automatically scale the limits, there is no need to call autoscale_view() any more.

import matplotlib.pyplot as plt
pts = [(162, 137), (211, 158), (89, 133)]
ax = plt.subplot(111)
triangle = plt.Polygon(pts, fill=None, edgecolor='r')
ax.add_patch(triangle)

ax.plot([100,151,200,100], [124,135,128,124])

plt.show()

enter image description here

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

It is by design. Things like plot and scatter are plotting functions that take in data, create the artists and form the plot/adjust the axes. add_patch on the other hand, is more of an artist control method (it does not create the artist, the artist itself gets passed in). As mentioned in a comment by Paul H, it is at the lowest level of the public API and at that level it is assumed that you have full control of the figure.

Ajean
  • 5,528
  • 14
  • 46
  • 69
  • What is a *'level of the API'*? What makes some commands be part of one specific level? – ImportanceOfBeingErnest Apr 03 '17 at 20:55
  • I'm not quite sure what you're going after - programmers should understand "low-level" versus "high-level." I'm not a matplotlib dev so I can't list out *exactly* how they have constructed all of their code base, but I also suspect that's not what you really wanted. You gave a very nice answer with the specifics, therefore this comment feels overly snarky to me - please let me know if this is not the case. For your benefit I also made it clearer everything I was quoting from a comment. – Ajean Apr 03 '17 at 21:53
  • So I was wondering if you (or maybe rather @PaulH) have any reason to divide the matplotlib API into levels. To me when looking at the code, and also the documentation `add_patch` is on the same level (whatever that is) as `plot`. Or maybe in other words, given a command `x`, what determines it's level? (I'm aware that this may be going a bit far away from the original question, so you don't need to respond to it. I'm just curious. ;-)) – ImportanceOfBeingErnest Apr 03 '17 at 22:01
  • Ah I see. Well, I can't speak for Paul H, but (for example), even though `plot` is technically an object method, it's also wrapped by `pyplot` and requires no underlying knowledge of matplotlib's artist architecture because its inputs are *data*. `add_patch` is not wrapped by pyplot, and requires that you construct an actual patch object first (and actually I think that the fact that `Polygon` is available from pyplot is an implementation detail rather than a documented feature). To me, the latter requires more knowledge of the guts. Not much, really, but still more. – Ajean Apr 03 '17 at 22:08