Skip to content
  • Sponsor matplotlib/matplotlib

  • Notifications You must be signed in to change notification settings
  • Fork 7.9k

pan and zoom are broken for mplot3d #110

Closed
@WeatherGod

Description

@WeatherGod

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

WeatherGod

WeatherGod commented on Jul 11, 2011

@WeatherGod
MemberAuthor

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...

WeatherGod

WeatherGod commented on Sep 23, 2011

@WeatherGod
MemberAuthor

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

orzechow

orzechow commented on Jul 16, 2015

@orzechow

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.

WeatherGod

WeatherGod commented on Jul 16, 2015

@WeatherGod
MemberAuthor

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.

orzechow

orzechow commented on Jul 17, 2015

@orzechow

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.

fermrav

fermrav commented on Feb 20, 2018

@fermrav

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... :) )

sleepyhollo

sleepyhollo commented on Jul 4, 2019

@sleepyhollo

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.

timhoffm

timhoffm commented on Jul 4, 2019

@timhoffm
Member

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.

brunorpinho

brunorpinho commented on Sep 20, 2019

@brunorpinho

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.

9 remaining items

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions

    pan and zoom are broken for mplot3d · Issue #110 · matplotlib/matplotlib