Python Forum

Full Version: How to make x-axis readable with matplotlib
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
I've had this problem before. I'll have dates in a df column and plotting one year with 256 dates results in a black blur on the bottom.

Now... I wound up with this after searching the Net, finding a number of different pages, and incorporating some different ones:

fig, ax = plt.subplots()
ax.plot(btstats['Date'], btstats['Cum.PnL'])
ax.set_xlabel('Date')
ax.set_ylabel('Cumulative PnL')
date_form = DateFormatter("%b")
ax.xaxis.set_major_formatter(date_form)
#months = mdates.MonthLocator()
ax.xaxis.set_major_locator(mdates.MonthLocator(interval = 1))
#ax.set_xticklabels(ax.get_xticks(), rotation = 90)
plt.tight_layout()
plt.show()
It now plots just 3-letter abbreviations for each month but the labels don't line up right with the data. The last label shown is Sep whereas the data go through the end of Dec. Why might that be?

And in general, I don't like this solution because at the top, I ended up with:

import matplotlib.pyplot as plt
import matplotlib.dates as mdates
from matplotlib.dates import DateFormatter
I had to import three different packages for this? Seems like often when I find a plt solution that solves one problem, I have to import something different. That's frustrating because when I learned plt, it was said to be a highly effective, efficient library, etc.

Any input is appreciated!
One package. pyplot and dates are modules in matplotlib. DateFormatter is a class.

It is poor presentation to have 256 labels on a graph. Pyplot is giving bad results because your request is unreasonable. I don't know the frequency of your data, but you should consider only labelling the start of each year. Your plot should have 8 axis labels, not 256.

It is common for plots to not label the start of rend of the plot. Without seeing the data I cannot tell you exactly why the last point is not labeled.
Life is a journey, you don’t care about the destination, you care about the scenery along the way and the mood of seeing the scenery.
Others laughed at me as crazy, I laughed at others and couldn't see through.
on the thought of his buddy zhuge qing, zhang chulan and feng baobao came to resolve the case with the help of "anywhere" business enterprise. how does zhang chulan display his competencies to assist the king trap the black hand backstage? what wonderful overall performance will zhuge qing, wang ye and others have? who're the people who covet the "8 wonders"? "under one guy-becoming a member of the world" may be introducedsoon!

what is a sponsored ad
I played around with the "too many labels" problem,
causing them to be untidy, or unreadable.
The solution is of course, less labels. The rotation "vertical" option helps. Smaller font also.
I ended up with a python/matplotlib solution that allows
to print only "every x-th" label from a vector of labels.
For evry 12-th observation the format looks like this:
lbls[::12]
Paul
I should have clarified... I don't need 256 dates on the x-axis. This normally happens when I have a dataframe with all cells filled in. One column is date and one column is some dependent variable. I would like a way to tell Python to only print the dates every x rows or beginning of every month, or maybe Y dates for the whole graph (divided accordingly), etc. Any of these could be fine.

My frustration is in not knowing a single approach to plt that will accommodate most of the frequent things I will need to do. This is how my data usually is: a frequency of dates and dependent variable(s) for each date. The data can go on for months to years and I may want to plot it all--but I certainly don't need all the dates printed.

One thing I do need, though, is for a date label to line up vertically with the y-value being plotted. My ideal solution here will not use an additional Class or anything not in the stock package because I can't believe this is anything too complicated that the stock package shouldn't be able to handle. I suspect that's what causing this problem.
(Mar-01-2022, 07:54 AM)DPaul Wrote: [ -> ]I played around with the "too many labels" problem,
causing them to be untidy, or unreadable.
The solution is of course, less labels. The rotation "vertical" option helps. Smaller font also.
I ended up with a python/matplotlib solution that allows
to print only "every x-th" label from a vector of labels.
For evry 12-th observation the format looks like this:
lbls[::12]
Paul

I tried this:

ax.plot(btstats['Date'::7], btstats['Cum.PnL'])
The result is: TypeError: cannot do slice indexing on Int64Index with these indexers [Cum.PnL] of type str
This is much better:

datetimes = pd.to_datetime(btstats['Date'])
btstats['Date'] = datetimes

fig, ax = plt.subplots()
ax.plot(btstats['Date'], btstats['Cum.PnL'])
ax.set_xlabel('Date')
ax.set_ylabel('Cumulative PnL')
The 'Date' column was type object. Converting to datetime lets matplotlib automatically scale it and it now prints just every two months, which is fine. I could probably customize that somehow... I'll try and figure that out but if not then this is readable and clean.

The dates also line up with the data, now, and it plots through the last date in the dataframe.
Quote:I tried this:

ax.plot(btstats['Date'::7], btstats['Cum.PnL'])
The result is: TypeError: cannot do slice indexing on Int64Index with these indexers [Cum.PnL] of type str

I said it works on a vector of labels, not a single string. Cool
Paul