GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — pan and zoom are broken for mplot3d · Issue #110 · matplotlib/matplotlib

pan and zoom are broken for mplot3d #110

New issue
Copy link
New issue
Copy link
Closed
#23449
Closed
pan and zoom are broken for mplot3d#110
#23449
Copy link
Assignees
WeatherGod
Labels
status: confirmed bugtopic: mplot3d
Milestone
v3.7.0

Description

@WeatherGod
WeatherGod
opened on May 10, 2011
Issue body actions

Chances are, this will probably fall on me to address, but I am documenting it here in case someone else realizes the issue.

When creating 3d axes in the old manner (ie, ax = Axes3D(fig)), the panning and zooming features are completely useless and often produces incomprehensible results. Axes created in the newer manner (ie, ax = fig.gca(projection='3d')) has somewhat better behavior, but still quite useless.

While pan and zoom has never really been properly supported in mplot3d, the current behavior is significantly worse than before. I suspect that there might be some interactions with a variety of changes. First, there were some changes to figure object itself, which may have not been properly tested with non-subplotted axes (which would explain differences in behavior between the old style and new style). Second, I suspect that some changes to the clipping logic for Agg might be causing some of the issues with zooming and panning.

I think I will temporarily address this issue by disabling pan and zoom for Axes3D objects. I also want to make the Home button capable of returning the figure view back to normal. It does not appear to do this right now.

Activity

  1. ghost assigned
    WeatherGod
    on Jun 22, 2011
  2. WeatherGod commented on Jul 11, 2011

    @WeatherGod
    WeatherGod
    on Jul 11, 2011
    MemberAuthor
    More actions

    This is partially resolved by disabling the zoom feature (through the button). Note that zooming is still possible by right-clicking the figure and dragging the mouse up and down.

    Disabling the Pan feature is trickier...

  3. WeatherGod
    added a commit that references this issue on Jul 14, 2011

    Added a "can_pan()" function and included it in the generic panning l…

    fcd9fd8
  4. WeatherGod commented on Sep 23, 2011

    @WeatherGod
    WeatherGod
    on Sep 23, 2011
    MemberAuthor
    More actions

    I am going to declare this issue closed with the current work-around in place in master.

  5. WeatherGod
    closed this as completedon Sep 23, 2011
  6. orzechow commented on Jul 16, 2015

    @orzechow
    orzechow
    on Jul 16, 2015
    More actions

    Pan and home button still don't work - any progress on this?
    Especially the pan feature is important for me. I am analyzing 3d data which contains noise / outliers, that scale away the interesting part of the figure. It's not enough only to zoom to the center of the data. I need to pan/move the data/camera in order to zoom into an interesting region.

    Reacted by Hao LI
  7. WeatherGod commented on Jul 16, 2015

    @WeatherGod
    WeatherGod
    on Jul 16, 2015
    MemberAuthor
    More actions

    This is likely to be addressed in version 2.1 as a part of the toolbar refactor. We will be able to dynamically add toolbar buttons with the new architecture, which would be required for this to work properly, I think. The timeline for version 2.1 will be next april, unfortunately.

    In the meantime, you might be interested in the vispy project which has made great strides in interactive visualizations that matplotlib cannot currently do, particularly for 3D. The long-term plan is to eventually integrate matplotlib and vispy together in some form, but that is a few years away.

  8. orzechow commented on Jul 17, 2015

    @orzechow
    orzechow
    on Jul 17, 2015
    More actions

    Thanks for the news!
    Unfortunately I need a solution within the next three months.

    Didn't know about vispy (but mayavi), which looks promising. Though it lacks axes that are necessary for proper analysis and scientific publication. I found that they are scheduled for the next version update end of September, but there is no info how they will behave.

    Until now I found no tool that is capable of plotting 3d data for analysis and publication, meaning with

    • an interactive GUI, that supports
      • (intuitive) pan/move, zoom (like mayavi)
      • preserving plot properties like line width etc. on zoom (not like mayavi where lines grow bigger on zoom)
      • axes that properly handle pan/zoom interaction (like mplot3d or gnuplot, not even matlab deals with this correctly)
      • axes that maintain a given ratio
    • nice formatting (I know this is very vague)
    • file export in vector image formats

    Looks like I need to use separate tools for those two tasks.

  9. fermrav commented on Feb 20, 2018

    @fermrav
    fermrav
    on Feb 20, 2018
    More actions

    Hello guys,

    I strongly disagree, that moving in figure makes no sense! General overview of your plotted data is not enough, espetially if you want to check some tiny details on the corner of your figure!

    On the other hand its true, that determine way to move with mouse make no sense, because of differences in 2D mouse and 3D graph (is 2D mouse close to myself, or inside of data yet?).

    I spent nearly 16 hours with solving issue, how to move in graph. (Where is list of Matplotlib keys? Why given examples wont work? Etc., etc. Documentation is complicated, unclear, and completely not friendly to use!!!)

    I found this tricky solution, maybe it someone found usefull. It works both for 2D and 3D, therefore there is added variable to determine, which view you actually use. The code is fairly straightforward, I am pretty sure, that you will be able to adjust it to your own without any issues.

    If you move data, in which you are interested in, in center of figure, then you will be able to zoom to them and view exactly them in details. (Note below).

        def move_view(event):
                ax.autoscale(enable=False, axis='both')  # I have no idea, it this line have some effect at all
                ## Set nearly similar speed of motion in dependency on zoom
                if view_2D:
                    koef = 4.  ## Speed for 2D should be higher
                else:
                    koef = 8.  ## speed for 3D should be lower
                    zkoef = (ax.get_zbound()[0] - ax.get_zbound()[1]) / koef
    
                xkoef = (ax.get_xbound()[0] - ax.get_xbound()[1]) / koef
                ykoef = (ax.get_ybound()[0] - ax.get_ybound()[1]) / koef
    
                ## Map an motion to keyboard shortcuts
                if event.key == "ctrl+down":
                    ax.set_ybound(ax.get_ybound()[0] + xkoef, ax.get_ybound()[1] + xkoef)
                if event.key == "ctrl+up":
                    ax.set_ybound(ax.get_ybound()[0] - xkoef, ax.get_ybound()[1] - xkoef)
                if event.key == "ctrl+right":
                    ax.set_xbound(ax.get_xbound()[0] + ykoef, ax.get_xbound()[1] + ykoef)
                if event.key == "ctrl+left":
                    ax.set_xbound(ax.get_xbound()[0] - ykoef, ax.get_xbound()[1] - ykoef)
                if not view_2D:
                    if event.key == "down":
                        ax.set_zbound(ax.get_zbound()[0] - zkoef, ax.get_zbound()[1] - zkoef)
                    if event.key == "up":
                        ax.set_zbound(ax.get_zbound()[0] + zkoef, ax.get_zbound()[1] + zkoef)
                # print event.key
    
            fig.canvas.mpl_connect("key_press_event", move_view)

    Like that its mapped to arrows on keyboard. I wasnt able to override default Matplotlib shortcuts through key_press_event, so its mapped to "ctrl", which is not comfortable, but I dont know better solution for now. If you want to change keyboard shortcut and you dont know the name for it, just uncomment last line. After run your script, you can see proper name for pressed key (or key combination), by pressing key on the (focused) figure.

    Note, that if you want to change the direction of motion, it is necessary to change both of signs before each koef. Otherwise it zooms, instead of move.

    It is obvious, that move direction will be still in the same axes, independently on your view.

    This code should be placed anywhere before plt.show()

    Note below: To determine a center of graph I tried an callback function to draw an cross in the middle of graph, but it behave a bit strange in Z-axes, I am unsure, why. Function is below. Maybe is good idea to map it to key_release_event, if in Matplotlib exists any.

    self.midptcurs = None ## it should be OUT of function scope, 
        ##because we need to persist pointer to previous position cross
            def showmidp(event):
                if view_2D:
                    midpt = [(ax.get_xbound()[1] + ax.get_xbound()[0]) / 2., (ax.get_ybound()[1] + ax.get_ybound()[0]) / 2.]
                else:
                    midpt = [(ax.get_xbound()[1] + ax.get_xbound()[0]) / 2.,
                                  (ax.get_ybound()[1] + ax.get_ybound()[0]) / 2.,
                                  (ax.get_zbound()[1] + ax.get_zbound()[0]) / 2.,]
    
                try:
                    self.midptcurs.remove()
                except AttributeError:  ## To prevent raise error, when first position is not known
                    pass
    
                if view_2D:
                    self.midptcurs = ax.scatter(midpt[0], midpt[1], marker="+", s=30, c="black")
                else:
                    self.midptcurs = ax.scatter(midpt[0], midpt[1], midpt[2], marker="+", s=30, c="black")

    Hope it helps and at least temporarily solve an issue.

    (And forgive me eventually code spaces errors, I am here completely newbie. This issue makes me so angry, that I decide to share solution and therefore I make my account here... :) )

    Reacted by woliveirax
  10. sleepyhollo commented on Jul 4, 2019

    @sleepyhollo
    sleepyhollo
    on Jul 4, 2019
    More actions

    This is partially resolved by disabling the zoom feature (through the button). Note that zooming is still possible by right-clicking the figure and dragging the mouse up and down.

    Disabling the Pan feature is trickier...

    I think the fix from fcd9fd8 is no longer valid as I can zoom but not pan. So perhaps the False returns from ax.can_pan() and ax.can_zoom() should be changed. I am using Matplotlib 3.1.0 with python 3.7.3.

    I came across this issue while searching for "pan matplotlib 3d" in google. I am trying to pan a 3d plot, but I cannot do it from the plot window. I also found this stackoverflow question about someone who can pan but cannot zoom.

  11. timhoffm commented on Jul 4, 2019

    @timhoffm
    timhoffm
    on Jul 4, 2019
    Member
    More actions

    I confirm that one can zoom using the right mouse button. However it's not possible to zoom using the regular "draw a rectangle" method. Not sure if and how we should handle this.

    Reacted by Hao LI and Christofer (C.J.) McGinnis
  12. brunorpinho commented on Sep 20, 2019

    @brunorpinho
    brunorpinho
    on Sep 20, 2019
    More actions

    I confirm the same issue @sleepyhollo is having. I can zoom but I cannot pan. Using WebAgg backend. Matplotlib 3.1.1.

    I also confirm @timhoffm issue, none of the zoom/pan buttons seem to work. They all maintain the default zoom behavior.

    Reacted by Hao LI
  13. timhoffm
    reopened this on Oct 3, 2019
  14. woliveirax commented on Jun 20, 2020

    @woliveirax
    woliveirax
    on Jun 20, 2020
    More actions

    Hello guys,

    I strongly disagree, that moving in figure makes no sense! General overview of your plotted data is not enough, espetially if you want to check some tiny details on the corner of your figure!

    On the other hand its true, that determine way to move with mouse make no sense, because of differences in 2D mouse and 3D graph (is 2D mouse close to myself, or inside of data yet?).

    I spent nearly 16 hours with solving issue, how to move in graph. (Where is list of Matplotlib keys? Why given examples wont work? Etc., etc. Documentation is complicated, unclear, and completely not friendly to use!!!)

    I found this tricky solution, maybe it someone found usefull. It works both for 2D and 3D, therefore there is added variable to determine, which view you actually use. The code is fairly straightforward, I am pretty sure, that you will be able to adjust it to your own without any issues.

    If you move data, in which you are interested in, in center of figure, then you will be able to zoom to them and view exactly them in details. (Note below).

        def move_view(event):
                ax.autoscale(enable=False, axis='both')  # I have no idea, it this line have some effect at all
                ## Set nearly similar speed of motion in dependency on zoom
                if view_2D:
                    koef = 4.  ## Speed for 2D should be higher
                else:
                    koef = 8.  ## speed for 3D should be lower
                    zkoef = (ax.get_zbound()[0] - ax.get_zbound()[1]) / koef
    
                xkoef = (ax.get_xbound()[0] - ax.get_xbound()[1]) / koef
                ykoef = (ax.get_ybound()[0] - ax.get_ybound()[1]) / koef
    
                ## Map an motion to keyboard shortcuts
                if event.key == "ctrl+down":
                    ax.set_ybound(ax.get_ybound()[0] + xkoef, ax.get_ybound()[1] + xkoef)
                if event.key == "ctrl+up":
                    ax.set_ybound(ax.get_ybound()[0] - xkoef, ax.get_ybound()[1] - xkoef)
                if event.key == "ctrl+right":
                    ax.set_xbound(ax.get_xbound()[0] + ykoef, ax.get_xbound()[1] + ykoef)
                if event.key == "ctrl+left":
                    ax.set_xbound(ax.get_xbound()[0] - ykoef, ax.get_xbound()[1] - ykoef)
                if not view_2D:
                    if event.key == "down":
                        ax.set_zbound(ax.get_zbound()[0] - zkoef, ax.get_zbound()[1] - zkoef)
                    if event.key == "up":
                        ax.set_zbound(ax.get_zbound()[0] + zkoef, ax.get_zbound()[1] + zkoef)
                # print event.key
    
            fig.canvas.mpl_connect("key_press_event", move_view)

    Like that its mapped to arrows on keyboard. I wasnt able to override default Matplotlib shortcuts through key_press_event, so its mapped to "ctrl", which is not comfortable, but I dont know better solution for now. If you want to change keyboard shortcut and you dont know the name for it, just uncomment last line. After run your script, you can see proper name for pressed key (or key combination), by pressing key on the (focused) figure.

    Note, that if you want to change the direction of motion, it is necessary to change both of signs before each koef. Otherwise it zooms, instead of move.

    It is obvious, that move direction will be still in the same axes, independently on your view.

    This code should be placed anywhere before plt.show()

    Note below: To determine a center of graph I tried an callback function to draw an cross in the middle of graph, but it behave a bit strange in Z-axes, I am unsure, why. Function is below. Maybe is good idea to map it to key_release_event, if in Matplotlib exists any.

    self.midptcurs = None ## it should be OUT of function scope, 
        ##because we need to persist pointer to previous position cross
            def showmidp(event):
                if view_2D:
                    midpt = [(ax.get_xbound()[1] + ax.get_xbound()[0]) / 2., (ax.get_ybound()[1] + ax.get_ybound()[0]) / 2.]
                else:
                    midpt = [(ax.get_xbound()[1] + ax.get_xbound()[0]) / 2.,
                                  (ax.get_ybound()[1] + ax.get_ybound()[0]) / 2.,
                                  (ax.get_zbound()[1] + ax.get_zbound()[0]) / 2.,]
    
                try:
                    self.midptcurs.remove()
                except AttributeError:  ## To prevent raise error, when first position is not known
                    pass
    
                if view_2D:
                    self.midptcurs = ax.scatter(midpt[0], midpt[1], marker="+", s=30, c="black")
                else:
                    self.midptcurs = ax.scatter(midpt[0], midpt[1], midpt[2], marker="+", s=30, c="black")

    Hope it helps and at least temporarily solve an issue.

    (And forgive me eventually code spaces errors, I am here completely newbie. This issue makes me so angry, that I decide to share solution and therefore I make my account here... :) )

    This was of great help, thank you!

    EDIT:
    I made the following changes to your event, since I'm not using 2D views:
    I also added the the redraw function at the end, as to see the changes when the even is called.

    >     def move_view(event):
    >             ax.autoscale(enable=False, axis='both')  # I have no idea, it this line have some effect at all
    >             ## Set nearly similar speed of motion in dependency on zoom
    >             koef = 8.  ## speed for 3D should be lower
    >             zkoef = (ax.get_zbound()[0] - ax.get_zbound()[1]) / koef
    > 
    >             xkoef = (ax.get_xbound()[0] - ax.get_xbound()[1]) / koef
    >             ykoef = (ax.get_ybound()[0] - ax.get_ybound()[1]) / koef
    > 
    >             ## Map an motion to keyboard shortcuts
    >             if event.key == "ctrl+down":
    >                 ax.set_ybound(ax.get_ybound()[0] + xkoef, ax.get_ybound()[1] + xkoef)
    >             if event.key == "ctrl+up":
    >                 ax.set_ybound(ax.get_ybound()[0] - xkoef, ax.get_ybound()[1] - xkoef)
    >             if event.key == "ctrl+right":
    >                 ax.set_xbound(ax.get_xbound()[0] + ykoef, ax.get_xbound()[1] + ykoef)
    >             if event.key == "ctrl+left":
    >                 ax.set_xbound(ax.get_xbound()[0] - ykoef, ax.get_xbound()[1] - ykoef)
    >             if event.key == "down":
    >                 ax.set_zbound(ax.get_zbound()[0] - zkoef, ax.get_zbound()[1] - zkoef)
    >             if event.key == "up":
    >                 ax.set_zbound(ax.get_zbound()[0] + zkoef, ax.get_zbound()[1] + zkoef)
    >             
    >              ax.figure.canvas.draw()
    >             # print event.key
    > ```
    
    Thanks again, you are a life saver!
  15. timhoffm commented on Nov 1, 2020

    @timhoffm
    timhoffm
    on Nov 1, 2020
    Member
    More actions

    Update as of 3.4 (yet to be released):

    • You can pan by moving the mouse while the middle mouse button is pressed (axes3d panning #18536).
    • You can zoom by moving the mouse while the right mouse button is pressed.
    • Still open: The standard "zoom" and "pan" tools from the toolbar do not work. - What should we do about this?
    Reacted by Robert Pollak, BaptisteDebes and weida wang
    Reacted by BaptisteDebes
    Reacted by BaptisteDebes
    Reacted by BaptisteDebes
  16. oscargus
    closed this as completedin #23449on Oct 10, 2022
  17. QuLogic
    modified the milestones: v1.1.0, v3.7.0 on Oct 12, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

  • @WeatherGod
    WeatherGod

Labels

status: confirmed bugtopic: mplot3d

Type

No type

Projects

No projects

    Milestone

    • v3.7.0

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

    You are visitor 01402503 — GeezerVison does not store the pages you look up.
    Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.