Description
Bug report
As has been previously reported, imshow misaligns grid lines and image data. This gives a tiny reproducible example and discusses the specific issues. The example is actually mild. I have larger data sets where the effect is worse, added at the end; but the following tiny example demonstrates the core issues.
Code for reproduction
import matplotlib.pyplot as mp
import numpy as np
matrix = np.zeros((40, 40), dtype='int32')
np.fill_diagonal(matrix, 1)
mp.imshow(matrix)
axis = mp.gca()
axis.set_yticks([10.5, 20.5, 30.5], minor='True')
axis.set_xticks([10.5, 20.5, 30.5], minor='True')
axis.yaxis.grid(True, which='minor')
axis.xaxis.grid(True, which='minor')
mp.savefig(fname='bug.png')
Actual outcome
Elaboration
Due to rounding, each cell of the data can have one of two sizes in pixels the image. This is understandable and inevitable. I added a red border using the smaller size to demonstrate the rounding issues, and annotated points where the actual issues arise. You would want to zoom in on the image to properly see these issues.
Points:
-
The cell at (0, 0) is clipped by 2 pixels in the Y direction and 1 pixel in the X direction. Compare to the cell at (39, 39) where the grid line is completely outside the cell.
-
Grid lines placed exactly between cells must, of necessity, overlap one of the cells. However, for best visual results, if the grid line is between a "big" cell and a "small" cell, the result is much better-looking if the grid line overlaps the "big" cell. You could argue this is nit-picking, but if rounding issues are addressed, this should be at least in the "to be considered" issues list.
-
The grid line which should have been between the cells is actually inside a cell. This seems to be an actual bug; on its face, there's no reason that this should ever happen, rounding errors or no rounding errors. It is worth noting that this seems to always happen in the Y direction and never in the X direction. There seems to be different treatment of X and Y axes when it comes to grid placement and rounding, expressed both at this point and at the first point. On it face, the code should be identical in both cases, so such axis-dependent artifacts should "never happen". If/when someone actually debugs the code, I would suggest that the first step would be looking for reasons why there is actually a difference between the X and Y axes.
-
Neither the (0, 0) cell nor the (39, 39) cell are "big" (with an extra pixel), because "big" cells appear only every 2/3 cells, and the (0, 0) cell and (39, 39) cells are too close to an existing big cell. Also, none of the "big" cells are exactly 2 or 3 cells away from either (0, 0) or (39, 39). Since the decision of whether a cell is "big" depends on rounding errors, one would expect that if every 4th cell is a "big" cell, then the 4th cell (starting from (0, 0), say) would be the 1st "big" cell. Perhaps using "round" shifts the pattern by one-half the repeat rate? Something to ponder when comparing the position of grid lines and cells (perhaps one us using "round" and another is using "floor")?
Matplotlib version
- Operating system: Linux, CentOs 7.5
- Matplotlib version: 2.2.3 (installed using
pip
). - Matplotlib backend: TkAgg
- Python version: 3.6
- Jupyter version (if applicable): NA
- Other libraries: NA
Example with worse effects
The following example is from my actual program. The grid line coordinates are identical in the X and Y axis; you can see in the top-right corner the top-most gray grid line is too low (purple pixels visible above it). Even worse, the matrix has an all-0 diagonal. This ends up being several pixels away from the top-right grid corner. This seems to go way beyond a +/- one pixel rounding error to point at a more systematic problem. Perhaps the problem is that the grid Y size does not match the data's Y size in some way.