Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Matplotlib: Move ticklabels between ticks

Tags:

I want to create a visualization of a confusion matrix using matplotlib. Parameters to the methods shown below are the class labels (alphabet), the classification results as a list of lists (conf_arr) and an output filename. I am pretty happy with the result so far, with one last problem:

I am not able to center the axis tick labels between the gridlines. If I pass the extent parameter to the imshow method as below, the grid is aligned as I would like it to be. If I comment it out, the grid is missaligned but the labels are were I would like them to be. I think I need a way to move the ticklabel between the associated tick and the next tick but I do not know if and how this is possible.

To summarize, I want the grid/ticks like in the left image, but the ticklabels positioned like in the right image:

enter image description here

def create_confusion_matrix(alphabet, conf_arr, outputname):     norm_conf = []     width = len(conf_arr)     height = len(conf_arr[0])     for i in conf_arr:         a = 0         tmp_arr = []         a = sum(i, 0)         for j in i:             tmp_arr.append(float(j)/float(a))         norm_conf.append(tmp_arr)      fig = plt.figure(figsize=(14,14))     #fig = plt.figure()     plt.clf()     ax = fig.add_subplot(111)     ax.set_aspect(1)     ax.grid(which='major')     res = ax.imshow(np.array(norm_conf), cmap=plt.cm.binary,                      interpolation='none', aspect='1', vmax=1,                     ##Commenting out this line sets labels correctly,                     ##but the grid is off                     extent=[0, width, height, 0]                     )     divider = make_axes_locatable(ax)     cax = divider.append_axes("right", size="5%", pad=0.2)     cb = fig.colorbar(res, cax=cax)      #Axes     ax.set_xticks(range(width))     ax.set_xticklabels(alphabet, rotation='vertical')     ax.xaxis.labelpad = 0.5     ax.set_yticks(range(height))     ax.set_yticklabels(alphabet, rotation='horizontal')     #plt.tight_layout()     plt.savefig(outputname, format='png') 

The produced image looks like this: enter image description here

like image 829
feob Avatar asked Jun 12 '14 17:06

feob


People also ask

How do I change the spacing between ticks in MatPlotLib?

MatPlotLib with Python Create a figure and add a set of subplots. To set the ticks on a fixed position, create two lists with some values. Use set_yticks and set_xticks methods to set the ticks on the axes. To display the figure, use show() method.

How do I rotate Xticks in MatPlotLib?

To rotate tick labels in a subplot, we can use set_xticklabels() or set_yticklabels() with rotation argument in the method. Create a list of numbers (x) that can be used to tick the axes. Get the axis using subplot() that helps to add a subplot to the current figure.

How do I center a tick label in MatPlotLib?

However there is no direct way to center the labels between ticks. To fake this behavior, one can place a label on the minor ticks in between the major ticks, and hide the major tick labels and minor ticks. Here is an example that labels the months, centered between the ticks.


1 Answers

As you've noticed, they're centered by default and you're overriding the default behavior by specifying extent=[0, width, height, 0].

There are a number of ways to handle this. One is to use pcolor and set the edgecolors and linestyles to look like the gridlines (you actually need pcolor and not pcolormesh for this to work). However, you'll have to change the extents to get the ticks in the center as imshow does by default.

import matplotlib.pyplot as plt import numpy as np  data = np.random.random((10,10)) labels = 'abcdefghij'  fig, ax = plt.subplots() im = ax.pcolor(data, cmap='gray', edgecolor='black', linestyle=':', lw=1) fig.colorbar(im)  # Shift ticks to be at 0.5, 1.5, etc for axis in [ax.xaxis, ax.yaxis]:     axis.set(ticks=np.arange(0.5, len(labels)), ticklabels=labels)  plt.show() 

enter image description here

Alternatively, you could turn on the minor grid and place it at the pixel boundaries. Because you want fixed labels, we'll just set everything manually. Otherwise, a MultipleLocator would make more sense:

import matplotlib.pyplot as plt import numpy as np  data = np.random.random((10,10)) labels = 'abcdefghij'  fig, ax = plt.subplots() im = ax.imshow(data, cmap='gray', interpolation='none') fig.colorbar(im)  # Set the major ticks at the centers and minor tick at the edges locs = np.arange(len(labels)) for axis in [ax.xaxis, ax.yaxis]:     axis.set_ticks(locs + 0.5, minor=True)     axis.set(ticks=locs, ticklabels=labels)  # Turn on the grid for the minor ticks ax.grid(True, which='minor')  plt.show() 

enter image description here

like image 78
Joe Kington Avatar answered Sep 18 '22 19:09

Joe Kington