1

I am trying to plot data from a Pandas dataframe that is created by importing data from a CSV. However in the plot not every label is displayed along the x-axis, the plot only shows 5 labels along the x-axis.

I have a total of 22 textbased labels, which are all supposed to be shown along the x-axis as tickmarks/labels. These labels correspond to the entries in the column in the dataframe with the name Category.

For each Line in the Line column of the dataframe a separate line in the plot is created. And the Amount columns in the dataframe contains the y-values.

I am sure there is a easy tweak for this, trying ax.set_xticks(np.arange(len(21)) and plt.xticks( arange(21) ) did not function, maybe because the labels are textbased, not numbers?

EDIT 2

I had some trouble with the initial code after changing computer with another software setup. Now I got another version of the code and CSV that I got to run without problems that actually plots a graph. Now back to the initial problem, as can be seen from the attached picture only a few of the categories (gts, jma, yja, lre, fgg) are displayed as labels along the x-axis (I want all 22 categories to be displayed along the x-axis in full text): Image of the plot that does not display all the categories as x-labels along the x-axis

Here is the code that I used for plotting that doesn't display all x-labels:

import pandas as pd
import matplotlib.pyplot as plt

df=pd.read_csv("import.csv", 
                   names=["Category", "Line", "Amount"], encoding="iso-8859-1")

fig, ax = plt.subplots(1,1);
df.groupby("Category").plot(x="Line", y="Amount", ax=ax)

plt.legend([v[0] for v in df.groupby('Category')['Category']], bbox_to_anchor=(1.1, 0.5)) 
plt.xlabel('Category')
plt.ylabel('Amount')

for line in ax.lines:
    line.set_linewidth(0.5)

The CSV contents look as follows, I didn't post the whole file as there are many lines. I believe this should be enough to reproduce the problem (of course I can put more if the plot doesn't work without). The first column is the Line-column, the second column corresponds to the Category-column and the third column corresponds to the Amount-column:

jabber,gts,1
jabber,aed,6
jabber,ame,2
jabber,asy,8
jabber,fxk,1
jabber,jma,6
jabber,oaw,2
jabber,ejt,8
jabber,qat,1
jabber,dzj,6
jabber,yja,2
jabber,ajz,8
jabber,jbp,1
jabber,bvi,6
jabber,pec,2
jabber,lre,8
jabber,wlx,1
jabber,hpw,6
jabber,spg,2
jabber,bdg,8
jabber,fgg,1
jabber,fgz,5
soshy,gts,6
soshy,aed,2
soshy,ame,8
soshy,asy,1
soshy,fxk,6
soshy,jma,2
soshy,oaw,8
soshy,ejt,1
soshy,qat,6
soshy,dzj,2
soshy,yja,8
soshy,ajz,1
soshy,jbp,6
soshy,bvi,2
soshy,pec,8
soshy,lre,1
soshy,wlx,6
soshy,hpw,2
soshy,spg,8
soshy,bdg,1
soshy,fgg,6
soshy,fgz,2
  • Yes, possibly. See [mcve] and update your question with one if you want help here. – ImportanceOfBeingErnest Mar 08 '18 at 19:28
  • Since there is only `YearA` in the data, it will produce only a single label, that is expected. Maybe my comment wasn't clear enough, in that case see [How to make good reproducible pandas examples](https://stackoverflow.com/questions/20109391/how-to-make-good-reproducible-pandas-examples). – ImportanceOfBeingErnest Mar 08 '18 at 20:30
  • I added CSV-data for one more year. I thought that one year was enough to reproduce the problem and at the same satisfying a "minimal-example". For each year a new line/graph in the plot-window is created (the years are not the x-labels). The x-labels are given by the Category-column which is the middle column, and in the CSV-data there is at least one row for each category. – BoroBorooooooooooooooooooooooo Mar 08 '18 at 20:45
  • The plot looks like [this](https://i.stack.imgur.com/fuzGW.png). It's pretty unclear what you are actually asking seeing the result. – ImportanceOfBeingErnest Mar 08 '18 at 20:49

1 Answers1

1

You are looking for xticks, Matplotlib automagicly picks the xticks that will be displayed to keep things simple and nice looking. This works fine when you are dealing with time series or numeric x axis's. But not so well in your case.

What you need to do is find out what the co-ordinates at the begining and end of the plot are and use those numbers to manually position your x-ticks. You can get this info by calling plt.xticks(). Which gives you a numpy array of (cordinates, xtick labels)

>>> plt.xticks()
(array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16,
         17, 18, 19, 20, 21]), <a list of 22 Text xticklabel objects>)

Here is a link to the matplotlib docs. matplotlib.pyplot.xticks enter image description here

Here is the code

import pandas as pd
import matplotlib.pyplot as plt
plt.ion() # turn on interactive plotting for ipython
# I stuck your data in a list
data = [
    ['jabber', 'gts', 1], ['jabber', 'aed', 6], ['jabber', 'ame', 2], ['jabber', 'asy', 8],
    ['jabber', 'fxk', 1], ['jabber', 'jma', 6], ['jabber', 'oaw', 2], ['jabber', 'ejt', 8],
    ['jabber', 'qat', 1], ['jabber', 'dzj', 6], ['jabber', 'yja', 2], ['jabber', 'ajz', 8],
    ['jabber', 'jbp', 1], ['jabber', 'bvi', 6], ['jabber', 'pec', 2], ['jabber', 'lre', 8],
    ['jabber', 'wlx', 1], ['jabber', 'hpw', 6], ['jabber', 'spg', 2], ['jabber', 'bdg', 8],
    ['jabber', 'fgg', 1], ['jabber', 'fgz', 5], ['soshy', 'gts', 6], ['soshy', 'aed', 2],
    ['soshy', 'ame', 8], ['soshy', 'asy', 1], ['soshy', 'fxk', 6], ['soshy', 'jma', 2],
    ['soshy', 'oaw', 8], ['soshy', 'ejt', 1], ['soshy', 'qat', 6], ['soshy', 'dzj', 2],
    ['soshy', 'yja', 8], ['soshy', 'ajz', 1], ['soshy', 'jbp', 6], ['soshy', 'bvi', 2],
    ['soshy', 'pec', 8], ['soshy', 'lre', 1], ['soshy', 'wlx', 6], ['soshy', 'hpw', 2],
    ['soshy', 'spg', 8], ['soshy', 'bdg', 1], ['soshy', 'fgg', 6], ['soshy', 'fgz', 2]]

df = pd.DataFrame(data, columns=["Category", "Line", "Amount"])
fig, ax = plt.subplots(1, 1)
df.groupby("Category").plot(x="Line", y="Amount", ax=ax)
plt.legend([v[0] for v in df.groupby('Category')['Category']], bbox_to_anchor=(1.1, 0.5))

# get the values we want displayed as tick labels
tick_labels = tuple(df['Line'])
# get the positions for the maximum xtick label
x_max = int(max(plt.xticks()[0]))  # int() to convert numpy.int32 => int
# manually set you xtick labels
plt.xticks(range(0, x_max + 1), tick_labels, rotation=45) 

plt.xlabel('Category')
plt.ylabel('Amount')
# change the limits and padding of the figure
plt.figure(1).subplots_adjust(
    **dict(left=0.1, right=.8, bottom=.15, top=.9, wspace=.1, hspace=.1))
for line in ax.lines:
    line.set_linewidth(0.5)

plt.plot()    # might need this without ipython
bigjake
  • 149
  • 11
  • I can't comment everywhere yet or I would comment on your question. I've only got python 3.6 right now(which this works with), not sure what you were using. – bigjake Mar 09 '18 at 01:03
  • This is fantastic, thank you very much! On my side/setup I had to change `plt.xticks(range(0, x_max), tick_labels, rotation=45)` to `plt.xticks(range(0, x_max+1), tick_labels, rotation=45)` in order to get the last x-label on the right hand side of the plot. IMO you commented/documented very well each step in your code – BoroBorooooooooooooooooooooooo Mar 09 '18 at 09:54
  • No prop, glad it worked for you, yeah, forgot the +1, i'll edit it. – bigjake Mar 09 '18 at 23:18