Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

matplotlib naming the tick marks on x axis 1, 2, 4, 8, 16, etc

Using the same code from a previous question, this sample generates the graph below:

import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt

data = (0, 1890,865, 236, 6, 1, 2, 0 , 0, 0, 0 ,0 ,0 ,0, 0, 0)
ind = range(len(data))
width = 0.9   # the width of the bars: can also be len(x) sequence

p1 = plt.bar(ind, data, width)
plt.xlabel('Duration 2^x')
plt.ylabel('Count')
plt.title('DBFSwrite')
plt.axis([0, len(data), -1, max(data)])

ax = plt.gca()

ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)
ax.spines['left'].set_visible(False)
ax.spines['bottom'].set_visible(False)

plt.savefig('myfig')

Sample output

Instead of the tick labels being 0, 2, 4, 6, 8...I would rather have them be labeled at every mark, and proceed with the value of 2^x: 1, 2, 4, 8, 16, etc. How can I do that? And then even better, could I have the label centered under the bar, instead of at the left edge?

like image 836
monty0 Avatar asked Oct 15 '25 07:10

monty0


1 Answers

One way of achieving this is to make use of a Locator and a Formatter. This makes it possible to use the plot interactively without "losing" tickmarks. In this case I'd recommend MultipleLocator and FuncFormatter as seen in example below.

import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
from matplotlib.ticker import MultipleLocator, FuncFormatter

data = (0, 1890,865, 236, 6, 1, 2, 0 , 0, 0, 0 ,0 ,0 ,0, 0, 0)
ind = range(len(data))
width = 0.9   # the width of the bars: can also be len(x) sequence

# Add `aling='center'` to center bars on ticks
p1 = plt.bar(ind, data, width, align='center')
plt.xlabel('Duration 2^x')
plt.ylabel('Count')
plt.title('DBFSwrite')
plt.axis([0, len(data), -1, max(data)])

ax = plt.gca()

# Place tickmarks at every multiple of 1, i.e. at any integer
ax.xaxis.set_major_locator(MultipleLocator(1))
# Format the ticklabel to be 2 raised to the power of `x`
ax.xaxis.set_major_formatter(FuncFormatter(lambda x, pos: int(2**x)))
# Make the axis labels rotated for easier reading
plt.gcf().autofmt_xdate()

ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)
ax.spines['left'].set_visible(False)
ax.spines['bottom'].set_visible(False)

plt.savefig('myfig')

enter image description here

like image 171
sodd Avatar answered Oct 16 '25 20:10

sodd