2

I am attempting to plot some data using matplotlib and would like to reduce the number of DateTime x-axis ticks displayed. I was able to use plt.locator to reduce the number of bins by half but the datetime does not align with the bars. Is there a way I can remedy this? I would like to have only 5 of the 10 ticks displayed. Where for example only the following datetimes are displayed under their respective plotted bars (2017-09-29 02:00, 2017-09-29 04:00, 2017-09-29 06:00, 2017-09-29 08:00, 2017-09-29 10:00).

Below is my reproducible code and the plotted output.

import pandas as pd
import matplotlib.pyplot as plt

df = pd.DataFrame([{'DATETIME': '2017-09-29 01:00,', 'Population': 1000},
                   {'DATETIME': '2017-09-29 02:00,', 'Population': 3000},
                   {'DATETIME': '2017-09-29 03:00,', 'Population': 4000},
                   {'DATETIME': '2017-09-29 04:00,', 'Population': 5000},
                   {'DATETIME': '2017-09-29 05:00,', 'Population': 7000},
                   {'DATETIME': '2017-09-29 06:00,', 'Population': 6000},
                   {'DATETIME': '2017-09-29 07:00,', 'Population': 5000},
                   {'DATETIME': '2017-09-29 08:00,', 'Population': 4000},
                   {'DATETIME': '2017-09-29 09:00,', 'Population': 4000},
                   {'DATETIME': '2017-09-29 10:00,', 'Population': 4000}])

df.index = df['DATETIME']
df.index = (pd.to_datetime(df.index)).strftime("%m/%d %H:00")
df.Population.plot.bar()
plt.tick_params(axis='both', which='both', labelsize=7)
plt.locator_params(nbins=5)
plt.tight_layout()
plt.show()

enter image description here

MBasith
  • 1,407
  • 4
  • 29
  • 48

1 Answers1

4

Let me first explain why the method you chose setting nbins on the locator params fails, although in principle this method might be expected to do exactly what you want.
The bars in the plot are positionned at integer numeric locations 0,1,2,...N-1. Their labels are set as a fixed list of texts. Hence if you chose to only have 5 ticks, those ticks are correctly positionned, but the labels to those are taken to be the first 5 elements from the fixed label list. Therefore, the third bar has the label of the second, the fifth bar has the label of the third and so on.

Knowing this, we can play the trick of setting new ticks and ticklabels just at every second bar by slicing the current labels. You get the current tick positions and labels via plt.xticks(), which returns a tuple of ticks and labels. Slicing a list is easy via the :: operator,
e.g. [0,1,2,3,4,5][1::2] returns [1,3,5]. Hence:

plt.xticks(plt.xticks()[0][1::2], 
           plt.xticks()[1][1::2])

Complete example:

import pandas as pd
import matplotlib.pyplot as plt

df = pd.DataFrame([{'DATETIME': '2017-09-29 01:00,', 'Population': 1000},
                   {'DATETIME': '2017-09-29 02:00,', 'Population': 3000},
                   {'DATETIME': '2017-09-29 03:00,', 'Population': 4000},
                   {'DATETIME': '2017-09-29 04:00,', 'Population': 5000},
                   {'DATETIME': '2017-09-29 05:00,', 'Population': 7000},
                   {'DATETIME': '2017-09-29 06:00,', 'Population': 6000},
                   {'DATETIME': '2017-09-29 07:00,', 'Population': 5000},
                   {'DATETIME': '2017-09-29 08:00,', 'Population': 4000},
                   {'DATETIME': '2017-09-29 09:00,', 'Population': 4000},
                   {'DATETIME': '2017-09-29 10:00,', 'Population': 4000}])

df.index = df['DATETIME']
df.index = (pd.to_datetime(df.index)).strftime("%m/%d %H:00")
df.Population.plot.bar()
plt.tick_params(axis='both', which='both', labelsize=7)

plt.xticks(plt.xticks()[0][1::2], 
           plt.xticks()[1][1::2])

plt.tight_layout()
plt.show()

enter image description here

ImportanceOfBeingErnest
  • 321,279
  • 53
  • 665
  • 712
  • Thanks for the explanation. That makes a lot of sense now. The slicing method is very simple and precisely accomplished what I was looking for. – MBasith Oct 01 '17 at 22:29