2

I'm having some issues in using imshow() from matplotlib, in specific with creating a pdf from it.

I'm dealing with a 500x500 matrix which, for the sake of this question, will be just random values:

np.random.seed(1)
arr = np.array(np.random.random((500, 500)))

The rows and columns are all labelled with different names, but for the sake of this question, let's just make them simple:

labels = ["Big_Label" if x % 2 == 0 else "Bigger_Big_Label" for x in range(500)]  

So, I have the following code to plot that matrix:

plt.rc('figure', figsize=(5,5), dpi=500)
fig = plt.figure()
ax = fig.add_subplot(111)
im = ax.imshow(arr)

# defining the same labels for rows and columns
ax.set_xticklabels([''] + labels)
ax.set_yticklabels([''] + labels)
# showing the labels for all the ticks
ax.xaxis.set_major_locator(ticker.MultipleLocator(1))
ax.yaxis.set_major_locator(ticker.MultipleLocator(1))
# personalising the ticks. In particular, labels on top
ax.tick_params(axis='both', which='both', labelsize=0.5, length=0)
ax.tick_params(axis='x',which='both', labelbottom='off', labeltop='on')
ax.tick_params(axis='both', pad=1)
# vertical labels
for label in im.axes.xaxis.get_ticklabels():
    label.set_rotation(90)

plt.colorbar(im)
plt.title("Just a Big Title With Words")

# Removing outer lines because they hide part of the lines/columns
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.spines['bottom'].set_visible(False)
ax.spines['left'].set_visible(False)

plt.savefig("fig.pdf")
plt.show() 

The first issue is with the title because is on top of the xlabels:

enter image description here

The second issue is, when zooming to see the ylabels and xlabels, they are not aligned. With regards the left labels, they have varying spaces between them and the plot, when I specifically coded ax.tick_params(axis='both', pad=1); if I execute this python code in an IDE or in terminal, this issue doesn't happen (they are all close to the plot). So I guess something is going on when putting this image into a pdf?. With regards with both labels, you can see they are not aligned with the actual rows and columns; for example, the second label on the top is in middle of the blue and orange square, when it should be aligned with the middle of the orange square:

enter image description here

Finally, I tried to call fig.autofmt_xdate() just before plt.savefig(), but the result is even worse, as the top labels are just completely not aligned:

enter image description here

Can you help me solving this issues? I know you have to do a big zoom to see labels, but for the real matrices that I have that is necessary. I also inform that I'm using matplotlib 1.5; I can't use 2.x because of a compatibility issue with another tool

tjiagoM
  • 448
  • 2
  • 10
  • 23
  • Can you try `plt.tight_layout()` please? –  Dec 08 '17 at 16:26
  • 1
    I called that method immediately before `plt.savefig("fig.pdf")` The result is here: https://imgur.com/a/yK0Th The result is even more strange because the colours of the squares changed (I use the same seed everytime, so the squares' colours shouldn't change), and the alignment problem persists – tjiagoM Dec 08 '17 at 16:31
  • @ImportanceOfBeingErnest I am sorry, you are right. It was a mistake I forgot to correct. I edited my question accordingly – tjiagoM Dec 08 '17 at 16:40
  • 1
    Fort moving the title see https://stackoverflow.com/questions/12750355/python-matplotlib-figure-title-overlaps-axes-label-when-using-twiny – ImportanceOfBeingErnest Dec 08 '17 at 16:46
  • Also because you specify `length=0` there should not be any ticks in the plot at all. Can you please verify? – ImportanceOfBeingErnest Dec 08 '17 at 16:47
  • Thanks for the answer to the tile, it solved my issue, although I thought matplotlib would have some automatic methods to not overlap the title with the plot. In this way I have to manually see what's the best distance – tjiagoM Dec 08 '17 at 16:55
  • About the length, I guess you are right, even looking to the docs: https://matplotlib.org/1.5.3/api/axes_api.html#matplotlib.axes.Axes.tick_params If I define (for example) a length of 1, the ticks will be so big that they will hide some of the squares. I don't know why some (what I guess are) ticks are appearing. With or without a length, the labels are still not aligned with the squares in the plot – tjiagoM Dec 08 '17 at 16:57
  • The issue with the ticks still appearing is with the `width` parameter. If I pass the argument `width=0`, no more ticks (labels still not aligned) – tjiagoM Dec 08 '17 at 16:58
  • I think many of those problems would disappear if you changed your figure size and dpi by a factor of e.g. 5 respecively, `figsize=(25,25), dpi=100`. – ImportanceOfBeingErnest Dec 08 '17 at 17:35
  • I don't think that solves the problem. I tried that and, as you can see [here](https://imgur.com/a/wnwxC), they are still not aligned. However, I notice that the squares' colours itself are changed... If I try a figsize of `(10,10)` they will be different as well. I should only have 500x500 little squares, so I'm a bit confused on what `figsize` actually does... – tjiagoM Dec 08 '17 at 17:50
  • I could reproduce the issue of misaligned labels in matplotlib 2.1. But that was solved once I used `figsize=(25,25), dpi=100`, so I thought it would be the same in matplotlib 1.5. I fear a bit that solving this will be much harder than maybe solving the compatibility issue which prevents you from upgrading matplotlib. – ImportanceOfBeingErnest Dec 08 '17 at 22:02
  • 1
    I submitted [an issue](https://github.com/matplotlib/matplotlib/issues/9963) about the part of the problem which I can reproduce. For the rest I fear that if it is only present with matplotlib 1.5 there is little one can do. – ImportanceOfBeingErnest Dec 08 '17 at 23:34
  • @ImportanceOfBeingErnest many thanks for that! I still don't get why different figsize produce different squares. I should have 500x500 squares no matter the resolution, right? From what I saw from documentation, `figsize` is about inches, so shouldn't make a difference in the amount of squares inside, no? – tjiagoM Dec 09 '17 at 16:52
  • @ImportanceOfBeingErnest I tried a figsize of (1,1) with dpi of 50. So, If my plot is 1x1 inch, with 50 dots per inch, I was expecting 50x50 squares, which doesn't happen... I maybe create a question with this, because it seems counter intuitive... – tjiagoM Dec 09 '17 at 16:59
  • The issue about squares is actually not very clear to me. Do you get less than 500x500 squares? In principle you are absolutely right, the figure size would just provide more space, such that the same plot takes up more space. Since I cannot reproduce this (I always see 500 time 500 nearly squared patches with matplotlib 2.1), it is hard to say what could be going on. Figure size and dpi will only in thus far change the number of squares if you go below the resolution limit. – ImportanceOfBeingErnest Dec 09 '17 at 17:01
  • Thanks for the interest, in the meantime I found the solution, I just disable interpolation: `imshow(arr, interpolation='none')` and it seems I have always 500x500 squares :) (when trying a low figsize and resolution that's obvious, because without that interpolation parameter I have around 70x70 squares; with the `interpolation=none` parameter I now have much more squares (thus 500x500). I will try with a lower matrix anyway to doublecheck – tjiagoM Dec 09 '17 at 17:04
  • Oh, I forgot that the `interpolation` default is different in older matplotlib versions. Sure, that makes sense. – ImportanceOfBeingErnest Dec 09 '17 at 17:19

1 Answers1

1

There is a PR for automatically moving the title. Should be included in v2.2 (Feb timeframe) https://github.com/matplotlib/matplotlib/pull/9498, and another for the title padding https://github.com/matplotlib/matplotlib/pull/9816. So we are working on it.

As for your label misalignment in PDF, it looks like there is a bug in label alignment if labelsize is less than 1.0, so don't do that: https://github.com/matplotlib/matplotlib/issues/9963 Its a bug, but I would imagine a low-priority one.

Jody Klymak
  • 4,979
  • 2
  • 15
  • 31