Different image generated when creating bar plots in dataquest platform and local machine

Backing up previously asked question in our previous slack forum:

I got different result when I run the “Bar Plots and Scatter Plots/Creating bars” lesson code on my computer. The x-axis labels are on incorrect position. How can I position the labels of x-axis? I have matplotlib version 2.2.3

Mission link: https://www.dataquest.io/m/144/bar-plots-and-scatter-plots/4/creating-bars

Figure generated on dataquest:
dataquest-bars
Figure dataquest-bars.png

Figure generated by code below:


Figure-1.png matplotlib 2.2.3 bar position incorrect

Matplotlib version of dataquest virtualenv is 1.5.1 and the code below has matplotlib version 2.2.3.

import matplotlib.pyplot as plt
from numpy import arange
import pandas as pd
reviews = pd.read_csv('./data/fandango_scores.csv')
norm_reviews = reviews[['FILM', 'RT_user_norm', 'Metacritic_user_nom',
                        'IMDB_norm', 'Fandango_Ratingvalue',
                        'Fandango_Stars']]
num_cols = ['RT_user_norm', 'Metacritic_user_nom', 'IMDB_norm',
            'Fandango_Ratingvalue', 'Fandango_Stars']
def bar_1():
    bar_heights = norm_reviews[num_cols].iloc[0].values
    bar_positions = arange(5) + 0.75
    fig, ax = plt.subplots()
    ax.bar(bar_positions, bar_heights, 0.5)


if __name__ == '__main__':
    bar_1()
    plt.show()

Solution and discussion

Here is the documentation: https://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.xticks

Ways to debug:
You can use the plt.xticks() to figure out what are locations of xticks:

locs, labels = plt.xticks()
print(locs)

Both different version of matplotlib prints [0. 1. 2. 3. 4. 5. 6.] for locs.

The problem is not with the ticks’ labels but with the bars’ position.

Default setting:
The default behavior of ax.bar has changed since matplotlib 1.5.1.
That is, the default setting behavior may have changed since 1.5.1 and in 2.2.3.

I had to set the align=‘edge’ of the Axes.bar() method because the default is ‘center` in matplotlib version 2.2.3.

However, not setting align on dataquest’s virtualenv and using bar_positions = arange(5) + 0.75 will align the bars correctly because the Default setting is `align=“edge” in matplotlib version 1.5.1.

If you want to use default settings, then set the following:

bar_position = arange(5) + 1

Why? At position x=0, given the bar width is 0.5, position x=0 will be the center of the bar. Hence the edge of bar will be at -0.25. If you want the first bar’s edge to position at 0.75, then you have to account for the offset, that is 0.75 = -0.25 + offset. The offset is 1 (=0.75+0.25). You have to offset to the bar_position.

The code works for matplotlib version 2.1.2 and above.

Using align = center
For align = "center" (or default setting for ax.bar without any align parameter given), to position first bar’s edge at x=0.75:

offset = 1
bar_position = arange(5) + offset

ax.bar(bar_position, bar_heights, 0.5)
# or 
ax.bar(bar_position, bar_heights, 0.5, align="center")

where the offset indicates (-width/2 + first bar edge position (before offset) + offset = where we want the first bar edge to be at (which is 0.75).

At position x=0, given the bar width is 0.5, position x=0 will be the center of the bar. Hence the edge of bar will be at -0.25. If you want the first bar’s edge to position at 0.75, then you have to account for the offset, that is 0.75 = -0.25 + offset. The offset is 1 (=0.75+0.25). You have to offset to the bar_position.

Using align = edge
For align="edge", to position first bar’s edge at x=0.75:

offset = 0.75
bar_position = arange(5) + offset
ax.bar(bar_position, bar_heights, 0.5, align="edge")

To figure out matplotlib version:
If you have similar issues on aligning the plot, you can check your matplotlib version number and its respective documentation.

>>> import matplotlib
>>> matplotlib.__version__

I have a related question. My code for this exercise works in dataquest:

bar_heights = norm_reviews[num_cols].iloc[0].values
bar_positions = arange(5) + 0.75

fig, ax = plt.subplots()
ax.bar(bar_positions, bar_heights, 0.5)
plt.show()

But on my local jupyter (matplotlib version 2.2.3) I get the following error:


TypeError Traceback (most recent call last)
in ()
1 fig, ax = plt.subplots()
----> 2 ax.bar(bar_positions, bar_heights, 0.5)
3 plt.show()

~/anaconda3/lib/python3.7/site-packages/matplotlib/init.py in inner(ax, *args, **kwargs)
1865 “the Matplotlib list!)” % (label_namer, func.name),
1866 RuntimeWarning, stacklevel=2)
-> 1867 return func(ax, *args, **kwargs)
1868
1869 inner.doc = _add_data_doc(inner.doc,

~/anaconda3/lib/python3.7/site-packages/matplotlib/axes/_axes.py in bar(self, *args, **kwargs)
2281 edgecolor=e,
2282 linewidth=lw,
-> 2283 label=‘nolegend’,
2284 )
2285 r.update(kwargs)

~/anaconda3/lib/python3.7/site-packages/matplotlib/patches.py in init(self, xy, width, height, angle, **kwargs)
684 “”"
685
–> 686 Patch.init(self, **kwargs)
687
688 self._x0 = xy[0]

~/anaconda3/lib/python3.7/site-packages/matplotlib/patches.py in init(self, edgecolor, facecolor, color, linewidth, linestyle, antialiased, hatch, fill, capstyle, joinstyle, **kwargs)
93 self.set_fill(fill)
94 self.set_linestyle(linestyle)
—> 95 self.set_linewidth(linewidth)
96 self.set_antialiased(antialiased)
97 self.set_hatch(hatch)

~/anaconda3/lib/python3.7/site-packages/matplotlib/patches.py in set_linewidth(self, w)
360 w = mpl.rcParams[‘axes.linewidth’]
361
–> 362 self._linewidth = float(w)
363 # scale the dash pattern by the linewidth
364 offset, ls = self._us_dashes

TypeError: only size-1 arrays can be converted to Python scalars

I actually just caught my mistake - I put brackets around the code for bar_positions in jupyter. :woman_shrugging:t2: