Is there a way to link axes of imshow plots?

Suppose I have a figure canvas with 3 plots… 2 are images of the same dimensions plotted with imshow, and the other is a scatterplot. I’d like to be able to link the x and y axes of the imshow plots so that when I zoom in one, the other zooms to the same coordinates, and when I pan in one, the other pans as well.

I started hacking my way around this by subclassing NavigationToolbar2WxAgg (shown below)… but there are several problems here.

  1. This will link the axes of all plots in a canvas since all I’ve done is get rid of the checks for a.in_axes()

  2. This worked well for panning, but zooming caused all subplots to zoom from the same global point, rather than from the same point in each of their respective axes.

Can anyone suggest a workaround?

Much thanks!

-Adam

from matplotlib.backends.backend_wxagg import NavigationToolbar2WxAgg as NavigationToolbar

class MyNavToolbar(NavigationToolbar):

def __init__(self, canvas, cpfig):

    NavigationToolbar.__init__(self, canvas)

    

# override

def press_pan(self, event):

    'the press mouse button in pan/zoom mode callback'

    if event.button == 1:

        self._button_pressed=1

    elif  event.button == 3:

        self._button_pressed=3

    else:

        self._button_pressed=None

        return

    x, y = event.x, event.y

    # push the current view to define home if stack is empty

    if self._views.empty(): self.push_current()

    self._xypress=[]

    for i, a in enumerate(self.canvas.figure.get_axes()):

        **# only difference from overridden method is that this one doesn't**

** # check a.in_axes(event) **

        if x is not None and y is not None and a.get_navigate():

            a.start_pan(x, y, event.button)

            self._xypress.append((a, i))

            self.canvas.mpl_disconnect(self._idDrag)

            self._idDrag=self.canvas.mpl_connect('motion_notify_event', self.drag_pan)



def press_zoom(self, event):

    'the press mouse button in zoom to rect mode callback'

    if event.button == 1:

        self._button_pressed=1

    elif  event.button == 3:

        self._button_pressed=3

    else:

        self._button_pressed=None

        return

    x, y = event.x, event.y

    # push the current view to define home if stack is empty

    if self._views.empty(): self.push_current()

    self._xypress=[]

    for i, a in enumerate(self.canvas.figure.get_axes()):

        **# only difference from overridden method is that this one doesn't**

** # check a.in_axes(event) **

        if x is not None and y is not None and a.get_navigate() and a.can_zoom():

            self._xypress.append(( x, y, a, i, a.viewLim.frozen(), a.transData.frozen()))

    self.press(event)

Do the “sharex” and “sharey”
kwargs help?

http://matplotlib.sourceforge.net/api/pyplot_api.html#matplotlib.pyplot.axes

http://matplotlib.sourceforge.net/examples/pylab_examples/shared_axis_demo.html

-paul

From:
Adam Fraser [mailto:adam.n.fraser@…287…]
AM
there a way to link axes of imshow plots?

Suppose I have a figure canvas with 3 plots… 2 are images of the same
dimensions plotted with imshow, and the other is a scatterplot. I’d like to be
able to link the x and y axes of the imshow plots so that when I zoom in one, the
other zooms to the same coordinates, and when I pan in one, the other pans as
well.

I started hacking my way around this by
subclassing NavigationToolbar2WxAgg (shown below)… but there are several
problems here.

  1. This will link the axes of all plots in a canvas since all I’ve done
    is get rid of the checks for a.in_axes()

  2. This worked well for panning, but zooming caused all subplots to
    zoom from the same global point, rather than from the same point in each of
    their respective axes.

Can anyone suggest a workaround?

Much thanks!

-Adam

from matplotlib.backends.backend_wxagg import NavigationToolbar2WxAgg
as NavigationToolbar

class MyNavToolbar(NavigationToolbar):

def __init__(self, canvas,

cpfig):

NavigationToolbar.init(self, canvas)

# override

def press_pan(self, event):

    'the press mouse

button in pan/zoom mode callback’

    if event.button ==

1:

self._button_pressed=1

    elif

event.button == 3:

self._button_pressed=3

    else:

self._button_pressed=None

return

    x, y = event.x,

event.y

    # push the current

view to define home if stack is empty

    if self._views.empty():

self.push_current()

    self._xypress=[]

    for i, a in

enumerate(self.canvas.figure.get_axes()):

        **# only difference from overridden method is that this

one doesn’t**

···

Sent: Thursday, May 27, 2010 10:44
To: matplotlib-users
Subject: [Matplotlib-users] Is

**
# check a.in_axes(event) **

        if x

is not None and y is not None and a.get_navigate():

a.start_pan(x, y, event.button)

self._xypress.append((a, i))

self.canvas.mpl_disconnect(self._idDrag)

self._idDrag=self.canvas.mpl_connect(‘motion_notify_event’,
self.drag_pan)

def press_zoom(self, event):

    'the press mouse

button in zoom to rect mode callback’

    if event.button ==

1:

self._button_pressed=1

    elif

event.button == 3:

self._button_pressed=3

    else:

self._button_pressed=None

return

    x, y = event.x,

event.y

    # push the current

view to define home if stack is empty

    if

self._views.empty(): self.push_current()

    self._xypress=[]

    for i, a in

enumerate(self.canvas.figure.get_axes()):

        **# only difference from overridden method is that this

one doesn’t**

**
# check a.in_axes(event) **

        if x

is not None and y is not None and a.get_navigate() and a.can_zoom():

self._xypress.append(( x, y, a, i, a.viewLim.frozen(),
a.transData.frozen()))

    self.press(event)

ax1 = subplot(121)
ax2 = subplot(122, sharex=ax1, sharey=ax1)

ax1.set_adjustable("box-forced")
ax2.set_adjustable("box-forced")

arr1 = np.arange(100).reshape((10, 10))
ax1.imshow(arr1)

arr2 = np.arange(100, 0, -1).reshape((10, 10))
ax2.imshow(arr2)

Note the use of set_adjustable("box-forced").
sharex and sharey does not get along with axes of aspect=1 & adjustable="box".

-JJ

···

On Thu, May 27, 2010 at 2:10 PM, <PHobson@...2850...> wrote:

Do the “sharex” and “sharey” kwargs help?

http://matplotlib.sourceforge.net/api/pyplot_api.html#matplotlib.pyplot.axes

http://matplotlib.sourceforge.net/examples/pylab_examples/shared_axis_demo.html

-paul

From: Adam Fraser [mailto:adam.n.fraser@…287…]
Sent: Thursday, May 27, 2010 10:44 AM
To: matplotlib-users
Subject: [Matplotlib-users] Is there a way to link axes of imshow plots?

Suppose I have a figure canvas with 3 plots... 2 are images of the same
dimensions plotted with imshow, and the other is a scatterplot. I'd like to
be able to link the x and y axes of the imshow plots so that when I zoom in
one, the other zooms to the same coordinates, and when I pan in one, the
other pans as well.

I started hacking my way around this by subclassing NavigationToolbar2WxAgg
(shown below)... but there are several problems here.

1) This will link the axes of all plots in a canvas since all I've done is
get rid of the checks for a.in_axes()

2) This worked well for panning, but zooming caused all subplots to zoom
from the same global point, rather than from the same point in each of their
respective axes.

Can anyone suggest a workaround?

Much thanks!

-Adam

from matplotlib.backends.backend_wxagg import NavigationToolbar2WxAgg as
NavigationToolbar

class MyNavToolbar(NavigationToolbar):

def \_\_init\_\_\(self, canvas, cpfig\):

    NavigationToolbar\.\_\_init\_\_\(self, canvas\)

\# override

def press\_pan\(self, event\):

    &#39;the press mouse button in pan/zoom mode callback&#39;

    if event\.button == 1:

        self\.\_button\_pressed=1

    elif  event\.button == 3:

        self\.\_button\_pressed=3

    else:

        self\.\_button\_pressed=None

        return

    x, y = event\.x, event\.y

    \# push the current view to define home if stack is empty

    if self\.\_views\.empty\(\): self\.push\_current\(\)

    self\.\_xypress=\[\]

    for i, a in enumerate\(self\.canvas\.figure\.get\_axes\(\)\):

        \# only difference from overridden method is that this one

doesn't

        \# check a\.in\_axes\(event\)

        if x is not None and y is not None and a\.get\_navigate\(\):

            a\.start\_pan\(x, y, event\.button\)

            self\.\_xypress\.append\(\(a, i\)\)

            self\.canvas\.mpl\_disconnect\(self\.\_idDrag\)

            self\.\_idDrag=self\.canvas\.mpl\_connect\(&#39;motion\_notify\_event&#39;,

self.drag_pan)

def press\_zoom\(self, event\):

    &#39;the press mouse button in zoom to rect mode callback&#39;

    if event\.button == 1:

        self\.\_button\_pressed=1

    elif  event\.button == 3:

        self\.\_button\_pressed=3

    else:

        self\.\_button\_pressed=None

        return

    x, y = event\.x, event\.y

    \# push the current view to define home if stack is empty

    if self\.\_views\.empty\(\): self\.push\_current\(\)

    self\.\_xypress=\[\]

    for i, a in enumerate\(self\.canvas\.figure\.get\_axes\(\)\):

        \# only difference from overridden method is that this one

doesn't

        \# check a\.in\_axes\(event\)

        if x is not None and y is not None and a\.get\_navigate\(\) and

a.can_zoom():

            self\.\_xypress\.append\(\( x, y, a, i, a\.viewLim\.frozen\(\),

a.transData.frozen()))

    self\.press\(event\)

------------------------------------------------------------------------------

_______________________________________________
Matplotlib-users mailing list
Matplotlib-users@lists.sourceforge.net
matplotlib-users List Signup and Options

Thanks very much,

I’m getting ValueError: argument must be “box”, or “datalim” at set_adjustable…

I’m using Matplotlib version 0.98.5.3, do I need to update?

···

On Thu, May 27, 2010 at 2:59 PM, Jae-Joon Lee <lee.j.joon@…287…> wrote:

ax1 = subplot(121)

ax2 = subplot(122, sharex=ax1, sharey=ax1)

ax1.set_adjustable(“box-forced”)

ax2.set_adjustable(“box-forced”)

arr1 = np.arange(100).reshape((10, 10))

ax1.imshow(arr1)

arr2 = np.arange(100, 0, -1).reshape((10, 10))

ax2.imshow(arr2)

Note the use of set_adjustable(“box-forced”).

sharex and sharey does not get along with axes of aspect=1 & adjustable=“box”.

-JJ

On Thu, May 27, 2010 at 2:10 PM, <PHobson@…2850…> wrote:

Do the “sharex” and “sharey” kwargs help?

http://matplotlib.sourceforge.net/api/pyplot_api.html#matplotlib.pyplot.axes

http://matplotlib.sourceforge.net/examples/pylab_examples/shared_axis_demo.html

-paul

From: Adam Fraser [mailto:adam.n.fraser@…287…]

Sent: Thursday, May 27, 2010 10:44 AM

To: matplotlib-users

Subject: [Matplotlib-users] Is there a way to link axes of imshow plots?

Suppose I have a figure canvas with 3 plots… 2 are images of the same

dimensions plotted with imshow, and the other is a scatterplot. I’d like to

be able to link the x and y axes of the imshow plots so that when I zoom in

one, the other zooms to the same coordinates, and when I pan in one, the

other pans as well.

I started hacking my way around this by subclassing NavigationToolbar2WxAgg

(shown below)… but there are several problems here.

  1. This will link the axes of all plots in a canvas since all I’ve done is

get rid of the checks for a.in_axes()

  1. This worked well for panning, but zooming caused all subplots to zoom

from the same global point, rather than from the same point in each of their

respective axes.

Can anyone suggest a workaround?

Much thanks!

-Adam

from matplotlib.backends.backend_wxagg import NavigationToolbar2WxAgg as

NavigationToolbar

class MyNavToolbar(NavigationToolbar):

def __init__(self, canvas, cpfig):
    NavigationToolbar.__init__(self, canvas)
# override
def press_pan(self, event):
    'the press mouse button in pan/zoom mode callback'
    if event.button == 1:
        self._button_pressed=1
    elif  event.button == 3:
        self._button_pressed=3
    else:
        self._button_pressed=None
        return
    x, y = event.x, event.y
    # push the current view to define home if stack is empty
    if self._views.empty(): self.push_current()
    self._xypress=[]
    for i, a in enumerate(self.canvas.figure.get_axes()):
        # only difference from overridden method is that this one

doesn’t

        # check a.in_axes(event)
        if x is not None and y is not None and a.get_navigate():
            a.start_pan(x, y, event.button)
            self._xypress.append((a, i))
            self.canvas.mpl_disconnect(self._idDrag)
            self._idDrag=self.canvas.mpl_connect('motion_notify_event',

self.drag_pan)

def press_zoom(self, event):
    'the press mouse button in zoom to rect mode callback'
    if event.button == 1:
        self._button_pressed=1
    elif  event.button == 3:
        self._button_pressed=3
    else:
        self._button_pressed=None
        return
    x, y = event.x, event.y
    # push the current view to define home if stack is empty
    if self._views.empty(): self.push_current()
    self._xypress=[]
    for i, a in enumerate(self.canvas.figure.get_axes()):
        # only difference from overridden method is that this one

doesn’t

        # check a.in_axes(event)
        if x is not None and y is not None and a.get_navigate() and

a.can_zoom():

            self._xypress.append(( x, y, a, i, a.viewLim.frozen(),

a.transData.frozen()))

    self.press(event)


Matplotlib-users mailing list

Matplotlib-users@lists.sourceforge.net

https://lists.sourceforge.net/lists/listinfo/matplotlib-users

Thanks very much,

I'm getting ValueError: argument must be "box", or "datalim" at
set_adjustable...

I'm using Matplotlib version 0.98.5.3, do I need to update?

Yes. Unfortunately, you will need to build from svn. JJ added box-forced in January, and we have not had a release since then.

Eric

···

On 05/27/2010 09:08 AM, Adam Fraser wrote:

On Thu, May 27, 2010 at 2:59 PM, Jae-Joon Lee <lee.j.joon@...287... > <mailto:lee.j.joon@…287…>> wrote:

    ax1 = subplot(121)
    ax2 = subplot(122, sharex=ax1, sharey=ax1)

    ax1.set_adjustable("box-forced")
    ax2.set_adjustable("box-forced")

    arr1 = np.arange(100).reshape((10, 10))
    ax1.imshow(arr1)

    arr2 = np.arange(100, 0, -1).reshape((10, 10))
    ax2.imshow(arr2)

    Note the use of set_adjustable("box-forced").
    sharex and sharey does not get along with axes of aspect=1 &
    adjustable="box".

    -JJ

Hi all, I updated to version 99.1.1 and I’m still getting the error

“ValueError: argument must be “box”, or “datalim” at set_adjustable…”

from axes.py

when I try to do ax.set_adjustable(“box-forced”) as you suggested.

-Adam

···

On Thu, May 27, 2010 at 3:08 PM, Adam Fraser <adam.n.fraser@…287…> wrote:

Thanks very much,

I’m getting ValueError: argument must be “box”, or “datalim” at set_adjustable…

I’m using Matplotlib version 0.98.5.3, do I need to update?

On Thu, May 27, 2010 at 2:59 PM, Jae-Joon Lee <lee.j.joon@…287…> wrote:

ax1 = subplot(121)

ax2 = subplot(122, sharex=ax1, sharey=ax1)

ax1.set_adjustable(“box-forced”)

ax2.set_adjustable(“box-forced”)

arr1 = np.arange(100).reshape((10, 10))

ax1.imshow(arr1)

arr2 = np.arange(100, 0, -1).reshape((10, 10))

ax2.imshow(arr2)

Note the use of set_adjustable(“box-forced”).

sharex and sharey does not get along with axes of aspect=1 & adjustable=“box”.

-JJ

On Thu, May 27, 2010 at 2:10 PM, <PHobson@…2850…> wrote:

Do the “sharex” and “sharey” kwargs help?

http://matplotlib.sourceforge.net/api/pyplot_api.html#matplotlib.pyplot.axes

http://matplotlib.sourceforge.net/examples/pylab_examples/shared_axis_demo.html

-paul

From: Adam Fraser [mailto:adam.n.fraser@…287…]

Sent: Thursday, May 27, 2010 10:44 AM

To: matplotlib-users

Subject: [Matplotlib-users] Is there a way to link axes of imshow plots?

Suppose I have a figure canvas with 3 plots… 2 are images of the same

dimensions plotted with imshow, and the other is a scatterplot. I’d like to

be able to link the x and y axes of the imshow plots so that when I zoom in

one, the other zooms to the same coordinates, and when I pan in one, the

other pans as well.

I started hacking my way around this by subclassing NavigationToolbar2WxAgg

(shown below)… but there are several problems here.

  1. This will link the axes of all plots in a canvas since all I’ve done is

get rid of the checks for a.in_axes()

  1. This worked well for panning, but zooming caused all subplots to zoom

from the same global point, rather than from the same point in each of their

respective axes.

Can anyone suggest a workaround?

Much thanks!

-Adam

from matplotlib.backends.backend_wxagg import NavigationToolbar2WxAgg as

NavigationToolbar

class MyNavToolbar(NavigationToolbar):

def __init__(self, canvas, cpfig):
    NavigationToolbar.__init__(self, canvas)
# override
def press_pan(self, event):
    'the press mouse button in pan/zoom mode callback'
    if event.button == 1:
        self._button_pressed=1
    elif  event.button == 3:
        self._button_pressed=3
    else:
        self._button_pressed=None
        return
    x, y = event.x, event.y
    # push the current view to define home if stack is empty
    if self._views.empty(): self.push_current()
    self._xypress=[]
    for i, a in enumerate(self.canvas.figure.get_axes()):
        # only difference from overridden method is that this one

doesn’t

        # check a.in_axes(event)
        if x is not None and y is not None and a.get_navigate():
            a.start_pan(x, y, event.button)
            self._xypress.append((a, i))
            self.canvas.mpl_disconnect(self._idDrag)
            self._idDrag=self.canvas.mpl_connect('motion_notify_event',

self.drag_pan)

def press_zoom(self, event):
    'the press mouse button in zoom to rect mode callback'
    if event.button == 1:
        self._button_pressed=1
    elif  event.button == 3:
        self._button_pressed=3
    else:
        self._button_pressed=None
        return
    x, y = event.x, event.y
    # push the current view to define home if stack is empty
    if self._views.empty(): self.push_current()
    self._xypress=[]
    for i, a in enumerate(self.canvas.figure.get_axes()):
        # only difference from overridden method is that this one

doesn’t

        # check a.in_axes(event)
        if x is not None and y is not None and a.get_navigate() and

a.can_zoom():

            self._xypress.append(( x, y, a, i, a.viewLim.frozen(),

a.transData.frozen()))

    self.press(event)


Matplotlib-users mailing list

Matplotlib-users@lists.sourceforge.net

https://lists.sourceforge.net/lists/listinfo/matplotlib-users

As Eric told, you need to build it from the "svn". Unfortunately, no
released version (I believe) includes this feature.

http://matplotlib.sourceforge.net/faq/installing_faq.html#install-from-svn

Anyhow, the patch for "box-forced" involves only a few lines of
change. You may consider to apply it by yourself (or do some monkey
patching).

Regards,

-JJ

···

On Tue, Jun 1, 2010 at 2:11 PM, Adam Fraser <adam.n.fraser@...287...> wrote:

Hi all, I updated to version 99.1.1 and I'm still getting the error
"ValueError: argument must be "box", or "datalim" at set_adjustable..."
from axes.py
when I try to do ax.set_adjustable("box-forced") as you suggested.
-Adam

On Thu, May 27, 2010 at 3:08 PM, Adam Fraser <adam.n.fraser@...287...> > wrote:

Thanks very much,
I'm getting ValueError: argument must be "box", or "datalim" at
set_adjustable...
I'm using Matplotlib version 0.98.5.3, do I need to update?

On Thu, May 27, 2010 at 2:59 PM, Jae-Joon Lee <lee.j.joon@...287...> >> wrote:

ax1 = subplot(121)
ax2 = subplot(122, sharex=ax1, sharey=ax1)

ax1.set_adjustable("box-forced")
ax2.set_adjustable("box-forced")

arr1 = np.arange(100).reshape((10, 10))
ax1.imshow(arr1)

arr2 = np.arange(100, 0, -1).reshape((10, 10))
ax2.imshow(arr2)

Note the use of set_adjustable("box-forced").
sharex and sharey does not get along with axes of aspect=1 &
adjustable="box".

-JJ

On Thu, May 27, 2010 at 2:10 PM, <PHobson@...2850...> wrote:
> Do the “sharex” and “sharey” kwargs help?
>
>
> http://matplotlib.sourceforge.net/api/pyplot_api.html#matplotlib.pyplot.axes
>
>
> http://matplotlib.sourceforge.net/examples/pylab_examples/shared_axis_demo.html
>
> -paul
>
>
>
> From: Adam Fraser [mailto:adam.n.fraser@…287…]
> Sent: Thursday, May 27, 2010 10:44 AM
> To: matplotlib-users
> Subject: [Matplotlib-users] Is there a way to link axes of imshow
> plots?
>
>
>
> Suppose I have a figure canvas with 3 plots... 2 are images of the same
> dimensions plotted with imshow, and the other is a scatterplot. I'd
> like to
> be able to link the x and y axes of the imshow plots so that when I
> zoom in
> one, the other zooms to the same coordinates, and when I pan in one,
> the
> other pans as well.
>
>
>
> I started hacking my way around this by
> subclassing NavigationToolbar2WxAgg
> (shown below)... but there are several problems here.
>
> 1) This will link the axes of all plots in a canvas since all I've done
> is
> get rid of the checks for a.in_axes()
>
> 2) This worked well for panning, but zooming caused all subplots to
> zoom
> from the same global point, rather than from the same point in each of
> their
> respective axes.
>
>
>
> Can anyone suggest a workaround?
>
>
>
> Much thanks!
>
> -Adam
>
>
>
> from matplotlib.backends.backend_wxagg import NavigationToolbar2WxAgg
> as
> NavigationToolbar
>
> class MyNavToolbar(NavigationToolbar):
>
> def __init__(self, canvas, cpfig):
>
> NavigationToolbar.__init__(self, canvas)
>
>
>
> # override
>
> def press_pan(self, event):
>
> 'the press mouse button in pan/zoom mode callback'
>
>
>
> if event.button == 1:
>
> self._button_pressed=1
>
> elif event.button == 3:
>
> self._button_pressed=3
>
> else:
>
> self._button_pressed=None
>
> return
>
>
>
> x, y = event.x, event.y
>
>
>
> # push the current view to define home if stack is empty
>
> if self._views.empty(): self.push_current()
>
>
>
> self._xypress=
>
> for i, a in enumerate(self.canvas.figure.get_axes()):
>
> # only difference from overridden method is that this one
> doesn't
>
> # check a.in_axes(event)
>
> if x is not None and y is not None and a.get_navigate():
>
> a.start_pan(x, y, event.button)
>
> self._xypress.append((a, i))
>
> self.canvas.mpl_disconnect(self._idDrag)
>
>
> self._idDrag=self.canvas.mpl_connect('motion_notify_event',
> self.drag_pan)
>
>
>
> def press_zoom(self, event):
>
> 'the press mouse button in zoom to rect mode callback'
>
> if event.button == 1:
>
> self._button_pressed=1
>
> elif event.button == 3:
>
> self._button_pressed=3
>
> else:
>
> self._button_pressed=None
>
> return
>
>
>
> x, y = event.x, event.y
>
>
>
> # push the current view to define home if stack is empty
>
> if self._views.empty(): self.push_current()
>
>
>
> self._xypress=
>
> for i, a in enumerate(self.canvas.figure.get_axes()):
>
> # only difference from overridden method is that this one
> doesn't
>
> # check a.in_axes(event)
>
> if x is not None and y is not None and a.get_navigate() and
> a.can_zoom():
>
> self._xypress.append(( x, y, a, i, a.viewLim.frozen(),
> a.transData.frozen()))
>
>
>
> self.press(event)
>
>
>
>
>
>
>
>
> ------------------------------------------------------------------------------
>
>
> _______________________________________________
> Matplotlib-users mailing list
> Matplotlib-users@lists.sourceforge.net
> matplotlib-users List Signup and Options
>
>