X Tutup
Skip to content
Merged
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
8 changes: 4 additions & 4 deletions lib/matplotlib/axes/_axes.py
Original file line number Diff line number Diff line change
Expand Up @@ -2705,11 +2705,11 @@ def errorbar(self, x, y, yerr=None, xerr=None,

Parameters
----------
x : scalar
y : scalar
x : scalar or array-like
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I would just say "array-like", scalars is just a special case.

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.

I'd keep it this way. Array-like refers to iterable, which a scalar isn't.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

scatter, bar, step all use array_like in their docs even though they also accept scalars. Either way we should be consistent.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I think that it should be removed for x and y but retained for errx and erry. x and y are arrays to plot. As @anntzer says, scalars are just a special case that represents a dataset of size 1. For errx and erry, scalars have a somewhat special meaning, which should be emphasized in the docs. Will update.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Another argument in @anntzer's favor is that the scalar case is explicitly dealt with in the sentence above the parameters section.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

e.g. np.sum:

    Parameters
    ----------
    a : array_like
        Elements to sum.
In [1]: np.sum(1)
Out[1]: 1

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.

As I said, I really don't care as I consider Matplotlib's loose input format harmful and not useful for the project, but this convention is not only unclear, but not followed by major scientific projects (scipy, sklearn, skimage, sympy pandas and even Matplotlib).

It boils down whether you want or not to document the fact that errorbar takes scalars as input. I am, once again, totally fine with not documenting it, but let's not pretend that the current docstring documents this in any meaningful and clear way.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The previous sentence reads:

x, y, xerr, and yerr can all be scalars, which plots a single error bar at x, y.

I think that should be enough for most users.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think that's good enough.

FWIW git-grepping the codebase of scipy and skimage yields no result for ... or array-like or array-like or ... (where ... refers to "scalar", "float", or some similar term); meanwhile at least some functions that are documented to take an "array-like" as argument can also take a scalar.

scikit-learn is different because it documents the shape of the required input nearly every time it documents an input as array-like, so scalars are explicitly excluded by that shape info.

sympy uses the word array-like exactly twice in its docs (in the sense of not including scalars).

pandas seems to use the word array-like in the sense of not including scalars as well.

So overall I wouldn't say there's any global agreement.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Since this thread is based on an outdated diff, I went ahead and changed back to scalar or array-like. I think that is a reasonable compromise that does not sacrifice clarity, which is really the main objective here (more so than consistency in my opinion).

y : scalar or array-like

xerr/yerr : scalar or array-like, shape(n,1) or shape(2,n), optional
If a scalar number, len(N) array-like object, or an Nx1
xerr/yerr : scalar or array-like, shape(N,) or shape(2,N), optional
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.

This change gives me pause as there is a bunch of subtle logic in error bar that depends on this shape. Can the exact behavior of (N, ) and (N, 1) arrays be checked before this is merged?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes. I did some checks and the docs are 99% correct. I am submitting an issue right now about an inconsistency that I found.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Here is the issue: #8140

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The shape is currently checked with len, which means that N, is a more accurate representation than Nx1. I also think that it is less confusing than swapping the dimension that corresponds to N around in the different cases. As a verification, the following works as expected:

>>> import matplotlib.pyplot as plt
>>> plt.ion()
>>> f, a = plt.subplots()
>>> a.errorbar(*[[1, 2, 3, 4, 5, 6]]*2, yerr=list(range(6)), fmt='o')

while the following does not:

>>> a.errorbar(*[[1, 2, 3, 4, 5, 6]]*2, yerr=[[i] for i in range(6)], fmt='o')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/jfoxrabi/miniconda3/lib/python3.5/site-packages/matplotlib/__init__.py", line 1892, in inner
    return func(ax, *args, **kwargs)
  File "/home/jfoxrabi/miniconda3/lib/python3.5/site-packages/matplotlib/axes/_axes.py", line 3020, in errorbar
    lower, upper = extract_err(yerr, y)
  File "/home/jfoxrabi/miniconda3/lib/python3.5/site-packages/matplotlib/axes/_axes.py", line 2965, in extract_err
    in cbook.safezip(data, err)]
  File "/home/jfoxrabi/miniconda3/lib/python3.5/site-packages/matplotlib/axes/_axes.py", line 2964, in <listcomp>
    low = [thisx - thiserr for (thisx, thiserr)
TypeError: unsupported operand type(s) for -: 'int' and 'list'

However, this does work:

a.errorbar(*[[1, 2, 3, 4, 5, 6]]*2, yerr=np.array([[i] for i in range(6)]), fmt='o')

So technically, N, 1 was outright wrong for non-array array-likes.
Sorry about that syntax for x, y. I was so fascinated with the fact that it actually worked that I left it in :)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I went ahead and added this pair of examples to issue #8140

If a scalar number, len(N) array-like object, or a N-element
array-like object, errorbars are drawn at +/-value relative
to the data. Default is None.

Expand Down
X Tutup