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

On a related note, I have noticed an incompatibility between AxesGrid and Basemap. It appears that Basemap will explicitly set adjustable=‘box’ when it calls ax.set_aspect(), but AxesGrid will error out, saying that it has to be ‘datalim’. What are the implications of using ‘box-forced’ instead of ‘box’ in Basemap?

Ben Root

···

On Thu, May 27, 2010 at 1:59 PM, Jae-Joon Lee <lee.j.joon@…149…> 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@…855…> 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@…149…]

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



Matplotlib-users mailing list

Matplotlib-users@lists.sourceforge.net

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

If Basemap explicitly sets aspect=1 and adjustable="box" at the same
time, you cannot use this with any axes that shares its axis with
others (including the axes created by the AxesGrid).

You need to somehow avoid the set_aspect call with adjustable"box"
(you can set box-forced in stead).

-JJ

···

On Tue, Jun 1, 2010 at 2:45 PM, Benjamin Root <ben.root@...553...> wrote:

On a related note, I have noticed an incompatibility between AxesGrid and
Basemap. It appears that Basemap will explicitly set adjustable='box' when
it calls ax.set_aspect(), but AxesGrid will error out, saying that it has to
be 'datalim'. What are the implications of using 'box-forced' instead of
'box' in Basemap?

Ben Root

On Thu, May 27, 2010 at 1:59 PM, Jae-Joon Lee <lee.j.joon@...149...> 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@...855...> 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@…149…]
> 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
>
>

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

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

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

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

Right, that is sort of what I am asking. My thinking is that Basemap could use ‘box-forced’ instead of ‘box’ for the adjustable parameter in order to make it and AxesGrid compatible. Usually, if one wants to use AxesGrid, they all should have the same domain and aspect ratio. I just have no clue what sort of repricussions that has for other use cases.

So far, this has worked just fine for me, but I hardly represent the normal use cases of Basemap and AxesGrid.

Ben Root

···

On Tue, Jun 1, 2010 at 5:20 PM, Jae-Joon Lee <lee.j.joon@…149…> wrote:

If Basemap explicitly sets aspect=1 and adjustable=“box” at the same

time, you cannot use this with any axes that shares its axis with

others (including the axes created by the AxesGrid).

You need to somehow avoid the set_aspect call with adjustable"box"

(you can set box-forced in stead).

-JJ

On Tue, Jun 1, 2010 at 2:45 PM, Benjamin Root <ben.root@…553…> wrote:

On a related note, I have noticed an incompatibility between AxesGrid and

Basemap. It appears that Basemap will explicitly set adjustable=‘box’ when

it calls ax.set_aspect(), but AxesGrid will error out, saying that it has to

be ‘datalim’. What are the implications of using ‘box-forced’ instead of

‘box’ in Basemap?

Ben Root

On Thu, May 27, 2010 at 1:59 PM, Jae-Joon Lee <lee.j.joon@…149…> 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@…855…> 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@…149…]

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



Matplotlib-users mailing list

Matplotlib-users@lists.sourceforge.net

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



Matplotlib-devel mailing list

Matplotlib-devel@lists.sourceforge.net

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



Matplotlib-devel mailing list

Matplotlib-devel@lists.sourceforge.net

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

Has anybody given any further thought to the implication of having Basemap set adjustable as “box-forced” instead of “box”? So far, it has been working just fine for me, but I have no clue if there are any unintended side-effects.

Ben Root

···

On Tue, Jun 1, 2010 at 6:00 PM, Benjamin Root <ben.root@…553…> wrote:

Right, that is sort of what I am asking. My thinking is that Basemap could use ‘box-forced’ instead of ‘box’ for the adjustable parameter in order to make it and AxesGrid compatible. Usually, if one wants to use AxesGrid, they all should have the same domain and aspect ratio. I just have no clue what sort of repricussions that has for other use cases.

So far, this has worked just fine for me, but I hardly represent the normal use cases of Basemap and AxesGrid.

Ben Root

On Tue, Jun 1, 2010 at 5:20 PM, Jae-Joon Lee <lee.j.joon@…149…> wrote:

If Basemap explicitly sets aspect=1 and adjustable=“box” at the same

time, you cannot use this with any axes that shares its axis with

others (including the axes created by the AxesGrid).

You need to somehow avoid the set_aspect call with adjustable"box"

(you can set box-forced in stead).

-JJ

On Tue, Jun 1, 2010 at 2:45 PM, Benjamin Root <ben.root@…553…> wrote:

On a related note, I have noticed an incompatibility between AxesGrid and

Basemap. It appears that Basemap will explicitly set adjustable=‘box’ when

it calls ax.set_aspect(), but AxesGrid will error out, saying that it has to

be ‘datalim’. What are the implications of using ‘box-forced’ instead of

‘box’ in Basemap?

Ben Root

On Thu, May 27, 2010 at 1:59 PM, Jae-Joon Lee <lee.j.joon@…149…> 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@…855…> 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@…149…]

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



Matplotlib-users mailing list

Matplotlib-users@lists.sourceforge.net

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



Matplotlib-devel mailing list

Matplotlib-devel@lists.sourceforge.net

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



Matplotlib-devel mailing list

Matplotlib-devel@lists.sourceforge.net

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

Has anybody given any further thought to the implication of having
Basemap set adjustable as "box-forced" instead of "box"? So far, it has
been working just fine for me, but I have no clue if there are any
unintended side-effects.

My sense is that box-forced lets you shoot yourself in the foot with shared axes, box doesn't. The reason I prohibited sharing x and y axes with adjustable as box is that it is not clear what should happen, or will happen--fundamental inconsistencies can arise. Suppose you have two axes sharing x and y. You set aspect to 1 for the first and 2 for the second. The first axes is drawn, executing apply_aspect and setting the box dimensions accordingly. Then the second is drawn, also executing apply_aspect. It is inconsistent with the first. There is no solution that satisfies all constraints. The basic point is that when using apply_aspect with adjustable as box, you have to have freedom to change one of the axes, and this is not in general consistent with sharing both axes--though it may be in particular cases.

Very likely there is a way of refining the logic, but beware: getting aspect ratio control to work under a wide range of conditions, including all sorts of zooming and resizing, is tricky and laborious. It is much easier to break it than to fix it, and the breakage can be hard to spot.

Eric

···

On 06/09/2010 09:58 AM, Benjamin Root wrote:

Ben Root

On Tue, Jun 1, 2010 at 6:00 PM, Benjamin Root <ben.root@...553... > <mailto:ben.root@…553…>> wrote:

    Right, that is sort of what I am asking. My thinking is that
    Basemap could use 'box-forced' instead of 'box' for the adjustable
    parameter in order to make it and AxesGrid compatible. Usually, if
    one wants to use AxesGrid, they all should have the same domain and
    aspect ratio. I just have no clue what sort of repricussions that
    has for other use cases.

    So far, this has worked just fine for me, but I hardly represent the
    normal use cases of Basemap and AxesGrid.

    Ben Root

    On Tue, Jun 1, 2010 at 5:20 PM, Jae-Joon Lee <lee.j.joon@...149... > <mailto:lee.j.joon@…149…>> wrote:

        If Basemap explicitly sets aspect=1 and adjustable="box" at the same
        time, you cannot use this with any axes that shares its axis with
        others (including the axes created by the AxesGrid).

        You need to somehow avoid the set_aspect call with adjustable"box"
        (you can set box-forced in stead).

        -JJ

        On Tue, Jun 1, 2010 at 2:45 PM, Benjamin Root <ben.root@...553... > <mailto:ben.root@…553…>> wrote:
         >
         > On a related note, I have noticed an incompatibility between
        AxesGrid and
         > Basemap. It appears that Basemap will explicitly set
        adjustable='box' when
         > it calls ax.set_aspect(), but AxesGrid will error out, saying
        that it has to
         > be 'datalim'. What are the implications of using
        'box-forced' instead of
         > 'box' in Basemap?
         >
         > Ben Root
         >
         > On Thu, May 27, 2010 at 1:59 PM, Jae-Joon Lee > <lee.j.joon@...149... <mailto:lee.j.joon@…149…>> 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@...855... > <mailto:PHobson@…855…>> 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@…149…
        <mailto:adam.n.fraser@…149…>]
         >> > 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
        <mailto:Matplotlib-users@lists.sourceforge.net>
         >> > matplotlib-users List Signup and Options
         >> >
         >>
        ------------------------------------------------------------------------------
         >>
         >> _______________________________________________
         >> Matplotlib-users mailing list
         >> Matplotlib-users@lists.sourceforge.net
        <mailto:Matplotlib-users@lists.sourceforge.net>
         >> matplotlib-users List Signup and Options
         >
        ------------------------------------------------------------------------------
         >
         > _______________________________________________
         > Matplotlib-devel mailing list
         > Matplotlib-devel@lists.sourceforge.net
        <mailto:Matplotlib-devel@lists.sourceforge.net>
         > matplotlib-devel List Signup and Options
         >

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

        _______________________________________________
        Matplotlib-devel mailing list
        Matplotlib-devel@lists.sourceforge.net
        <mailto:Matplotlib-devel@lists.sourceforge.net>
        matplotlib-devel List Signup and Options

------------------------------------------------------------------------------
ThinkGeek and WIRED's GeekDad team up for the Ultimate
GeekDad Father's Day Giveaway. ONE MASSIVE PRIZE to the
lucky parental unit. See the prize list and enter to win:
http://p.sf.net/sfu/thinkgeek-promo

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

"box-forced" must be only used in a very limited cases when axes
sharing is okay.
For example, when both x and y axis are shared and both axes have same
aspect ratio and the original axes position of both axes have same
width and height.

Hm, maybe it is better to limit the visibility of the "box-forced"
option from normal users.

For the issue of the Basemap using

        ax.set_aspect('equal',adjustable='box',anchor=self.anchor)

I think (adjustable="box") is not necessary here. Simply using

        ax.set_aspect('equal',anchor=self.anchor)

should work and it will also resolve the compatibility issue with
axes_grid toolkit.

But this issue should be addressed by Jeff. I'm not quite familiar with Basemap.

Regards,

-JJ

···

On Wed, Jun 9, 2010 at 4:18 PM, Eric Firing <efiring@...229...> wrote:

My sense is that box-forced lets you shoot yourself in the foot with
shared axes, box doesn't. The reason I prohibited sharing x and y axes
with adjustable as box is that it is not clear what should happen, or
will happen--fundamental inconsistencies can arise. Suppose you have
two axes sharing x and y. You set aspect to 1 for the first and 2 for
the second. The first axes is drawn, executing apply_aspect and setting
the box dimensions accordingly. Then the second is drawn, also
executing apply_aspect. It is inconsistent with the first. There is no
solution that satisfies all constraints. The basic point is that when
using apply_aspect with adjustable as box, you have to have freedom to
change one of the axes, and this is not in general consistent with
sharing both axes--though it may be in particular cases.

Very likely there is a way of refining the logic, but beware: getting
aspect ratio control to work under a wide range of conditions, including
all sorts of zooming and resizing, is tricky and laborious. It is much
easier to break it than to fix it, and the breakage can be hard to spot.

Eric

My sense is that box-forced lets you shoot yourself in the foot with
shared axes, box doesn't. The reason I prohibited sharing x and y axes
with adjustable as box is that it is not clear what should happen, or
will happen--fundamental inconsistencies can arise. Suppose you have
two axes sharing x and y. You set aspect to 1 for the first and 2 for
the second. The first axes is drawn, executing apply_aspect and setting
the box dimensions accordingly. Then the second is drawn, also
executing apply_aspect. It is inconsistent with the first. There is no
solution that satisfies all constraints. The basic point is that when
using apply_aspect with adjustable as box, you have to have freedom to
change one of the axes, and this is not in general consistent with
sharing both axes--though it may be in particular cases.

Very likely there is a way of refining the logic, but beware: getting
aspect ratio control to work under a wide range of conditions, including
all sorts of zooming and resizing, is tricky and laborious. It is much
easier to break it than to fix it, and the breakage can be hard to spot.

Eric

"box-forced" must be only used in a very limited cases when axes
sharing is okay.
For example, when both x and y axis are shared and both axes have same
aspect ratio and the original axes position of both axes have same
width and height.

Hm, maybe it is better to limit the visibility of the "box-forced"
option from normal users.

For the issue of the Basemap using

         ax.set_aspect('equal',adjustable='box',anchor=self.anchor)

I think (adjustable="box") is not necessary here. Simply using

         ax.set_aspect('equal',anchor=self.anchor)

should work and it will also resolve the compatibility issue with
axes_grid toolkit.

But this issue should be addressed by Jeff. I'm not quite familiar with Basemap.

Jeff can correct me if I am wrong, but I think adjustable='box' is essential for basemap because the maximum data limits are set when the Basemap instance is created. In some cases the characteristics of the projection, and in all cases the extraction of coastlines, is set at instantiation time. You can zoom in to show smaller regions, but you don't want apply_aspect to expand the data limits beyond their initial values.

Eric

···

On 06/09/2010 10:53 AM, Jae-Joon Lee wrote:

On Wed, Jun 9, 2010 at 4:18 PM, Eric Firing<efiring@...229...> wrote:

Regards,

-JJ

------------------------------------------------------------------------------
ThinkGeek and WIRED's GeekDad team up for the Ultimate
GeekDad Father's Day Giveaway. ONE MASSIVE PRIZE to the
lucky parental unit. See the prize list and enter to win:
http://p.sf.net/sfu/thinkgeek-promo
_______________________________________________
Matplotlib-devel mailing list
Matplotlib-devel@lists.sourceforge.net
matplotlib-devel List Signup and Options

I think that, as axes in matplotlib, by default, has adjustable='box',
it should be okay without explicitly setting adjustable='box' in most
cases.

With explicit adjustable='bbox',

* you will fix when a user accidentally provided an axes with wrong
adjustable value.
* On the other hand, you will prohibit any axes sharing when Basemap
is used (there are cases when axes sharing is fine even if the aspect
is set to "equal").

So, I guess my point is that it might be good in this case to let the
user be responsible for what he is doing.
Since I'm not a regular Basemap user, it is just my point of view
(which might be wrong) from the outside.

Regards,

-JJ

···

On Wed, Jun 9, 2010 at 6:22 PM, Eric Firing <efiring@...229...> wrote:

Jeff can correct me if I am wrong, but I think adjustable='box' is
essential for basemap because the maximum data limits are set when the
Basemap instance is created. In some cases the characteristics of the
projection, and in all cases the extraction of coastlines, is set at
instantiation time. You can zoom in to show smaller regions, but you
don't want apply_aspect to expand the data limits beyond their initial
values.