0

I have code (code follows), which uses matplotlib and numpy to create a diagram. I have the following requirements for my plot:

  1. I want the axes to have integer ticks.
  2. The axes ticks shall not have trailing zeros, so for example there should not be any 1.0 or 2.0, but instead 1 and 2.
  3. The ticks for x=0 and y=0 shall be hidden (the origin ticks).

I've achieved this with this code:

import numpy
import matplotlib.pyplot as plt
import matplotlib as mp
from matplotlib.ticker import FormatStrFormatter

# approximately a circle
x1 = [0.3, 1.0, 1.3, 1.3, 1.0, 0.3, -0.3, -1.0, -1.3, -1.3, -1.0, -0.3]
y1 = [1.7, 1.2, 0.6, -0.2, -1.2, -1.5, -1.5, -1.2, -0.2, 0.6, 1.2, 1.7]

number_of_values = 12
x2 = numpy.random.uniform(low=-1.0, high=1.0, size=number_of_values)
y2 = numpy.random.uniform(low=-1.0, high=1.0, size=number_of_values)


fig = plt.figure()
ax = fig.add_subplot(111)

ax.scatter(x1, y1, s=100, color='#FF0000', linewidth='1.5', marker='x', label='$y=1$')
ax.scatter(x2, y2, s=100, facecolors='none', edgecolors='#66AAAA', linewidth='1.5', marker='o', label='$y=0$')

ax.legend(loc='upper right')
ax.grid(True)

# LIMITS
x_lower_limit = min(x1) - 0.2 * max(x1)
x_upper_limit = 1.2 * max(x1)
ax.set_xlim(-2.0, 2.0)

y_lower_limit = min(y1) - 0.2 * max(y1)
y_upper_limit = 1.2 * max(y1)
ax.set_ylim(-2.0, 2.0)

# ORIGIN AXIS
ax.spines['left'].set_position('center')
ax.spines['right'].set_color('none')
ax.spines['bottom'].set_position('center')
ax.spines['top'].set_color('none')

ax.spines['left'].set_smart_bounds(True)
ax.spines['bottom'].set_smart_bounds(True)

ax.xaxis.set_ticks_position('bottom')
ax.yaxis.set_ticks_position('left')

ax.set_xlabel('$x_1$', fontsize=14)#, x=0.9, y=1, labelpad=0.6)
ax.set_ylabel('$x_2$', fontsize=14, rotation=0)#, x=1, y=0.9, labelpad=0.6)

ax.xaxis.set_label_coords(1.04, 0.5)
ax.yaxis.set_label_coords(0.5, 1.02)

ax.set_xticks([-2.0, -1.0, 1.0, 2.0])
ax.set_yticks([-2.0, -1.0, 1.0, 2.0])

plt.title('Non-linear Decision Boundary', y=1.06)

plt.show()

However, as you can see, I am hardcoding the ticks there - bad practice. I'd like to improve upon this way of doing it. I've tried other methods so far, namely the following SO post's solutions:

trimming trailing xtick zeros

The problem here is, that it actually doesn't even work. When I remove the hardcoded ax.set_xticks([-2.0, -1.0, 1.0, 2.0]) and ax.set_yticks([-2.0, -1.0, 1.0, 2.0]), this makes the plot show 0.5 steps in the ticks and they have trailing zeros.

modify tick labels text

The problem with this is, that if I change the tick label to something like ' ', it'll still interpret that as 0.0 and render the trailing zeros and non integer values.

How can I circumvent hardcoding the values of the tick labels? I'd like to set some frequency, something like this:

ax.xaxis.set_ticks_frequency(1.0)
ax.xaxis.set_ticks_formatter(something with integer values only)

This would also avoid iterating over all tick labels. If need be, iterating over the tick labels would be a necessary evil, but I think there should be a way without such iteration.

Community
  • 1
  • 1
Zelphir Kaltstahl
  • 5,722
  • 10
  • 57
  • 86

1 Answers1

0

You could replace the hard-coded ticks:

ax.set_xticks([-2.0, -1.0, 1.0, 2.0])
ax.set_yticks([-2.0, -1.0, 1.0, 2.0])

with a MultipleLocator with a step size 1 and a custom FuncFormatter (to omit zeros):

import matplotlib.ticker as ticker
loc = ticker.MultipleLocator(1)
ax.xaxis.set_major_locator(loc)
ax.yaxis.set_major_locator(loc)
def fmt(x, pos):
    return '' if x == 0 else '{:.0f}'.format(x)
ax.xaxis.set_major_formatter(ticker.FuncFormatter(fmt))
ax.yaxis.set_major_formatter(ticker.FuncFormatter(fmt))

enter image description here

unutbu
  • 842,883
  • 184
  • 1,785
  • 1,677