2

Some times when a plot is zoomed in enough the axis change so showing something like this

enter image description here

which means that the x value is, in this case 1.565 + the value showed in the tick.

Is there a way to set the axis ticks in this format? And once there how can I set the offset (The 1.565 in this case) and format the ticks?

Alex
  • 55
  • 1
  • 5
  • So you would start with an `offset` and a `list_of_ticks` and want to show it in the way as in the picture? – ImportanceOfBeingErnest Nov 20 '18 at 16:03
  • @ImportanceOfBeingErnest yes, concretely what I want is to center the axes at `pi/2` and then set the ticks at `[..., pi/2 -0.02, pi/2 - 0.01, pi/2, pi/2 + 0.01, ...]`, so that it shows `[..., -0.02, - 0.01, 0, 0.01, ...]` and the `offset = pi/2` – Alex Nov 20 '18 at 16:11

1 Answers1

2

A. Manually placing the offset

I think the easiest solution is to plot x-offset, instead of x itself. Then just add a text field with the offset below the axes.

import numpy as np
import matplotlib.pyplot as plt

x = np.array([-0.02+np.pi/2, +0.02+np.pi/2])
y = [1,1]

plt.plot(x - np.pi/2, y)
plt.text(1, -0.07, "$+\pi / 2$", ha="right", va="top",
         transform=plt.gca().transAxes)

plt.show()

enter image description here

B. Using a fixed formatter

Alternatively you can use a FixedFormatter and set its offset label manually.

import numpy as np
import matplotlib.pyplot as plt

x = np.array([-0.02+np.pi/2, +0.02+np.pi/2])
y = [1,1]

plt.plot(x, y)

xticks = np.array([-0.02, -0.01, 0, 0.01, 0.02])

plt.gca().set(xticks = xticks + np.pi/2, 
              xticklabels = xticks)
plt.gca().xaxis.get_major_formatter().set_offset_string("$+\pi / 2$")

plt.show()

enter image description here

The drawback of this is that the tick positions are fixed so you loose the nice labeling when zooming.

C. Using a custom locator and formatter with a fixed offset

This is possible but utterly complicated. The solution would look similar to Set scientific notation with fixed exponent and significant digits for multiple subplots but needs to use a Locator as well.

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.ticker

class OffsetLocator(matplotlib.ticker.AutoLocator):
    def __init__(self, offset=0):
        self.fixed_offset = offset
        matplotlib.ticker.AutoLocator.__init__(self)
    def tick_values(self, vmin, vmax):
        v = np.array([vmin,vmax])-self.fixed_offset
        ticks = matplotlib.ticker.AutoLocator.tick_values(self, *v)
        return ticks + self.fixed_offset

class OffsetFormatter(matplotlib.ticker.ScalarFormatter):
    def __init__(self, offset=0, offsettext = None, mathText=True):
        self.fixed_offset = offset
        self.offset_text = offsettext
        matplotlib.ticker.ScalarFormatter.__init__(self,useOffset=offset,
                                                   useMathText=mathText)
    def _set_orderOfMagnitude(self, nothing):
        self.orderOfMagnitude = 0
    def _compute_offset(self):
        return self.fixed_offset
    def get_offset(self):
        return self.offset_text or matplotlib.ticker.ScalarFormatter.get_offset(self)
   

x = np.array([-0.02+np.pi/2, +0.02+np.pi/2])
y = [1,1]

plt.plot(x, y)

plt.gca().xaxis.set_major_locator(OffsetLocator(np.pi/2))
plt.gca().xaxis.set_major_formatter(OffsetFormatter(np.pi/2, offsettext="$+\pi / 2$"))

plt.show()

enter image description here

The result looks similar to the above, but behaves completely natural like in all other cases where some offset is used. One will probably observe the differences only when playing with figure size, zooming and panning etc.

Community
  • 1
  • 1
ImportanceOfBeingErnest
  • 321,279
  • 53
  • 665
  • 712