Как построить одну строку у-данных с двумя строками х-данных?

Я хочу построить график с 1 набором y-данных, относящихся к 2 различным (но, конечно, связанным) наборам x-данных. Мои данные выглядят так:

x1          x2  y
1,84596E17  100 18,96342
2,27684E17  102 18,15215
2,80198E17  104 15,40415
3,44059E17  106 16,13399
4,21554E17  108 15,51298
5,15396E17  110 14,92131
6,28797E17  112 15,25483
7,65554E17  114 14,81549
9,30146E17  116 15,3397
1,12785E18  118 14,76562
1,36485E18  120 14,5095
1,64844E18  122 13,24967
1,98711E18  124 12,79743
2,39083E18  126 12,53556
2,87119E18  128 12,32063
3,44172E18  130 11,95121

Я хотел бы иметь логарифмически нормальный график (x1, y) в качестве основной информации. Для ориентации я хотел бы добавить вторую ось х (x2, y), которая соответствует графику (x1, y).

Есть ли способ позволить matplotlib напрямую вычислить масштабирование второй оси x, не зная функциональной связи x1 и x2? Я также хотел бы избегать отображения одних и тех же y-данных дважды, а затем пытаться сопоставить границы осей, потому что это означало бы, что я должен знать функцию между x1 и x2.

Эскиз участка

Я добавил небольшой набросок, который, надеюсь, прояснит мое намерение (извините за качество).

Спасибо, лепакк

Всего 3 ответа


Это решение опасно и может привести к серьезным ошибкам, которые трудно отследить, но это может помочь вам сделать нужную фигуру, если вы будете осторожны.

Основываясь на данных из другого ответа в этой теме, мы можем переопределить положение верхней оси x и отметку, чтобы сказать, что мы хотим. ВНИМАНИЕ: это отделяет значение данных от метки, делая его крайне ненадежным и подверженным ошибкам. Я обычно рассматриваю переопределение меток тиков как хак, и я не одобряю этот шаблон, когда занимаюсь наукой, разработкой, исследованием данных или даже при подготовке пояснительной фигуры. Но вот мы здесь, поэтому, пожалуйста, будьте осторожны ...

import matplotlib.pyplot as plt
x1 = [184596e17, 227684e17, 280198e17, 344059e17, 421554e17, 515396e17]
x2 = [100, 102, 104, 106, 108, 110]
y = [1896342, 1815215, 1540415, 1613399, 1551298, 1492131]

fig=plt.figure()
ax=fig.add_subplot(111, label="1")

ax.plot(x1, y, color="C0")
ax.set_xlabel("x label 1", color="C0")
ax.set_ylabel("y label 1")

ax2=ax.twiny()
ax2.set_xticks(x1)
ax2.set_xticklabels(x2)
ax2.plot(x1, y, color="C2", alpha=0)
ax2.xaxis.tick_top()
ax2.set_xlabel('x label 2', color="C1") 
ax2.tick_params(axis='x', colors="C1")

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

Теперь отметка на вторичной оси x совпадает с точкой данных и отображает ее коррелирующее значение в другом пространстве «оси» в качестве метки отметки. Мне пришлось построить невидимый ряд, чтобы две шкалы оси X точно совпали (вы также можете переопределить это, установив свои собственные значения xlim). Этот подход фактически эквивалентен добавлению аннотации к каждой точке данных, но немного чище.

Редактировать:

Не забывайте, что если у вас гораздо больше точек данных, чем нумерация желаемых отметок, вы можете перемещаться по позициям и меткам, чтобы получить каждые 2, 3 или 10 или 10 отметку и метку.

Для быстрого использования используйте:

stride=2
ax2.set_xticks(x1[::stride])
ax2.set_xticklabels(x2[::stride])


В случае, если вторичная ось X будет иметь линейную шкалу, соответствие может быть принудительно установлено путем установки xlims для соответствующих первого и последнего значений.

В случае, если такая линейная шкала невозможна, обе оси должны иметь одинаковый логарифмический масштаб, и положения тиков для вторичной оси задаются через значения первой. Метки галочек, соответствующие этим позициям, должны быть установлены метками в x2 . Незначительные отметки вторичной оси, которые были установлены через логарифмическую шкалу, должны быть удалены.

Обратите внимание, что главная ось X имеет только один основной тик и множество мелких тиков. При желании эти второстепенные тики могут также получить метку с помощью set_minor_formatter(ticker.ScalarFormatter()) .

from matplotlib import pyplot as plt
from matplotlib import ticker
import numpy as np

data = np.array([[1.84596E17, 100, 18.96342],
                 [2.27684E17, 102, 18.15215],
                 [2.80198E17, 104, 15.40415],
                 [3.44059E17, 106, 16.13399],
                 [4.21554E17, 108, 15.51298],
                 [5.15396E17, 110, 14.92131],
                 [6.28797E17, 112, 15.25483],
                 [7.65554E17, 114, 14.81549],
                 [9.30146E17, 116, 15.3397],
                 [1.12785E18, 118, 14.76562],
                 [1.36485E18, 120, 14.5095],
                 [1.64844E18, 122, 13.24967],
                 [1.98711E18, 124, 12.79743],
                 [2.39083E18, 126, 12.53556],
                 [2.87119E18, 128, 12.32063],
                 [3.44172E18, 130, 11.95121]])
x1 = data[:,0]
x2 = data[:,1].astype(int) # change to integer, so they get displayed as such
y = data[:,2]

fig, ax = plt.subplots()

ax.plot(x1, y, 'or-')
ax.set_xscale('log')
ax.set_xlabel('x1 (log scale)')
# ax.set_xlim(x1[0], x1[-1]) # optionally set tighter xlims
ax.xaxis.set_minor_formatter(ticker.ScalarFormatter()) # this shows the minor tick labels

ax2 = ax.twiny()
ax2.set_xlabel('x2')
ax2.set_xlim(ax.get_xlim()) # exactly the same limits for both axes
ax2.set_xscale('log')
ax2.set_xticks(x1) # set the tick positions via x1, but the labels via x2
ax2.set_xticklabels(x2)
ax2.xaxis.set_minor_locator(ticker.NullLocator()) # remove the old minor ticks
ax2.grid(True, axis='x', ls=':')

plt.tight_layout()
plt.show()

результирующий сюжет


Используя два (или более) графика в одном графике с разными масштабами оси X и оси Y в Python в качестве ссылки, ваш код будет выглядеть так:

import matplotlib.pyplot as plt

x1 = [184596e17, 227684e17,280198e17, 344059e17, 421554e17, 515396e17]
x2 = [100, 102, 104, 106, 108, 110]
y = [1896342, 1815215, 1540415, 1613399, 1551298, 1492131]

fig=plt.figure()
ax=fig.add_subplot(111, label="1")
ax2=fig.add_subplot(111, label="2", frame_on=False)

ax.plot(x1, y, color="C0")
ax.set_xlabel("x label 1", color="C0")
ax.set_ylabel("y label 1", color="C0")

ax2.plot(x2, y, color="C1")
ax2.xaxis.tick_top()
ax2.set_xlabel('x label 2', color="C1") 
ax2.xaxis.set_label_position('top') 
ax2.tick_params(axis='x', colors="C1")


plt.savefig('stackoverflow.png', bbox_inches='tight')
plt.show()

и соответствующий вывод будет это изображение (принимая только 6 значений). введите описание изображения здесь

Дайте знать, если у вас появятся вопросы :)