Как добавить вторичную ось matplotlib с неравномерным интервалом и разным масштабом

#python #matplotlib #twinx

Вопрос:

У меня есть три массива: time , steps и volume . Я хочу построить график изменения volume (оси Y) по time (оси X) и продемонстрировать, как time это соотносится с steps (2-й осью X).

 time = np.array([1.280000e-07, 1.322240e-07, 1.364480e-07, 1.288448e-06,
       1.288448e-06, 1.288448e-06, 1.292672e-06, 1.292672e-06,
       1.420672e-06, 1.424896e-06, 1.429120e-06, 2.581120e-06,
       2.581120e-06, 2.581120e-06, 2.585344e-06, 2.585344e-06,
       2.586400e-06, 2.587456e-06, 2.603456e-06])

steps = np.arange(1,20)

volume = np.array([256., 384., 512., 512., 384., 256., 128.,   0., 256., 384., 512.,
   512., 384., 256., 128.,   0.,  32.,  64.,  96.])
 

Значения времени от time связаны с соответствующими steps значениями, такими как step[1] происходит в time[1] , step[2] в time[2] и т. Д.

Я пробовал twiny() , но, похоже, это работает только в том случае, если масштаб между двумя осями одинаков. На графике ниже обе оси имеют одинаковые интервалы между значениями и равномерно распределены.

 fig, ax1 = plt.subplots(1, 1, figsize=(10, 4.5), dpi=160, facecolor='w', edgecolor='k', sharey=True)
ax1.plot(t,volume)
ax2 = ax1.twiny()
ax2.set_xticks(steps)
 

введите описание изображения здесь

Как масштабировать steps ось в соответствии с time осью?

Ответ №1:

A twin ax -это новый ax , помещенный в ту же позицию, что и исходный, но устанавливающий свои тики с другой стороны. По умолчанию нет связи между исходными отметками и новыми отметками, хотя такая связь может подразумеваться тщательным установлением ограничений по оси.

Напротив, a secondary ax устанавливает фиксированную связь между тиками. Если явно не задано отношение, это будет отношение идентичности.

Чтобы получить желаемый результат, вы можете установить такую вторичную ось и поместить метки steps as, используя time для позиционирования.

Это выглядело бы так:

 import numpy as np
import matplotlib.pyplot as plt

time = np.array([1.28e-07, 1.32224e-07, 1.36448e-07, 1.288448e-06, 1.288448e-06, 1.288448e-06, 1.292672e-06, 1.292672e-06, 1.420672e-06, 1.424896e-06, 1.42912e-06, 2.58112e-06, 2.58112e-06, 2.58112e-06, 2.585344e-06, 2.585344e-06, 2.5864e-06, 2.587456e-06, 2.603456e-06])
steps = np.arange(1, 20)
volume = np.array([256., 384., 512., 512., 384., 256., 128., 0., 256., 384., 512., 512., 384., 256., 128., 0., 32., 64., 96.])

fig, ax1 = plt.subplots(1, 1, figsize=(10, 4.5),  facecolor='w', edgecolor='k')
ax1.plot(time, volume)
secax = ax1.secondary_xaxis('top')
secax.set_xticks(time)
secax.set_xticklabels(steps)
plt.show()
 

вторичная ось с использованием шагов в качестве меток

Поскольку многие временные позиции либо идентичны, либо близки друг к другу, полученные метки перекрываются. Решением может быть объединение этих перекрывающихся меток и создание диапазона меток:

 pos = []
labels = []
start_step = steps[0]
for prev_t, t, prev_step, step in zip(time,
                                      np.append(time[1:], np.inf),
                                      steps,
                                      np.append(steps[1:], 0)):
    if (t - prev_t) > prev_t / 20:
        pos  = [prev_t]
        if start_step == prev_step:
            labels  = [f'{start_step}']
        else:
            labels  = [f'{start_step}-{prev_step}']
        start_step = step
secax.set_xticks(pos)
secax.set_xticklabels(labels)
 

вторичная ось со связанными метками

Комментарии:

1. Это определенно так. Большое спасибо!