0

Recently I posted this question about creating a border and controlling tick label locations. @ImportanceOfBeingErnest had a couple nice ways of controlling the border, but I was left with the tick label location issue.

I was able to track down the post I mentioned regarding using a transform to control tick label location padding (also explained by @ImportanceOfBeingErnest). I was able to implement this solution to change the tick label locations, but I have found an issue that I can't solve.

When the plot is initiated (using the desired tick label location) everything looks fine (see first fig below). But, as the data is updated (which is my application happens when a user adds a new data to a dataset), sometimes the tick label location remains properly places (i.e. with the specified padding), but sometimes it does not. Sometimes it is in the "default" (unpadded) location, sometimes it appears to be padded in the wrong direction, etc. It actually seems quite random. See additional figures below.

Below is a simple example of what I'm seeing in my full code. To keep it "minimal" I'm initializing a plot with no data and the first and last tick label adjust as desired, then updating a random set of points to the plot in a loop (4 times). As I mentioned, sometimes it's fine, sometimes it's not.

Any idea what is going on and how to address it to have the first and last tick label consistently padded inside the plot area so they don't get covered by the boarder?

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


def update_data(a):
    X = np.random.randint(low=-9, high=9, size=10)
    Y = np.random.randint(low=-9, high=9, size=10)
    ax.set(xlim=[np.floor(np.min(X) - 1), np.ceil(np.max(X) + 1)], ylim=[np.floor(np.min(Y) - 1), np.ceil(np.max(Y) + 1)])
    ax.scatter(X, Y, c="b", marker="o", s=40)


if __name__ == '__main__':
    plt.ion()

    fig, ax = plt.subplots()
    ax2 = fig.add_subplot(111)
    ax2.patch.set_visible(False)
    ax2.tick_params(left=False, bottom=False, labelleft=False, labelbottom=False)
    for _, sp in ax2.spines.items():
        sp.set_linewidth(3)

    ax.axis([-10, 10, -10, 10])
    ax.spines['left'].set_position('zero')
    ax.spines['bottom'].set_position('zero')
    ax.spines['top'].set_visible(False)
    ax.spines['right'].set_visible(False)

    plt.setp(ax.xaxis.get_majorticklabels()[0], ha='left')
    plt.setp(ax.xaxis.get_majorticklabels()[-1], ha='right')
    plt.setp(ax.yaxis.get_majorticklabels()[0], va='bottom')
    plt.setp(ax.yaxis.get_majorticklabels()[-1], va='top')
    delx = 5 / 72.
    dely = 5 / 72.
    offsetX = matplotlib.transforms.ScaledTranslation(delx, 0, fig.dpi_scale_trans)
    offsetY = matplotlib.transforms.ScaledTranslation(0, dely, fig.dpi_scale_trans)
    ax.xaxis.get_majorticklabels()[0].set_transform(ax.xaxis.get_majorticklabels()[0].get_transform() + offsetX)
    ax.xaxis.get_majorticklabels()[-1].set_transform(ax.xaxis.get_majorticklabels()[-1].get_transform() - offsetX)
    ax.yaxis.get_majorticklabels()[0].set_transform(ax.yaxis.get_majorticklabels()[0].get_transform() + offsetY)
    ax.yaxis.get_majorticklabels()[-1].set_transform(ax.yaxis.get_majorticklabels()[-1].get_transform() - offsetY)

    ax.grid(True)
    fig.set_tight_layout(True)

    ax.scatter([], [], c="b", marker="o", s=40)
    plt.show()
    plt.pause(3)

    for a in range(1, 4):
        update_data(a)
        plt.pause(3)
        plt.draw()

Intended Tick Locations Incorrect Tick Location 1 Incorrect Tick Location 2 Incorrect Tick Location 3

hbb
  • 33
  • 10
  • After updating the plot, the label that was initially the last, may not necessarily be the last one any more. Example: You have a graph ticked with 0,2,4,6. The fourth (last) label is shifted. Now you update the graph. It will show 0,5,10,15,20 as ticklabels. The fourth ticklabel has taken the value 15 - but it's not the last ticklabel any more. So 15 is shifted, but the new last label (20) is not. – ImportanceOfBeingErnest Dec 21 '18 at 11:22
  • 2
    What this means is that you probably need to reset all shifts each time you update the graph and then apply them again to the then new first/last labels. To do so you can connect a callback to the `xlim_changed` event, see e.g. [here](https://stackoverflow.com/questions/31490436/matplotlib-finding-out-xlim-and-ylim-after-zoom). – ImportanceOfBeingErnest Dec 21 '18 at 11:26
  • Perfect, but what is the easiest/correct/best way to reset all the shifts? I can't seem to find a way to set just the label location back to "default". Would just removing the labels and re-adding them work? Seems like there should be a "reset" call that I just can't find. – hbb Dec 21 '18 at 14:47
  • I think I would store the original transform somewhere, and reuse it later. – ImportanceOfBeingErnest Dec 21 '18 at 15:05

0 Answers0