FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

Support for Scalar Image Cursor Display? · Issue #3984 · matplotlib/matplotlib · GitHub

Repository navigation

Support for Scalar Image Cursor Display? #3984

Closed

Description

How would everyone feel about the following change? It will show the z value of a scalar image in the cursor if available (similar to what Matlab does). If there is no image or the image is RGB, it will revert to the previous behaviour.

--- a/lib/matplotlib/axes/_base.py
+++ b/lib/matplotlib/axes/_base.py
@@ -2971,7 +2971,12 @@ class _AxesBase(martist.Artist):
             ys = '???'
         else:
             ys = self.format_ydata(y)
-        return 'x=%s y=%s' % (xs, ys)
+        try:
+            z = self.images[0].get_array()[int(y + 0.5), int(x + 0.5)]
+            zs = self.format_xdata(z)
+            return 'x=%s y=%s z=%s' % (xs, ys, zs)
+        except:
+            return 'x=%s y=%s' % (xs, ys)

     def minorticks_on(self):
         'Add autoscaling minor ticks to the axes.'

Activity

  1. blink1073 commented on Jan 9, 2015

    MemberAuthor

    We could also add a fmt_zdata which falls back on format_xdata if None, so the user can directly change the z axis format:

    --- a/lib/matplotlib/axes/_base.py
    +++ b/lib/matplotlib/axes/_base.py
    @@ -438,6 +438,7 @@ class _AxesBase(martist.Artist):
             # funcs used to format x and y - fall back on major formatters
             self.fmt_xdata = None
             self.fmt_ydata = None
    +        self.fmt_zdata = None
    
             self.set_cursor_props((1, 'k'))  # set the cursor properties for axes
    
    @@ -2971,7 +2972,13 @@ class _AxesBase(martist.Artist):
                 ys = '???'
             else:
                 ys = self.format_ydata(y)
    -        return 'x=%s y=%s' % (xs, ys)
    +        try:
    +            z = self.images[0].get_array()[int(y + 0.5), int(x + 0.5)]
    +            formatter = self.fmt_zdata or self.format_xdata
    +            zs = formatter(z)
    +            return 'x=%s y=%s z=%s' % (xs, ys, zs)
    +        except:
    +            return 'x=%s y=%s' % (xs, ys)
    
         def minorticks_on(self):
  2. tacaswell commented on Jan 9, 2015

    Member

    You need to also take the extent of the image into account.

  3. WeatherGod commented on Jan 9, 2015

    Member

    Yeah, it is a lot more complicated than that. I made an exa!mole demoing it
    in my upcoming book, but it is incomplete in that it only recognizes the
    last image added (doesn't take into account the zsort order).
    On Jan 8, 2015 9:36 PM, "Thomas A Caswell" notifications@github.com wrote:

    You need to also take the extent of the image into account.

    —
    Reply to this email directly or view it on GitHub
    #3984 (comment)
    .

  4. WeatherGod commented on Jan 9, 2015

    Member

    I should note that my example was partly based off of the functionality
    provided by the mpldatacursor package.
    On Jan 8, 2015 9:41 PM, "Benjamin Root" ben.root@ou.edu wrote:

    Yeah, it is a lot more complicated than that. I made an exa!mole demoing
    it in my upcoming book, but it is incomplete in that it only recognizes the
    last image added (doesn't take into account the zsort order).
    On Jan 8, 2015 9:36 PM, "Thomas A Caswell" notifications@github.com
    wrote:

    You need to also take the extent of the image into account.

    —
    Reply to this email directly or view it on GitHub
    #3984 (comment)
    .

  5. blink1073 commented on Jan 9, 2015

    MemberAuthor

    I hear this complaint from everyone I introduce to Python, so I'd really like to nail this down.

  6. blink1073 commented on Jan 9, 2015

    MemberAuthor

    Hack so far based on mpldatacursor:

    --- a/lib/matplotlib/axes/_base.py
    +++ b/lib/matplotlib/axes/_base.py
    @@ -438,6 +438,7 @@ class _AxesBase(martist.Artist):
             # funcs used to format x and y - fall back on major formatters
             self.fmt_xdata = None
             self.fmt_ydata = None
    +        self.fmt_zdata = None
    
             self.set_cursor_props((1, 'k'))  # set the cursor properties for axes
    
    @@ -2961,6 +2962,17 @@ class _AxesBase(martist.Artist):
                 val = func(y)
                 return val
    
    +    def _get_z_coord(self, x, y):
    +        im = self.images[0]
    +        xmin, xmax, ymin, ymax = im.get_extent()
    +        if im.origin == 'upper':
    +            ymin, ymax = ymax, ymin
    +        data_extent = mtransforms.Bbox([[ymin, xmin], [ymax, xmax]])
    +        array_extent = mtransforms.Bbox([[0, 0], im.get_array().shape[:2]])
    +        trans = mtransforms.BboxTransformFrom(data_extent) +\
    +            mtransforms.BboxTransformTo(array_extent)
    +        return trans.transform_point([y,x]).astype(int)
    +
         def format_coord(self, x, y):
             """Return a format string formatting the *x*, *y* coord"""
             if x is None:
    @@ -2971,7 +2983,14 @@ class _AxesBase(martist.Artist):
                 ys = '???'
             else:
                 ys = self.format_ydata(y)
    -        return 'x=%s y=%s' % (xs, ys)
    +        try:
    +            i, j = self._get_z_coord(x, y)
    +            z = self.images[0].get_array()[i, j]
    +            formatter = self.fmt_zdata or self.format_xdata
    +            zs = formatter(z)
    +            return 'x=%s y=%s z=%s' % (xs, ys, zs)
    +        except:
    +            return 'x=%s y=%s' % (xs, ys)
    
         def minorticks_on(self):
             'Add autoscaling minor ticks to the axes.'
  7. blink1073 commented on Jan 9, 2015

    MemberAuthor

    With zorder handling:

    --- a/lib/matplotlib/axes/_base.py
    +++ b/lib/matplotlib/axes/_base.py
    @@ -438,6 +438,7 @@ class _AxesBase(martist.Artist):
             # funcs used to format x and y - fall back on major formatters
             self.fmt_xdata = None
             self.fmt_ydata = None
    +        self.fmt_zdata = None
    
             self.set_cursor_props((1, 'k'))  # set the cursor properties for axes
    
    @@ -2961,6 +2962,16 @@ class _AxesBase(martist.Artist):
                 val = func(y)
                 return val
    
    +    def _get_z_coord(self, im, x, y):
    +        xmin, xmax, ymin, ymax = im.get_extent()
    +        if im.origin == 'upper':
    +            ymin, ymax = ymax, ymin
    +        data_extent = mtransforms.Bbox([[ymin, xmin], [ymax, xmax]])
    +        array_extent = mtransforms.Bbox([[0, 0], im.get_array().shape[:2]])
    +        trans = mtransforms.BboxTransformFrom(data_extent) +\
    +            mtransforms.BboxTransformTo(array_extent)
    +        return trans.transform_point([y,x]).astype(int)
    +
         def format_coord(self, x, y):
             """Return a format string formatting the *x*, *y* coord"""
             if x is None:
    @@ -2971,7 +2982,15 @@ class _AxesBase(martist.Artist):
                 ys = '???'
             else:
                 ys = self.format_ydata(y)
    -        return 'x=%s y=%s' % (xs, ys)
    +        try:
    +            im = self.images[np.argmax([im.zorder for im in self.images])]
    +            i, j = self._get_z_coord(im, x, y)
    +            z = im.get_array()[i, j]
    +            formatter = self.fmt_zdata or self.format_xdata
    +            zs = formatter(z)
    +            return 'x=%s y=%s z=%s' % (xs, ys, zs)
    +        except:
    +            return 'x=%s y=%s' % (xs, ys)
    
         def minorticks_on(self):
             'Add autoscaling minor ticks to the axes.'
  8. tacaswell commented on Jan 9, 2015

    Member

    All artists have picker logic, you could probably hi-jack that to sort out which, if any of the you are in and then take the top one of that sub-set.

    This may be why no one has done this yet (obnoxious demanding devs) ;)

  9. blink1073 commented on Jan 9, 2015

    MemberAuthor

    So basically all of mpldatacursor then...

  10. blink1073 commented on Jan 9, 2015

    MemberAuthor

    The problem I see is that we don't have an event, which is needed by the picking logic and is used extensively by mpldatacursor.

  11. tacaswell commented on Jan 9, 2015

    Member

    We should have a mouse motion event (as that is what is updating the
    formatter).

    On Thu Jan 08 2015 at 10:14:31 PM Steven Silvester notifications@github.com
    wrote:

    The problem I see is that we don't have an event, which is needed by
    the picking logic and is used extensively by mpldatacursor.

    —
    Reply to this email directly or view it on GitHub
    #3984 (comment)
    .

  12. blink1073 commented on Jan 9, 2015

    MemberAuthor

    So we'd need to plug in here:

    ./backend_bases.py:2790: s = event.inaxes.format_coord(event.xdata, event.ydata)

  13. blink1073 commented on Jan 9, 2015

    MemberAuthor

    Get the s message there and then get an optional add-on message based on the artist...

  14. blink1073 commented on Jan 9, 2015

    MemberAuthor

    Shucks, there is no artist assigned to a motion_notify_event.

  15. tacaswell commented on Jan 9, 2015

    Member

    This is some-what related to the discussion in #2986 in that we were talking about (iirc with out re-reading it in detail) a way to stack the message strings from multiple axes, not just the 'top' one of a twin{x,y} pair.

    This should also be linked to #3146

  16. 7 remaining items

  17. blink1073 commented on Jan 9, 2015

    MemberAuthor

    I sense a PR coming...

  18. blink1073 commented on Jan 9, 2015

    MemberAuthor

    What if there are multiple images though? Don't we still need a zorder arbiter?

  19. tacaswell commented on Jan 9, 2015

    Member

    Yeah, it should probably figure out which of the artists it is over and then only ask the top artist to add an entry to the message. This will also help arbitrate when we have multiple crossing lines or lines on top of images, etc.

  20. blink1073 commented on Jan 9, 2015

    MemberAuthor

    I think we should still check for contains, then check zorder, then ask that artist for its additional message, no?

  21. blink1073 commented on Jan 9, 2015

    MemberAuthor

    Ah, I see that is what you already said...

  22. added this to the milestone on Feb 19, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions


      Back | FazBrowse Home | New Git URL