matplotlib / matplotlib/matplotlib
Misalignment between grid and image in imshow w/ examples
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 23.2k
- Forks
- 8.5k
- Avg merge
- 1d 6h
- Merged PRs (30d)
- 66
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**
```python
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:
1. 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.
2. 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.
3. 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.
4. 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.

Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Run the provided Python reproduction using imshow, minor ticks, axis grids, and savefig, then compare the rendered grid lines with the image cells in the attached examples. Investigate the differing X and Y placement and rounding behavior; done means grid lines consistently align between cells without axis-dependent offsets or unexpected clipping.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- matplotlib, python
- Domain
- data-visualization
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 42/100