Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 8 additions & 20 deletions lib/matplotlib/axes/_axes.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
import functools
import itertools
import logging
Expand Down Expand Up @@ -1183,19 +1183,13 @@
# e.g. by errorbar()), which would make nanmin/nanmax stumble.
updatex = True
updatey = True
minx = np.nanmin(masked_verts[..., 0])
maxx = np.nanmax(masked_verts[..., 0])
miny = np.nanmin(masked_verts[..., 1])
maxy = np.nanmax(masked_verts[..., 1])
if self.name == "rectilinear":
datalim = lines.get_datalim(self.transData)
t = lines.get_transform()
updatex, updatey = t.contains_branch_separately(self.transData)
minx = np.nanmin(datalim.xmin)
maxx = np.nanmax(datalim.xmax)
miny = np.nanmin(datalim.ymin)
maxy = np.nanmax(datalim.ymax)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you know why this worked fine for the linear scale but not for the log scale?

Copy link
Copy Markdown
Member

@timhoffm timhoffm Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suspect this is rather a bug in LineCollection.get_datalim. That should not depend on the scale.

Collections can do weird things in that the stored data doesn't have to be the data coordinates, but e.g. can have offsets. Possibly something with how the stored data has to be interpreted is wrong.

Copy link
Copy Markdown
Contributor Author

@Vikash-Kumar-23 Vikash-Kumar-23 Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @rcomer
I don’t know the full root cause yet, but as @timhoffm noted it may be a bug in LineCollection.get_datalim(...) (or how that datalim is interpreted) that ends up being scale-dependent, so on log axes the autoscale limits can differ depending on when the scale is set. This change avoids that path by computing the limits directly from the underlying vertices, which makes the result consistent

else:
minx = np.nanmin(masked_verts[..., 0])
maxx = np.nanmax(masked_verts[..., 0])
miny = np.nanmin(masked_verts[..., 1])
maxy = np.nanmax(masked_verts[..., 1])

corners = (minx, miny), (maxx, maxy)
self.update_datalim(corners, updatex, updatey)
Expand Down Expand Up @@ -1275,19 +1269,13 @@
# e.g. by errorbar()), which would make nanmin/nanmax stumble.
updatex = True
updatey = True
minx = np.nanmin(masked_verts[..., 0])
maxx = np.nanmax(masked_verts[..., 0])
miny = np.nanmin(masked_verts[..., 1])
maxy = np.nanmax(masked_verts[..., 1])
if self.name == "rectilinear":
datalim = lines.get_datalim(self.transData)
t = lines.get_transform()
updatex, updatey = t.contains_branch_separately(self.transData)
minx = np.nanmin(datalim.xmin)
maxx = np.nanmax(datalim.xmax)
miny = np.nanmin(datalim.ymin)
maxy = np.nanmax(datalim.ymax)
else:
minx = np.nanmin(masked_verts[..., 0])
maxx = np.nanmax(masked_verts[..., 0])
miny = np.nanmin(masked_verts[..., 1])
maxy = np.nanmax(masked_verts[..., 1])

corners = (minx, miny), (maxx, maxy)
self.update_datalim(corners, updatex, updatey)
Expand Down
19 changes: 19 additions & 0 deletions lib/matplotlib/tests/test_axes.py
Original file line number Diff line number Diff line change
Expand Up @@ -4654,6 +4654,25 @@ def test_errorbar_limits():
ax.set_title('Errorbar upper and lower limits')


def test_errorbar_log_autoscale_order_independent():
x = 10 ** np.array([18, 18.1, 18.2, 18.3])
y = np.array([100, 80, 60, 30])
yerr = np.ones_like(y) * 10

fig1, ax1 = plt.subplots()
ax1.set_xscale("log")
ax1.set_yscale("log")
ax1.errorbar(x, y, yerr=yerr)

fig2, ax2 = plt.subplots()
ax2.errorbar(x, y, yerr=yerr)
ax2.set_xscale("log")
ax2.set_yscale("log")

assert_allclose(ax1.get_xlim(), ax2.get_xlim())
assert_allclose(ax1.get_ylim(), ax2.get_ylim())


def test_errorbar_nonefmt():
# Check that passing 'none' as a format still plots errorbars
x = np.arange(5)
Expand Down
Loading