get aspect ratio of axes

前端 未结 4 1658
[愿得一人]
[愿得一人] 2020-12-06 11:49

Is there an easy and reliable way to determine the current aspect ratio of an axes when its aspect is set to \'auto\'?

The obvious thing to

相关标签:
4条回答
  • 2020-12-06 12:26

    How about

    import numpy as np
    aspect = sum(np.abs(ax.get_xlim())) / sum(np.abs(ax.get_ylim()))
    
    0 讨论(0)
  • 2020-12-06 12:37

    The best thing I can find is this:

    def get_aspect(ax=None):
        if ax is None:
            ax = plt.gca()
        fig = ax.figure
    
        ll, ur = ax.get_position() * fig.get_size_inches()
        width, height = ur - ll
        axes_ratio = height / width
        aspect = axes_ratio / ax.get_data_ratio()
    
        return aspect
    

    But it's surprisingly complicated, and I'm not sure if it is reliable under transforms, etc, as I know nothing about the bbox and transform objects.

    0 讨论(0)
  • 2020-12-06 12:39

    I am not sure if it does exactly what you want, but try it

        bbox = axis.get_window_extent().transformed(figure.dpi_scale_trans.inverted())
        aspect_ratio = bbox.width / bbox.height
    
    0 讨论(0)
  • 2020-12-06 12:42

    From the docs, the aspect ratio is the ratio of data-to-display scaling units in the x- and y-axes. i.e., if there are 10 data units per display in the y-direction and 1 data unit per display unit in the x-direction, the ratio would be 1/10. The circle would be 10 times wider than it is tall. This corresponds to the statement that an aspect of num does the following:

    a circle will be stretched such that the height is num times the width. aspect=1 is the same as aspect=’equal’.

    Based on the same original piece of code that you looked at (matplotlib.axes._base.adjust_aspect, starting around line 1405), I think we can come up with a simplified formula as long as you only need this ratio for linear Cartesian axes. Things get complicated with polar and logarithmic axes, so I will ignore them.

    To reiterate the formula:

    (x_data_unit / x_display_unit) / (y_data_unit / y_display_unit)
    

    This happens to be the same as

    (y_display_unit / x_display_unit) / (y_data_unit / x_data_unit)
    

    This last formulation is just the ratio of the display sizes in the two directions divided by the ratio of the x and y limits. Note that ax.get_data_ratio does NOT apply here because that returns the results for the actual data bounds, not the axis limits at all:

    from operator import sub
    def get_aspect(ax):
        # Total figure size
        figW, figH = ax.get_figure().get_size_inches()
        # Axis size on figure
        _, _, w, h = ax.get_position().bounds
        # Ratio of display units
        disp_ratio = (figH * h) / (figW * w)
        # Ratio of data units
        # Negative over negative because of the order of subtraction
        data_ratio = sub(*ax.get_ylim()) / sub(*ax.get_xlim())
    
        return disp_ratio / data_ratio
    

    Now let's test it:

    from matplotlib import pyplot as plt
    fig, ax = plt.subplots()
    ax.set_aspect('equal')
    print('{} == {}'.format(ax.get_aspect(), get_aspect(ax)))
    ax.set_aspect(10)
    print('{} == {}'.format(ax.get_aspect(), get_aspect(ax)))
    
    0 讨论(0)
提交回复
热议问题