-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
fill_between() misbehaves with logarithmic X axis #7371
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Fill_between is using linear interpolation to find the zero-crossing. To get the behavior you are expecting it would need to transform from data to screen space (or any equivalent coordinate system), interpolate, and then transform back to data space to get the zero-crossing. Normally with fill_between this doesn't make much difference because the curves have enough points in x that the interpolation is over a small interval. |
Thanks for the prompt response. I may be missing something obvious, but is there any reason why interpolated zero-crossings are "special"? I notice it seems to interpolate non-zero-crossing segments fine, for what it's worth: And since I don't have any sense of it -- is what you described a feasible solution that could be incorporated fairly easily, or would that be overly complex/computationally-expensive? |
Yes, the zero-crossings are special because they require inserting a data point in the array. That point is needed to define the polygon being filled. It's the start or end point of the line segment along the axis. |
I think the problem here is actually with import numpy as np
import matplotlib
import matplotlib.pyplot as plt
plt.xscale('log')
xs = np.array([10, 100])
ys = np.array([10, -25])
zeros = np.array([0, 0])
x_lots = np.linspace(10, 100, 512)
y_lots = np.linspace(10, -25, 512)
plt.plot(x_lots, y_lots)
plt.fill_between(xs, zeros, ys, where=ys > zeros, facecolor='green', interpolate=True)
plt.fill_between(xs, zeros, ys, where=ys < zeros, facecolor='red', interpolate=True)
plt.show() The problem is that there are enough points in your data and the |
@tacaswell, that was also my first reaction, but that is looking at the problem with the assumption that a line between two points on a log scale should be a log curve. This is not what we want, however, as a plotting library. We want to preserve the ability to make a straight line between any two points. Consider a spectrum on a log-log plot. If the theory says the PSD should go as the inverse second power of the frequency, you want to be able to plot a straight-line segment with a slope of -2. Fill_between is a bit different because it is inserting a data point--or a point that is most likely to be interpreted visually as a data point. It's debatable, but I came around to the idea that is should indeed do that interpolation linearly in data space, not in screen space as it does now. Yes, it would also make sense for the user in such an instance to make sure that the data points are closely spaced, and we could respond to this by leaving out the complexity of the transform-interpolate-inverse transform sequence. I'm close to neutral on this. |
I am confused, I think Both of these methods behave better if you up the density: import numpy as np
import matplotlib
import matplotlib.pyplot as plt
plt.xscale('log')
xs = np.array([10, 100])
ys = np.array([10, -25])
x_lots = np.linspace(10, 100, 512)
y_lots = np.linspace(10, -25, 512)
plt.plot(x_lots, y_lots)
plt.fill_between(xs, zeros, ys, where=ys > zeros, facecolor='green', interpolate=True, alpha=.5)
plt.fill_between(xs, zeros, ys, where=ys < zeros, facecolor='red', interpolate=True, alpha=.5)
plt.fill_between(x_lots, 0, y_lots, where=y_lots > 0, facecolor='green', interpolate=True, alpha=.5)
plt.fill_between(x_lots, 0, y_lots, where=y_lots < 0, facecolor='red', interpolate=True, alpha=.5) I am pretty strongly 👎 on doing the zero-crossing logic in screen space. I think it also makes sense for us to continue to connect point in screen-space with strait lines independent of the underlying transform, anything else will lead to excessive complication (for now). |
don't we have a transform_curve() method in the transform stack? Consider On Tue, Nov 1, 2016 at 4:02 PM, Thomas A Caswell notifications@github.com
|
On 2016/11/01 10:26 AM, Benjamin Root wrote:
Yes, that occurred to me also--but adding in that sort of functionality |
On 2016/11/01 10:02 AM, Thomas A Caswell wrote:
Yes, that is what the OP is expecting, and the behavior for which I was |
@tacaswell, I think your statements, |
This issue has been marked "inactive" because it has been 365 days since the last comment. If this issue is still present in recent Matplotlib releases, or the feature request is still wanted, please leave a comment and this label will be removed. If there are no updates in another 30 days, this issue will be automatically closed, but you are free to re-open or create a new issue if needed. We value issue reports, and this procedure is meant to help us resurface and prioritize issues that have not been addressed yet, not make them disappear. Thanks for your help! |
This seems to still be broken unfortunately. |
I suppose, interpolation should be done in screen space
should cover the same areas as
Note: The interpolation is done on execution of The relevant code section is |
This issue has been marked "inactive" because it has been 365 days since the last comment. If this issue is still present in recent Matplotlib releases, or the feature request is still wanted, please leave a comment and this label will be removed. If there are no updates in another 30 days, this issue will be automatically closed, but you are free to re-open or create a new issue if needed. We value issue reports, and this procedure is meant to help us resurface and prioritize issues that have not been addressed yet, not make them disappear. Thanks for your help! |
I'm seeing
fill_between()
drawing polygons incorrectly on a logarithmic X axis.If I comment out the
plt.xscale('log')
line everything comes out as expected:But with the log axis the
fill_between()
polygons don't align with theplt.plot(xs, ys)
line:(This is with matplotlib 1.5.3, installed via pip.)
The text was updated successfully, but these errors were encountered: