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:
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:
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.
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.
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.
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()
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()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With