Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Misalignment imshow vs. grid lines #1441

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
rougier opened this issue Oct 31, 2012 · 17 comments
Open

Misalignment imshow vs. grid lines #1441

rougier opened this issue Oct 31, 2012 · 17 comments
Labels
keep Items to be ignored by the “Stale” Github Action status: confirmed bug status: needs patch

Comments

@rougier
Copy link
Member

rougier commented Oct 31, 2012

The following script show a mis-alignment between grid lines and image patterns while they should be aligned:

import numpy as np
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt

n = 16
fig = plt.figure(figsize=(6,6))
Z = np.zeros((n,n))
Z[::2,::2] = Z[1::2,1::2] = 1
plt.imshow(Z, interpolation='none', cmap=plt.cm.gray, extent=[0,n,0,n], alpha=0.25)
plt.xticks(np.arange(0,n), []), plt.yticks(np.arange(0,n), [])
plt.grid(ls='solid')
delta = 0.01
plt.xlim(1-delta,1+delta), plt.ylim(1-delta,1+delta)
plt.savefig('pylab-grid.png')
plt.savefig('pylab-grid.pdf')
@pelson
Copy link
Member

pelson commented Oct 31, 2012

@rougier : You can make code blocks with three consecutive ``` (grave/backquotes). Hope you don't mind but I've edited your description to use them.

@tacaswell
Copy link
Member

If you interactively pan around on this example the amount that the lines miss the edges of the pixels by jumps around. I suspect that this might be related to #3057 (more beating?) and smells like snap is related, but I don't understand that well enough

@tacaswell
Copy link
Member

Punting this to 1.4.x as this is only visible if you zoom way in and looks like it is something subtle down at the bottom (maybe not a fast find or fix).

@tacaswell tacaswell modified the milestones: v1.4.x, v1.4.0 Jun 4, 2014
@mojca
Copy link

mojca commented Jun 4, 2014

I'm not objecting the increase of the milestone. I agree that it might be difficult to debug this and that one would usually not see the difference, I just wanted to note that this effect may be visible at normal magnifications as well. I spotted it at relatively normal scale when noticing that the grid was off the pixels on the image (my real-life example is very similar to #2935).

What is the expected result of the example above? I'm asking because I see off-by-one error on PNG, but the PDF I get seems completely wrong.

@tacaswell tacaswell modified the milestones: v1.4.x, 1.5.0 Feb 7, 2015
@jkseppan
Copy link
Member

jkseppan commented Jul 8, 2015

If I change interpolation='none' to interpolation='nearest' the PDF looks similar to the PNG. The Agg backend has to resample images to display them, but the PDF backend does not, so when you make a very low-resolution image it's up to the viewer program to figure out how to display it.

Here's another example adapted from #2935:

import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['pdf.compression'] = 0

plt.gcf().set_size_inches([1,1])
a=np.bitwise_xor.outer(np.arange(20)&2, np.arange(20)&2)
im = plt.imshow(a, interpolation='none', cmap='gray', origin='lower', extent=[-2,2,-2,2])
plt.gca().set_xticks(np.linspace(-2,2,21))
plt.gca().set_yticks(np.linspace(-2,2,21))
plt.gca().xaxis.set_ticklabels([])
plt.gca().yaxis.set_ticklabels([])
plt.grid(ls='-',lw=0.1,color='white')
plt.axis('square')
plt.savefig('pattern.png')
plt.savefig('pattern.pdf')

Here's how the checkerboard pattern image looks, as written in the PDF file:

ff fe 00 00 ff fe 00 00 ff fe 00 00 ff fe 00 00 ff fe 00 00
ff fe 00 00 ff fe 00 00 ff fe 00 00 ff fe 00 00 ff fe 00 00
00 01 fe fc 00 01 fe fc 00 01 fe fc 00 01 fe fc 00 01 fe fe
00 00 ff fe 00 00 ff fe 00 00 ff fe 00 00 ff fe 00 00 ff ff
fe fc 00 01 fe fc 00 01 fe fc 00 01 fe fc 00 01 fe fc 00 00
ff fe 00 00 ff fe 00 00 ff fe 00 00 ff fe 00 00 ff fe 00 00
00 01 fe fc 00 01 fe fc 00 01 fe fc 00 01 fe fc 00 01 fe fe
00 00 ff fe 00 00 ff fe 00 00 ff fe 00 00 ff fe 00 00 ff ff
fe fc 00 01 fe fc 00 01 fe fc 00 01 fe fc 00 01 fe fc 00 00
ff fe 00 00 ff fe 00 00 ff fe 00 00 ff fe 00 00 ff fe 00 00
00 01 fe fc 00 01 fe fc 00 01 fe fc 00 01 fe fc 00 01 fe fe
00 00 ff fe 00 00 ff fe 00 00 ff fe 00 00 ff fe 00 00 ff ff
fe fc 00 01 fe fc 00 01 fe fc 00 01 fe fc 00 01 fe fc 00 00
ff fe 00 00 ff fe 00 00 ff fe 00 00 ff fe 00 00 ff fe 00 00
00 01 fe fc 00 01 fe fc 00 01 fe fc 00 01 fe fc 00 01 fe fe
00 00 ff fe 00 00 ff fe 00 00 ff fe 00 00 ff fe 00 00 ff ff
fe fc 00 01 fe fc 00 01 fe fc 00 01 fe fc 00 01 fe fc 00 00
ff fe 00 00 ff fe 00 00 ff fe 00 00 ff fe 00 00 ff fe 00 00
00 01 fe fc 00 01 fe fc 00 01 fe fc 00 01 fe fc 00 01 fe fe
00 00 ff fe 00 00 ff fe 00 00 ff fe 00 00 ff fe 00 00 ff ff

Note that the values are not all 00 or ff. Even with interpolation='none' there is some resampling going on, and the data written in the file is not exactly what was given to imshow.

@tacaswell tacaswell modified the milestones: proposed next point release, next point release Jul 17, 2015
@efiring
Copy link
Member

efiring commented May 22, 2016

The bug is still present after the image refactor.

@tacaswell tacaswell modified the milestones: 2.1 (next point release), 2.1.1 (next bug fix release) Sep 24, 2017
@tacaswell
Copy link
Member

There is some quantization going on with this. If you pan left and right the pattern 'jumps' but the grid lines move smoothly.

@tacaswell tacaswell modified the milestones: 2.1.1 (next bug fix release), 2.2 (next feature release) Oct 9, 2017
@kuzand
Copy link

kuzand commented Apr 20, 2018

The grid lines are misaligned on the x-axis. E.g.

import numpy as np
import matplotlib.pyplot as plt
nx, ny = 5, 5
Z = np.random.randint(2, size=(ny,nx))
fix, ax = plt.subplots()
ax.set_xticks(np.arange(0.5, nx-1, 1))
ax.set_yticks(np.arange(0.5, ny-1, 1))
plt.imshow(Z, cmap='binary')
plt.grid()
plt.show()

Is there a fix for this?

@tacaswell
Copy link
Member

I sunk the better part of a day into this and still don't really understand it (but I as a side-effect, I think I have the start of a performance-improvement PR!).

  • single pixel offset an 'zoomed' out maybe due to implicit pixel snapping on the image, explicit pixel snapping on the grid lines, and a mis-match between the number of pixels in the output and and the number of pixel in the input. If you ask for a 5x5 gird rendered into 333 pixels across, the 'logical pixels' will not be the same size in 'screen pixels'
  • if you zoom very far in (like ax.set_xlim((3.4904144000410406, 3.516563080023857))) then you can get really big offsets in screen space between the lines and the 'logical pixel' edges, however if you scan the limits slightly left or right the amount of error changes. As mentioned above, the grid lines move smoothly, the 'logical pixels' jump. This makes me think that we are running into precision issues someplace, but not clear to me where
  • they don't jump in the y-direction, but gets a bit funny with zoom
  • may depend on where in the image you are
  • the error does not depend on figure size, just the x-limits
  • not clear if the issue as at the 'resample the image' step or the 'put the image on the canvas' step.

I suspect that the issue is in how we are calling the Agg resample code, but that may just me blaming the part of the code I understand the least.

@QuLogic
Copy link
Member

QuLogic commented Apr 22, 2020

This is about PNG, not PDF, but I wonder if your trawling into raster image rendering might give you some ideas about this, @brunobeltran.

@brunobeltran
Copy link
Contributor

Oh neat, this is the error I alluded to in #6827. This is separate from all DPI-related issues actually, and has to do instead with the logic in the helper function _ImageBase._make_image that decides how to color each pixel. It will always be off by exactly one-half "input pixels", since it's passed the _ImageBase's extents, which look like:

    def get_extent(self):
        """Return the image extent as tuple (left, right, bottom, top)."""
        numrows, numcols = self.get_size()
        return (-0.5 + self.ox, numcols-0.5 + self.ox,
                -0.5 + self.oy, numrows-0.5 + self.oy)

After I push working versions of the rounding fixes, I'll try to think harder about the "correct" way to fix this.

This is related to the issue brought up by @efiring yesterday on the call, where we sometimes want to use the center of the pixel's color to decide the color, and sometimes we want the color on the edge...

@brunobeltran
Copy link
Contributor

brunobeltran commented Apr 22, 2020

If anyone has thoughts about how this should be fixed, the easiest way to see the faulty logic is to use a trivial example:

import matplotlib.pyplot as plt
delta = 0.01
plt.imshow([[1, 0], [0, 1]], interpolation='antialiased')
plt.xlim([1/2 - delta, 1/2 + delta])
plt.ylim([1/2 - delta, 1/2 + delta])
plt.savefig('anything.anyextension')

and set a breakpoint at image.py:903 or so. Notice that the input array is correct, but the return value from make_image already has the "offset" issue, due to the value passed to bbox.

@github-actions
Copy link

This issue has been marked "inactive" because it has been 365 days since the last comment. If this issue is still present in recent Matplotlib releases, or the feature request is still wanted, please leave a comment and this label will be removed. If there are no updates in another 30 days, this issue will be automatically closed, but you are free to re-open or create a new issue if needed. We value issue reports, and this procedure is meant to help us resurface and prioritize issues that have not been addressed yet, not make them disappear. Thanks for your help!

@github-actions github-actions bot added the status: inactive Marked by the “Stale” Github Action label Feb 28, 2023
@oscargus
Copy link
Member

Still a problem, this is the current PNG from the first example:

pylab-grid

@rcomer rcomer removed the status: inactive Marked by the “Stale” Github Action label Feb 28, 2023
Copy link

github-actions bot commented Mar 1, 2024

This issue has been marked "inactive" because it has been 365 days since the last comment. If this issue is still present in recent Matplotlib releases, or the feature request is still wanted, please leave a comment and this label will be removed. If there are no updates in another 30 days, this issue will be automatically closed, but you are free to re-open or create a new issue if needed. We value issue reports, and this procedure is meant to help us resurface and prioritize issues that have not been addressed yet, not make them disappear. Thanks for your help!

@github-actions github-actions bot added the status: inactive Marked by the “Stale” Github Action label Mar 1, 2024
@github-actions github-actions bot added the status: closed as inactive Issues closed by the "Stale" Github Action. Please comment on any you think should still be open. label Apr 1, 2024
@github-actions github-actions bot closed this as not planned Won't fix, can't repro, duplicate, stale Apr 1, 2024
@pelson
Copy link
Member

pelson commented Apr 1, 2024

Just to add that this issue still exists on main, and I can confirm that it can be seen without the Agg renderer (cairo & another). This supports the assumption that this is a problem in the image code, rather than the renderer.

I find it curious that you only see the misalignment in the y-axis, and not in the x.

@timhoffm timhoffm added keep Items to be ignored by the “Stale” Github Action and removed status: inactive Marked by the “Stale” Github Action status: closed as inactive Issues closed by the "Stale" Github Action. Please comment on any you think should still be open. labels Apr 1, 2024
@timhoffm
Copy link
Member

timhoffm commented Apr 1, 2024

This should stay open.

@timhoffm timhoffm reopened this Apr 1, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
keep Items to be ignored by the “Stale” Github Action status: confirmed bug status: needs patch
Projects
None yet
Development

No branches or pull requests