Repository navigation
Improve error messages for unit conversion - #13005
Conversation
| """ | ||
| if unit is None: | ||
| raise ValueError( | ||
| 'Missing unit for StrCategoryConverter. This might be caused' |
There was a problem hiding this comment.
So what's missing here is the mapping from category to float. Worried about using unit in a user facing error because unit is a kwarg that doesn't have to be passed in for categoricals to work.
There was a problem hiding this comment.
Worried about using unit in a user facing error because unit is a kwarg that doesn't have to be passed in for categoricals to work.
That's why I'm casting the error message to "Failed to convert..." using raise ... from.
So what's missing here is the mapping from category to float.
Not sure what that means. Moving the example from pyplot to ax to make it a little more obvious:
ax = plt.gca()
ax.bar([1, 2, 3], [50, 10, 20])
ax.set_xticks(['banana', 'apple', 'pear'])
We are trying to string positions (not labels) to a float axis. IMHO there's nothing missing here and this should error out. Ideally, the error message would be something like "Attemtping to set categorical ticks to a non-categorical axis".
But there's no good place to raise that.
The original stacktrace before this PR was:
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-2-13c713392566> in <module>()
2 ax = plt.gca()
3 ax.bar([1, 2, 3], [50, 10, 20])
----> 4 ax.set_xticks(['banana', 'apple', 'pear'])
~/dev/matplotlib/lib/matplotlib/axes/_base.py in set_xticks(self, ticks, minor)
3303 Default is ``False``.
3304 """
-> 3305 ret = self.xaxis.set_ticks(ticks, minor=minor)
3306 self.stale = True
3307 return ret
~/dev/matplotlib/lib/matplotlib/axis.py in set_ticks(self, ticks, minor)
1686 """
1687 # XXX if the user changes units, the information will be lost here
-> 1688 ticks = self.convert_units(ticks)
1689 if len(ticks) > 1:
1690 xleft, xright = self.get_view_interval()
~/dev/matplotlib/lib/matplotlib/axis.py in convert_units(self, x)
1488 return x
1489
-> 1490 ret = self.converter.convert(x, self.units, self)
1491 return ret
1492
~/dev/matplotlib/lib/matplotlib/category.py in convert(value, unit, axis)
51
52 # force an update so it also does type checking
---> 53 unit.update(values)
54
55 str2idx = np.vectorize(unit._mapping.__getitem__,
AttributeError: 'NoneType' object has no attribute 'update'
So, you can raise
- in
set_ticks(self, ticks, minor)
Advantage: You know you are setting ticks, so you could issue "Attemtping to set categorical ticks to a non-categorical axis".
Disadvantage: You need to explicitly check ticks and the unit of Axis. - in
convert_units(self, x)
Advantage: You can investigate self.units and generate a more appropriate message related to categoricals.
Disadvantage: You don't know that you are setting ticks here. You would have to explicitly check which converter you are using. - in
convert(value, unit, axis)
Advantage: You know that unit must not be None so the check is trivial.
Disadvantage: You don't know anything about categorical axes anymore and therefore can only state that unit is missing and add a guess why that might be the case.
In that situation I decided to raise on 3. add add context information in 2. using the raise .. from.
There was a problem hiding this comment.
I'm not against the error, I worry that the specific word unit will lead users down a google rabbit hole that's misguided. Basically, there's an xunit/yunit kwarg:
https://matplotlib.org/gallery/units/bar_demo2.html#sphx-glr-gallery-units-bar-demo2-py
axs[1, 0].bar(cms, cms, bottom=bottom, width=width, xunits=inch, yunits=cm)So I worry an error message with the word unit might make users think the fix is to pass in something, when really the issue is that the axis input data is not a string so the axis is not registered as string units. I wonder if the following is enough:
'Axis does not support StrCategoryConvertor; axis data values must be strings'
Like you, I want to help people catch that the problem is the mismatch between the plot data and the tick data.
There was a problem hiding this comment.
Rephrased to
raise ValueError(
'Missing category information for StrCategoryConverter; '
'this might be caused by unintendedly mixing categorical and '
'numeric data')
I don't want to mention an Axis as we don't know the call context here. In the end, this is also why we can only guess the reason for the failure but not make a clear statement what to change.
| from matplotlib import cbook | ||
|
|
||
|
|
||
| class ConversionError(ValueError): |
There was a problem hiding this comment.
this is a bit bikesheddy but it looks more like a TypeError than a ValueError to me.
| if unit is None: | ||
| raise ValueError( | ||
| 'Missing unit for StrCategoryConverter. This might be caused' | ||
| 'by unintendedly mixing categorical and numeric data.') |
There was a problem hiding this comment.
Minor preference for error messages that are single sentence and without a final dot, as that's what we mostly have in the codebase (so replace the middle dot by a semicolon).
Also a missing space after "caused".
387c345 to
83a3631
Compare
4cebc36 to
e38410c
Compare
|
Travis CI failure is due to #13137 and unrelated to this PR. By me, this is ready to go in. |
| @staticmethod | ||
| def convert(value, unit, axis): | ||
| """Converts strings in value to floats using | ||
| """Convert strings in value to floats using |
There was a problem hiding this comment.
Just inherit the docstring from units.ConversionInterface perhaps? (and possibly edit that docstring).
There was a problem hiding this comment.
I don't think we can reasonably use an inherited docstring here. Using the conversion interface for string-index mapping is a bit of a stretch and justifies explicit description.
- type of
valueis a string, which is rather the exception for ConversionInterface - mark
unitasUnitData - note that axis is unused.
e38410c to
c9a0ac7
Compare
anntzer
left a comment
There was a problem hiding this comment.
anyone can merge (including tim) when ci passes.
|
Self-merging based on the reviews. The Travis CI failure is still due to #13137 (unrelated to this PR). |
|
Re-milestoned to 3.1 so we do not have to deal with backporting the |
PR Summary
Fixes #12990. The call stack is a bit lengthy, but that's because the error happens several levels down and at least the reason gets clear.
Assigning categoricals to floats.
results in
Assigning categoricals to dates.
results in