Python, Matplotlib: нормализация нескольких графиков для соответствия одним и тем же произвольным ограничениям оси

Я пытаюсь создать фигуру, содержащую несколько графиков, и нормализую их все, чтобы их можно было легко различить. У меня возникли проблемы с формулировкой того, что я пытаюсь сделать, но приведенный ниже пример кода должен помочь прояснить ситуацию.

Пример графика, сгенерированного приведенным ниже кодом.

Код создает фигуру с тремя линиями на ней. Данные черной линии варьируются от -1000 до 1000, поэтому масштаб корректируется соответствующим образом. Это означает, что изменение данных зеленого цвета, а тем более красного, трудно увидеть. В идеале я хотел бы увеличить зеленые и красные данные, чтобы их изменение было более четким, но, надеюсь, без простого умножения на постоянное значение.

Пример результата, на который я надеюсь: все разные линии имеют разные порядки величины, но были приспособлены к произвольному масштабу оси Y, чтобы можно было продемонстрировать их форму.

import numpy as np
import matplotlib.pyplot as plt

time_arr = np.arange(0, 25, 1)

dist_arr = np.zeros(len(time_arr))
speed_arr = np.zeros(len(time_arr))
energy_arr = np.zeros(len(time_arr))

for i in range(len(time_arr)):
    dist_arr[i] = np.random.randint(-10, 10)
    speed_arr[i] = np.random.randint(-50, 50)
    energy_arr[i] = np.random.randint(-1000, 1000)


fig = plt.figure(figsize=(13,13))

plt.plot(time_arr, dist_arr, 'red', linestyle='-', label='dist (m)', linewidth=5)
plt.plot(time_arr, speed_arr, 'lime', linestyle='-', label='speed (m/s)', linewidth=5)
plt.plot(time_arr, energy_arr, 'black', linestyle='--', label='E_tot (J)', linewidth=5)

plt.xlabel('Time (s)', fontsize=25)
plt.ylabel('Various Params', fontsize=25)
plt.tick_params(axis='x', labelsize=20)
plt.tick_params(axis='y', labelsize=20)
plt.title('Various VS Time', fontsize = 32, y=1.008)
plt.legend(loc='best', fontsize=25)

plt.show()

Я пробовал играть с такими вещами, как plt.ylim([0, 100]) для каждого отдельного линейного графика, но, похоже, это не сработало. Любая помощь здесь была бы фантастической, ура.

ИЗМЕНИТЬ:

Проблема решена в комментариях благодаря улучшенной технике нормализации ImportanceOfBeingErnest в сочетании с принятым ответом. Спасибо!


person Milo    schedule 07.04.2017    source источник
comment
Какой код создает эту новую фигуру, которую вы показываете? В коде из вопроса нет кривых sin или cos.   -  person ImportanceOfBeingErnest    schedule 07.04.2017
comment
@ImportanceOfBeingErnest извините за это - я отредактировал вопрос, чтобы теперь он отображался правильно. Это намного сложнее, поэтому я надеялся, что моего оригинального миниатюрного примера кода будет достаточно!   -  person Milo    schedule 08.04.2017
comment
Ваша функция нормализации не очень полезна. Вы можете либо нормализовать диапазон от 0 до 1, norm = lambda x: (x-x.min())/(x.max()-x.min()), либо диапазон вокруг среднего значения, norm = lambda x: 2*(x-x.mean())/(x.max()-x.min()) или аналогичный.   -  person ImportanceOfBeingErnest    schedule 08.04.2017
comment
Блин, кажется, проблема решилась. Спасибо @ImportanceOfBeingErnest!! Есть ли какая-то конкретная причина, по которой вы предложили использовать здесь лямбда вместо обычной функции?   -  person Milo    schedule 08.04.2017
comment
Нет, лямбда короче и понятнее в комментариях; это все.   -  person ImportanceOfBeingErnest    schedule 08.04.2017


Ответы (3)


у вас есть возможность нормализовать данные, а также иметь несколько двойных осей Y. Смотри ниже.

import numpy as np
import matplotlib.pyplot as plt

def norm(data):
    return (data)/(max(data)-min(data))

time_arr = np.arange(0, 25, 1)

dist_arr = np.zeros(len(time_arr))
speed_arr = np.zeros(len(time_arr))
energy_arr = np.zeros(len(time_arr))

for i in range(len(time_arr)):
    dist_arr[i] = np.random.randint(-10, 10)
    speed_arr[i] = np.random.randint(-50, 50)
    energy_arr[i] = np.random.randint(-1000, 1000)

# option 1
fig = plt.figure(figsize=(10,10))

plt.plot(time_arr, norm(dist_arr), 'red', linestyle='-', label='dist (m)', linewidth=5)
plt.plot(time_arr, norm(speed_arr), 'lime', linestyle='-', label='speed (m/s)', linewidth=5)
plt.plot(time_arr, norm(energy_arr), 'black', linestyle='--', label='E_tot (J)', linewidth=5)

plt.xlabel('Time (s)', fontsize=25)
plt.ylabel('Various Params', fontsize=25)
plt.tick_params(axis='x', labelsize=20)
plt.tick_params(axis='y', labelsize=20)
plt.title('Various VS Time', fontsize = 32, y=1.008)
plt.legend(loc='best', fontsize=25)

plt.show()

# option 2
fig, ax1 = plt.subplots(1,1,figsize=(12,9))

ax1.plot(time_arr, dist_arr, 'red', linestyle='-', label='dist (m)', linewidth=5)
ax1.set_xlabel('Time (s)', fontsize=25)
# Make the y-axis label, ticks and tick labels match the line color.
ax1.set_ylabel('Distance(m)', color='r',fontsize=25)
ax1.tick_params('y', colors='r', labelsize=20)

ax2 = ax1.twinx()
ax2.plot(time_arr, speed_arr, 'lime', linestyle='-', label='speed (m/s)', linewidth=5)
ax2.set_ylabel('Speed (m/s)', color='lime',fontsize=25)
ax2.tick_params('y', colors='lime', labelsize=20)

ax3 = ax1.twinx()
ax3.spines['right'].set_position(('axes', 1.25)) # move the right axis light bit to the right by 25 % of the axes
ax3.plot(time_arr, norm(energy_arr), 'black', linestyle='--', label='E_tot (J)', linewidth=5)
ax3.set_ylabel('E_tot (J)', color='black',fontsize=25)
ax3.tick_params('y', colors='black', labelsize=20)


fig.tight_layout()
plt.show()

приводит к

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

person plasmon360    schedule 07.04.2017
comment
Я думаю, что это именно то, что я ищу, но, похоже, у меня та же проблема. Я отредактировал свой пост, добавив еще один рисунок - пурпурная и синяя линии представляют собой синусоидальные кривые, аналогичные приведенному мной исходному целевому примеру, но из-за масштаба оси и низкой амплитуды колебаний это вообще не видно. . Любые идеи? - person Milo; 07.04.2017

Я думаю, у вас есть два варианта:

  1. Подграфики — см. эту демонстрацию. вы можете скопировать случай «совместного использования обеих осей»

  2. Двойная ось Y — см. здесь. Я думаю, что эти графики менее ясны, так как трудно понять, какой масштаб использовать для каждой кривой.

Я бы рекомендовал вариант 1

person James Dilworth    schedule 07.04.2017

Вы должны включить (data -np.amin(x)) в числитель для правильного масштабирования.

person Jose Robles    schedule 08.06.2020