简体   繁体   中英

How to make equal grid spacing with secondary axis in matplotlib?

I am trying to create a plot with equal grid spacing the first code I used is:

import numpy as np
import matplotlib.pyplot as plt
time= np.linspace (0, 25, 5000)
temp_pri = 50 / np.sqrt (2 * np.pi * 3**2) * np.exp (-((time - 13)**2 / (3**2))**2) + 15
temp_sec = 50 * np.sin(2* np.pi * time/100)
figure_x_y = plt.figure(figsize=(10, 10))
figure_x_y.clf()
plot_x_vs_y = plt.subplot(111)
plot_x_vs_y.plot(time, temp_pri, linewidth=1.0)
plot_x_vs_y.set_ylabel(r'\textit{Temperature (K)}', labelpad=6)
plot_x_vs_y.set_xlabel(r'\textit{Time (ms)}', labelpad=6)
# plot_x_vs_y.set_aspect('equal')
ax2 = plot_x_vs_y.twinx()
ax2.plot(time, temp_sec, color='#4DAF4A')
# ax2.set_aspect('equal')
plt.show()
plt.close()

and the output is I get is:

set_aspect('equal')选项关闭

When I set the option set_aspect('equal') option on, code:

import numpy as np
import matplotlib.pyplot as plt
time= np.linspace (0, 25, 5000)
temp_pri = 50 / np.sqrt (2 * np.pi * 3**2) * np.exp (-((time - 13)**2 / (3**2))**2) + 15
temp_sec = 50 * np.sin(2* np.pi * time/100)
figure_x_y = plt.figure(figsize=(10, 10))
figure_x_y.clf()
plot_x_vs_y = plt.subplot(111)
plot_x_vs_y.plot(time, temp_pri, linewidth=1.0)
plot_x_vs_y.set_ylabel(r'\textit{Temperature (K)}', labelpad=6)
plot_x_vs_y.set_xlabel(r'\textit{Time (ms)}', labelpad=6)
plot_x_vs_y.set_aspect('equal')
ax2 = plot_x_vs_y.twinx()
ax2.plot(time, temp_sec, color='#4DAF4A')
ax2.set_aspect('equal')
plt.show()
plt.close()

the output I get is:

set_aspect('equal')选项在

How can I get both (primary and secondary y-axis) the grid spacing to be the same?

If by "the same spacing" you mean that numbers on both y-axises are aligned then you could use .ylim() to set min/max ticks on both of the axises:

#plot_x_vs_y.set_ylim(10,25)  # This one is optional, manually set min/max for primary axis. 
lims = plot_x_vs_y.get_ylim() # Get min/max of primary y-axis 
ax2.set_ylim(lims)  # Set min/max of secondary y-axis
ax2.grid('off')  # You can turn the grid of secondary y-axis off
plt.show()

This gives:

情节

UPDATE:

To allow more flexibility here is a helper function that you might call just before calling plt.show() :

def align_axis(ax1, ax2, step=1):
    """ Sets both axes to have the same number of gridlines
        ax1: left axis
        ax2: right axis
        step: defaults to 1 and is used in generating a range of values to check new boundary 
              as in np.arange([start,] stop[, step])
    """
    ax1.set_aspect('auto')
    ax2.set_aspect('auto')

    grid_l = len(ax1.get_ygridlines())  # N of gridlines for left axis
    grid_r = len(ax2.get_ygridlines())  # N of gridlines for right axis
    grid_m = max(grid_l, grid_r)  # Target N of gridlines

    #  Choose the axis with smaller N of gridlines 
    if grid_l < grid_r:
        y_min, y_max = ax1.get_ybound()  # Get current boundaries 
        parts = (y_max - y_min) / (grid_l - 1)  # Get current number of partitions
        left = True 
    elif grid_l > grid_r:
        y_min, y_max = ax2.get_ybound()
        parts = (y_max - y_min) / (grid_r - 1)
        left = False
    else:
        return None

    # Calculate the new boundary for axis:
    yrange = np.arange(y_max + 1, y_max * 2 + 1, step)  # Make a range of potential y boundaries
    parts_new = (yrange - y_min) / parts  # Calculate how many partitions new boundary has
    y_new = yrange[np.isclose(parts_new, grid_m - 1)]  # Find the boundary matching target

    # Set new boundary
    if left:
        return ax1.set_ylim(top=round(y_new, 0), emit=True, auto=True)
    else:
        return ax2.set_ylim(top=round(y_new, 0), emit=True, auto=True)

So calling it on your example:

align_axis(plot_x_vs_y, ax2)
plt.show()

produces:

Aligned_axis_plot

Which is perhaps a more fair representation than a cropped version of the plot.

Note that I have not tested it extensively and there might be extreme cases when this function will fail to find correct values for alignment.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM