(event, canvas=None, toolbar=None)
| 2633 | |
| 2634 | |
| 2635 | def scroll_handler(event, canvas=None, toolbar=None): |
| 2636 | ax = event.inaxes |
| 2637 | if ax is None: |
| 2638 | return |
| 2639 | if ax.name != "rectilinear": |
| 2640 | # zooming is currently only supported on rectilinear axes |
| 2641 | return |
| 2642 | |
| 2643 | if toolbar is None: |
| 2644 | toolbar = (canvas or event.canvas).toolbar |
| 2645 | |
| 2646 | if toolbar is None: |
| 2647 | # technically we do not need a toolbar, but until wheel zoom was |
| 2648 | # introduced, any interactive modification was only possible through |
| 2649 | # the toolbar tools. For now, we keep the restriction that a toolbar |
| 2650 | # is required for interactive navigation. |
| 2651 | return |
| 2652 | |
| 2653 | if event.key in {"control", "x", "y"}: # zoom towards the mouse position |
| 2654 | toolbar.push_current() |
| 2655 | |
| 2656 | xmin, xmax = ax.get_xlim() |
| 2657 | ymin, ymax = ax.get_ylim() |
| 2658 | (xmin, ymin), (xmax, ymax) = ax.transScale.transform( |
| 2659 | [(xmin, ymin), (xmax, ymax)]) |
| 2660 | |
| 2661 | # mouse position in scaled (e.g., log) data coordinates |
| 2662 | x, y = ax.transScale.transform((event.xdata, event.ydata)) |
| 2663 | |
| 2664 | scale_factor = 0.85 ** event.step |
| 2665 | # Determine which axes to scale based on key |
| 2666 | zoom_x = event.key in {"control", "x"} |
| 2667 | zoom_y = event.key in {"control", "y"} |
| 2668 | |
| 2669 | if zoom_x: |
| 2670 | new_xmin = x - (x - xmin) * scale_factor |
| 2671 | new_xmax = x + (xmax - x) * scale_factor |
| 2672 | else: |
| 2673 | new_xmin, new_xmax = xmin, xmax |
| 2674 | |
| 2675 | if zoom_y: |
| 2676 | new_ymin = y - (y - ymin) * scale_factor |
| 2677 | new_ymax = y + (ymax - y) * scale_factor |
| 2678 | else: |
| 2679 | new_ymin, new_ymax = ymin, ymax |
| 2680 | |
| 2681 | inv_scale = ax.transScale.inverted() |
| 2682 | (new_xmin, new_ymin), (new_xmax, new_ymax) = inv_scale.transform( |
| 2683 | [(new_xmin, new_ymin), (new_xmax, new_ymax)]) |
| 2684 | |
| 2685 | ax.set_xlim(new_xmin, new_xmax) |
| 2686 | ax.set_ylim(new_ymin, new_ymax) |
| 2687 | |
| 2688 | ax.figure.canvas.draw_idle() |
| 2689 | |
| 2690 | |
| 2691 | class NonGuiException(Exception): |
nothing calls this directly
no test coverage detected
searching dependent graphs…