Gaps in histogram or bargap error depending on number of bins

Screen Link:
https://app.dataquest.io/c/56/m/306/the-weighted-mean-and-the-median/7/the-median-for-ordinal-scales

My Code:

import numpy as np

mean = houses['Overall Cond'].mean()
median = houses['Overall Cond'].median()

houses['Overall Cond'].plot.hist()
plt.show()

What I expected to happen:
A nice pretty histogram with no gaps.

What actually happened:
I got gaps…
Screenshot from 2021-09-27 12-05-27

Realizing that the data spans from 1 to 9 and that there are 10 bins (default), I realized the bins are (9-1)/10 units wide and therefore the [4.2, 5.0) bin is empty! Ok, easy enough to fix: change to 9 bins! While this generates a bargap error, it does produce a plot without gaps but the xlabels aren’t quite right.

houses['Overall Cond'].plot.hist(bins=9)
plt.show()

Error produced by the above code:

ValueErrorTraceback (most recent call last)
<ipython-input-1-5a1140c5ef17> in <module>()
     17 
     18 houses['Overall Cond'].plot.hist(bins=9)
---> 19 plt.show()
     20 
     21 print(houses['Overall Cond'].value_counts().sort_index())

/dataquest/system/env/python3/lib/python3.5/site-packages/matplotlib/pyplot.py in show(*args, **kw)
    252     """
    253     global _show
--> 254     return _show(*args, **kw)
    255 
    256 

/dataquest/system/libs/dq_matplotlib_backend.py in show(*args, **kw)
    123 
    124         results = backend_inline.show(*args, close=False, **kw)
--> 125         record_jsons(figures)
    126     finally:
    127         matplotlib.pyplot.close("all")

/dataquest/system/libs/dq_matplotlib_backend.py in record_jsons(figures)
    326 
    327     for figure in figures:
--> 328         plotly_fig = plotly_tools.mpl_to_plotly(figure).to_plotly_json()
    329         json_list.append(plotly_fig)
    330 

/dataquest/system/env/python3/src/plotly-master/packages/python/plotly/plotly/tools.py in mpl_to_plotly(fig, resize, strip_style, verbose)
    110     if matplotlylib:
    111         renderer = matplotlylib.PlotlyRenderer()
--> 112         matplotlylib.Exporter(renderer).run(fig)
    113         if resize:
    114             renderer.resize()

/dataquest/system/env/python3/src/plotly-master/packages/python/plotly/plotly/matplotlylib/mplexporter/exporter.py in run(self, fig)
     49             import matplotlib.pyplot as plt
     50             plt.close(fig)
---> 51         self.crawl_fig(fig)
     52 
     53     @staticmethod

/dataquest/system/env/python3/src/plotly-master/packages/python/plotly/plotly/matplotlylib/mplexporter/exporter.py in crawl_fig(self, fig)
    116                                        props=utils.get_figure_properties(fig)):
    117             for ax in fig.axes:
--> 118                 self.crawl_ax(ax)
    119 
    120     def crawl_ax(self, ax):

/dataquest/system/env/python3/src/plotly-master/packages/python/plotly/plotly/matplotlylib/mplexporter/exporter.py in crawl_ax(self, ax)
    147                 with self.renderer.draw_legend(legend=legend, props=props):
    148                     if props['visible']:
--> 149                         self.crawl_legend(ax, legend)
    150 
    151     def crawl_legend(self, ax, legend):

/usr/local/lib/python3.5/contextlib.py in __exit__(self, type, value, traceback)
     64         if type is None:
     65             try:
---> 66                 next(self.gen)
     67             except StopIteration:
     68                 return False

/dataquest/system/env/python3/src/plotly-master/packages/python/plotly/plotly/matplotlylib/mplexporter/renderers/base.py in draw_axes(self, ax, props)
     57         self.open_axes(ax=ax, props=props)
     58         yield
---> 59         self.close_axes(ax=ax)
     60         self._current_ax = None
     61         self._ax_props = {}

/dataquest/system/env/python3/src/plotly-master/packages/python/plotly/plotly/matplotlylib/renderer.py in close_axes(self, ax)
    197 
    198         """
--> 199         self.draw_bars(self.current_bars)
    200         self.msg += "  Closing axes\n"
    201         self.x_is_mpl_date = False

/dataquest/system/env/python3/src/plotly-master/packages/python/plotly/plotly/matplotlylib/renderer.py in draw_bars(self, bars)
    214             )
    215         for trace in mpl_traces:
--> 216             self.draw_bar(trace)
    217 
    218     def draw_bar(self, coll):

/dataquest/system/env/python3/src/plotly-master/packages/python/plotly/plotly/matplotlylib/renderer.py in draw_bar(self, coll)
    305             self.plotly_fig.add_trace(bar),
    306             if bar_gap is not None:
--> 307                 self.plotly_fig["layout"]["bargap"] = bar_gap
    308         else:
    309             self.msg += "    Bar chart not drawn\n"

/dataquest/system/env/python3/src/plotly-master/packages/python/plotly/plotly/basedatatypes.py in __setitem__(self, prop, value)
   4435         if match is None:
   4436             # Set as ordinary property
-> 4437             super(BaseLayoutHierarchyType, self).__setitem__(prop, value)
   4438         else:
   4439             # Set as subplotid property

/dataquest/system/env/python3/src/plotly-master/packages/python/plotly/plotly/basedatatypes.py in __setitem__(self, prop, value)
   3488             # ### Handle simple property ###
   3489             else:
-> 3490                 self._set_prop(prop, value)
   3491 
   3492         # Handle non-scalar case

/dataquest/system/env/python3/src/plotly-master/packages/python/plotly/plotly/basedatatypes.py in _set_prop(self, prop, val)
   3775                 return
   3776             else:
-> 3777                 raise err
   3778 
   3779         # val is None

/dataquest/system/env/python3/src/plotly-master/packages/python/plotly/plotly/basedatatypes.py in _set_prop(self, prop, val)
   3770         validator = self._validators.get(prop)
   3771         try:
-> 3772             val = validator.validate_coerce(val)
   3773         except ValueError as err:
   3774             if self._skip_invalid:

/dataquest/system/env/python3/src/plotly-master/packages/python/plotly/_plotly_utils/basevalidators.py in validate_coerce(self, v)
    785             if self.has_min_max:
    786                 if not (self.min_val <= v <= self.max_val):
--> 787                     self.raise_invalid_val(v)
    788         return v
    789 

/dataquest/system/env/python3/src/plotly-master/packages/python/plotly/_plotly_utils/basevalidators.py in raise_invalid_val(self, v, inds)
    281                 typ=type_str(v),
    282                 v=repr(v),
--> 283                 valid_clr_desc=self.description(),
    284             )
    285         )

ValueError: 
    Invalid value of type 'numpy.float64' received for the 'bargap' property of layout
        Received value: -2.220446049250313e-16

    The 'bargap' property is a number and may be specified as:
      - An int or float in the interval [0, 1]

Despite this lengthy error, a plot is still produced:
Screenshot from 2021-09-27 12-14-22
However, since the bins are now (9-1)/9 units wide, the xlabels are a little off.

After much Googling and sifting through Stackoverflow posts, I came up with the following code:

houses['Overall Cond'].plot.hist(bins=np.arange(0.5, 10, 1))
plt.xticks(np.arange(10))
plt.show()

Which produces the following plot:
Screenshot from 2021-09-27 13-28-27

While I ultimately was able to produce what I was looking for, I’m wondering if there is a better way to do this or if there’s something I failed to understand when generating histograms for discrete values?

Any and all help/feedback are greatly welcomed!

BONUS QUESTION: According to the documentation, df.plot.hist()returns a matplotlib.AxesSubplot object whereas matplotlib.pyplot.hist() returns n, bins, and patches so that one can easily retrieve the values for each bin (n) and the bin edges (bins). Is there an easy way to retrieve this same data from the pandas version of hist()? IOW: how would one retrieve the bin edges of a histogram from an axe object?