Skip to content
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

Axes.hist: use bottom for minimum if log and histtype='step...' #4608

Merged
merged 2 commits into from
Jul 10, 2015

Conversation

duncanmmacleod
Copy link
Contributor

This PR fixes #4606, whereby a histogram with log=True and histtype=step... would override bottom to prevent zeros on a log scale.

With the included patch, the same code (or at least very similar) as given in the issue produces the following:

import numpy
from matplotlib import pyplot
fig = pyplot.figure()
ax = fig.gca()
ax.hist(numpy.random.random(1000), bins=100, log=True, bottom=1e-2, histtype='stepfilled', label='Bottom = 1e-2')
ax.hist(numpy.random.random(1000), bins=100, log=True, histtype='stepfilled', label='No bottom', alpha=0.6, facecolor='red')
ax.set_ylim(1e-2, 1e3)
ax.legend()

mpl-hist-bottom

@jenshnielsen
Copy link
Member

The fix looks correct to me even if the remaining code is more complicated than I would like.

Could you add a couple of tests for this? I would add a test where bottom is larger than 1/base and one where it is smaller.

http://matplotlib.org/devel/testing.html#writing-an-image-comparison-test describes how to do image comparison tests. We probably only need a png test.

@duncanmmacleod
Copy link
Contributor Author

@jenshnielsen: I have drafted the following test, but wanted to run it by you before committing a new image to the repo:

@image_comparison(baseline_images=['hist_step_log_bottom'],
                  remove_text=True, extensions=['png'])
def test_hist_step_log_bottom():
    # check that bottom doesn't get overwritten by the 'minimum' on a
    # log scale histogram
    np.random.seed(0)
    data = np.random.standard_normal(2000)
    fig = plt.figure()
    ax = fig.add_subplot(111)
    ax.hist(data, log=True, histtype='stepfilled', alpha=0.5)
    ax.hist(data, log=True, histtype='stepfilled', bottom=1e-2, alpha=0.5)
    ax.hist(data, log=True, histtype='stepfilled', bottom=0.5, alpha=0.5)
    ax.set_ylim(9e-3, 1e3)

which produces (blue: no bottom, green: bottom < 1/base, red: bottom > 1/base):
hist_step_log_bottom
The test runs and passes in place on my system, at least.

@jenshnielsen
Copy link
Member

Thanks that looks good to me.

Perhaps is is worth setting the colours explicitly for the 3 hist plots to make it easier to compare the code to the image?

Adding a reference to the this pr i.e. #4608 to the comment would be useful too.

@WeatherGod
Copy link
Member

Does the gap at the bottom make sense?
On Jul 9, 2015 12:54 PM, "Jens Hedegaard Nielsen" notifications@github.com
wrote:

Thanks that looks good to me.

Perhaps is is worth setting the colours explicitly for the 3 sections to
make it easier to compare the code to the image?

Adding a reference to the this pr i.e. #4608
#4608 to the comment would
be useful too.


Reply to this email directly or view it on GitHub
#4608 (comment)
.

@duncanmmacleod
Copy link
Contributor Author

@WeatherGod: which gap? I have manually set the lower ybound to 9e-3 to highlight the bottom=1e-2 call, if that's what you mean.

@duncanmmacleod
Copy link
Contributor Author

@jenshnielsen: I can set the colours explicitly, my assumption was that the image is only every analysed by the test engine, and not by real humans. Anyways, simple, done.

@WeatherGod
Copy link
Member

I was seeing the gap between the green bar and the x-axis, and was
expecting to see blue for it not having a bottom, before realizing that
this is the stepfilled histogram. So, I might be getting confused as to
what the expected behavior is there (I don't use stepfilled).

On Thu, Jul 9, 2015 at 1:32 PM, Duncan Macleod notifications@github.com
wrote:

@jenshnielsen https://github.com/jenshnielsen: I can set the colours
explicitly, my assumption was that the image is only every analysed by the
test engine, and not by real humans. Anyways, simple, done.


Reply to this email directly or view it on GitHub
#4608 (comment)
.

@duncanmmacleod
Copy link
Contributor Author

On a log=True, histtype=step{filled} histogram the bottom is automatically set to 1/base (if normed=False, weights=None), or np.min(x[nonzero])/base otherwise. This PR fixes the bug whereby that default would over-ride the bottom specified by a user, even if non-zero and positive.

Perhaps the bottom for a log-scale hist might be best defaulted to some small positive number (1e-100) so long as that doesn't automatically set the orientation axis lower bound as well (which is the current behaviour). I'll leave that for another issue/PR.

@jenshnielsen
Copy link
Member

@duncanmmacleod Yes it's not at all critical. It just makes it a bit easier if the test breaks to understand what the intention of the test is

@jenshnielsen
Copy link
Member

It looks like there is another bug with the snapping of the top of the bars not being exactly identical see the last bar.

@jenshnielsen
Copy link
Member

Nevermind that is just bottom working as expected offsetting the histogram.
The reason this looks odd is just that the last bin is so much smaller than the rest as it should be.

@duncanmmacleod
Copy link
Contributor Author

I hadn't appreciated that setting bottom would actually move the lower-end of the bar, i.e. scale the bars to have the same height with a different starting point, but it looks like I've stumbled across a bug and a fix in the mean time.

I was actually just wanting to make sure that the minimum can be set to something off the bottom of the chart, especially when using weights. Anyways, if the tests are good, I will commit and wait for review.

@jenshnielsen
Copy link
Member

Neither had I. I think we should clarify the docstring but that is for another time.

Your test is good so please go ahead and commit it 👍

Perhaps it is worth adding a test where bottom is an array too. Something like the following should work:

np.random.seed(0)
data = (np.random.standard_normal(2000))
bottom = np.arange(1,11)
fig = plt.figure()
ax = fig.add_subplot(111)
hist1 = ax.hist(data, log=True, histtype='stepfilled', bottom=bottom, alpha=0.5, color='green')
hist2 = ax.hist(data, log=True, histtype='stepfilled', alpha=0.5, color='blue')
ax.set_ylim(9e-3, 1e3)
plt.show()

@tacaswell tacaswell added this to the next point release milestone Jul 10, 2015
- this new test checks that the `bottom` kwarg to `Axes.hist` behaves
  as expected under a variety of circumstances when
  `log=True, histtype='step{filled}' given
jenshnielsen added a commit that referenced this pull request Jul 10, 2015
Axes.hist: use bottom for minimum if log and histtype='step...'
@jenshnielsen jenshnielsen merged commit 8befb06 into matplotlib:master Jul 10, 2015
@jenshnielsen
Copy link
Member

Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Axes.hist with log=True, histtype='step...' ignores bottom kwarg
4 participants