two (or more) graphs in one plot with different x-axis AND y-axis scales in python

前端 未结 3 1984
刺人心
刺人心 2020-12-13 21:23

I want 3 graphs on one axes object, for example:

#example x- and y-data
x_values1=[1,2,3,4,5]
y_values1=[1,2,3,4,5]

x_values2=[-1000,-800,-600,-400,-200]
y_         


        
相关标签:
3条回答
  • 2020-12-13 22:03

    In this example, you can plot multiple lines in each x-y-axis, and legend each line.

    import numpy as np
    import matplotlib.pyplot as plt
    X1 = np.arange(10)
    X1 = np.stack([X1, X1])
    Y1 = np.random.randint(1, 10, (2, 10))
    X2 = np.arange(0, 1000, 200)
    X2 = np.stack([X2, X2])
    Y2 = np.random.randint(100, 200, (2, 5))
    
    
    x_label_names = ['XXX', 'xxx']
    y_label_names = ['YYY', 'yyy']
    X1_legend_names = ['X1_legend1', 'X1_legend2']
    X2_legend_names = ['X2_legend1', 'X2_legend2']
    
    
    def plot_by_two_xaxis(X1, Y1, X2, Y2, x_label_names: list, y_label_names: list, X1_legend_names: list, X2_legend_names: list):
        fig = plt.figure()
        ax1s = []
        ax2s = []
        lines = []
        j = 0
        for i in range(len(X1)):
            j += 1
            ax1s.append(fig.add_subplot(111, label=f"{j}", frame_on=(j == 1)))
        for i in range(len(X2)):
            j += 1
            ax2s.append(fig.add_subplot(111, label=f"{j}", frame_on=(j == 1)))
    
        k = 0
        for i in range(len(X1)):
            lines.append(ax1s[i].plot(X1[i], Y1[i], color=f"C{k}")[0])
            if i == 0:
                ax1s[i].set_xlabel(x_label_names[0], color=f"C{k}")
                ax1s[i].set_ylabel(y_label_names[0], color=f"C{k}")
                ax1s[i].tick_params(axis='x', colors=f"C{k}")
                ax1s[i].tick_params(axis='y', colors=f"C{k}")
            else:
                ax1s[i].set_xticks([])
                ax1s[i].set_yticks([])
            k += 1
    
        for i in range(len(X1)):
            lines.append(ax2s[i].plot(X2[i], Y2[i], color=f"C{k}")[0])
            if i == 0:
                ax2s[i].xaxis.tick_top()
                ax2s[i].yaxis.tick_right()
                ax2s[i].set_xlabel(x_label_names[1], color=f"C{k}")
                ax2s[i].set_ylabel(y_label_names[1], color=f"C{k}")
                ax2s[i].xaxis.set_label_position('top')
                ax2s[i].yaxis.set_label_position('right')
                ax2s[i].tick_params(axis='x', colors=f"C{k}")
                ax2s[i].tick_params(axis='y', colors=f"C{k}")
            else:
                ax2s[i].set_xticks([])
                ax2s[i].set_yticks([])
            k += 1
    
        ax1s[0].legend(lines, X1_legend_names + X2_legend_names)
    
        plt.show()
    
    
    plot_by_two_xaxis(X1, Y1, X2, Y2, x_label_names,
                    y_label_names, X1_legend_names, X2_legend_names)
    

    0 讨论(0)
  • 2020-12-13 22:07

    The idea would be to create three subplots at the same position. In order to make sure, they will be recognized as different plots, their properties need to differ - and the easiest way to achieve this is simply to provide a different label, ax=fig.add_subplot(111, label="1").

    The rest is simply adjusting all the axes parameters, such that the resulting plot looks appealing. It's a little bit of work to set all the parameters, but the following should do what you need.

    import matplotlib.pyplot as plt
    
    x_values1=[1,2,3,4,5]
    y_values1=[1,2,2,4,1]
    
    x_values2=[-1000,-800,-600,-400,-200]
    y_values2=[10,20,39,40,50]
    
    x_values3=[150,200,250,300,350]
    y_values3=[10,20,30,40,50]
    
    
    fig=plt.figure()
    ax=fig.add_subplot(111, label="1")
    ax2=fig.add_subplot(111, label="2", frame_on=False)
    ax3=fig.add_subplot(111, label="3", frame_on=False)
    
    ax.plot(x_values1, y_values1, color="C0")
    ax.set_xlabel("x label 1", color="C0")
    ax.set_ylabel("y label 1", color="C0")
    ax.tick_params(axis='x', colors="C0")
    ax.tick_params(axis='y', colors="C0")
    
    ax2.scatter(x_values2, y_values2, color="C1")
    ax2.xaxis.tick_top()
    ax2.yaxis.tick_right()
    ax2.set_xlabel('x label 2', color="C1") 
    ax2.set_ylabel('y label 2', color="C1")       
    ax2.xaxis.set_label_position('top') 
    ax2.yaxis.set_label_position('right') 
    ax2.tick_params(axis='x', colors="C1")
    ax2.tick_params(axis='y', colors="C1")
    
    ax3.plot(x_values3, y_values3, color="C3")
    ax3.set_xticks([])
    ax3.set_yticks([])
    
    plt.show()
    
    0 讨论(0)
  • 2020-12-13 22:08

    You could also standardize the data so it shares the same limits and then plot the limits of the desired second scale "manually". This function standardizes the data to the limits of the first set of points:

    def standardize(data):
        for a in range(2):
            span = max(data[0][a]) - min(data[0][a])
            min_ = min(data[0][a])
            for idx in range(len(data)):
                standardize = (max(data[idx][a]) - min(data[idx][a]))/span
                data[idx][a] = [i/standardize + min_ - min([i/standardize 
                                for i in data[idx][a]]) for i in data[idx][a]]
        return data
    

    Then, plotting the data is easy:

    import matplotlib.pyplot as plt
    data = [[[1,2,3,4,5],[1,2,2,4,1]], [[-1000,-800,-600,-400,-200], [10,20,39,40,50]], [[150,200,250,300,350], [10,20,30,40,50]]]
    limits = [(min(data[1][a]), max(data[1][a])) for a in range(2)]
    
    norm_data = standardize(data)
    
    fig, ax = plt.subplots()
    
    for x, y in norm_data:
        ax.plot(x, y)
    
    ax2, ax3 = ax.twinx(), ax.twiny()
    ax2.set_ylim(limits[1])
    ax3.set_xlim(limits[0])
    
    plt.show()
    

    Since all data points have the limits of the first set of points, we can just plot them on the same axis. Then, using the limits of the desired second x and y axis we can set the limits for these two.

    0 讨论(0)
提交回复
热议问题