Ось X-паразитов на графике журнала
У меня есть график, где ось X является температурой в ГэВ, но мне также нужно указать эталон температуры в Кельвинах, поэтому я подумал о том, чтобы поместить ось паразита с температурой в К. Попытка следовать этому ответу Как добавить вторую ось x в matplotlib, вот пример кода. В верхней части графика я получаю вторую ось, но это не та температура в К, которая мне нужна.
import numpy as np
import matplotlib.pyplot as plt
tt = np.logspace(-14,10,100)
yy = np.logspace(-10,-2,100)
fig = plt.figure()
ax1 = fig.add_subplot(111)
ax2 = ax1.twiny()
ax1.loglog(tt,yy)
ax1.set_xlabel('Temperature (GeV')
new_tick_locations = np.array([.2, .5, .9])
def tick_function(X):
V = X*1.16e13
return ["%.1f" % z for z in V]
ax2.set_xlim(ax1.get_xlim())
ax2.set_xticks(new_tick_locations)
ax2.set_xticklabels(tick_function(ax1Xs))
ax2.set_xlabel('Temp (Kelvin)')
plt.show()
Это то, что я получаю, когда запускаю код.
сюжет журнала
Мне нужно, чтобы ось паразита была пропорциональна исходной оси X. И что это может быть легко прочитать температуру в Кельвинах, когда кто-то видит график. Заранее спасибо.
2 ответа
Решение общего назначения может выглядеть следующим образом. Поскольку у вас есть нелинейный масштаб, идея состоит в том, чтобы найти позиции хороших тиков в Кельвинах, преобразовать в ГэВ, установить позиции в единицах ГэВ, но пометить их в единицах Кельвина. Это звучит сложно, но преимущество в том, что вам не нужно находить тиков самостоятельно, просто полагайтесь на matplotlib для их поиска. Однако для этого требуется функциональная зависимость между двумя шкалами, т. Е. Конверион между ГэВ и Кельвином и его обратная зависимость.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.ticker as mticker
tt = np.logspace(-14,10,100)
yy = np.logspace(-10,-2,100)
fig = plt.figure()
ax1 = fig.add_subplot(111)
ax2 = ax1.twiny()
plt.setp([ax1,ax2], xscale="log", yscale="log")
ax1.get_shared_x_axes().join(ax1, ax2)
ax1.plot(tt,yy)
ax1.set_xlabel('Temperature (GeV)')
ax2.set_xlabel('Temp (Kelvin)')
fig.canvas.draw()
# 1 GeV == 1.16 × 10^13 Kelvin
Kelvin2GeV = lambda k: k / 1.16e13
GeV2Kelvin = lambda gev: gev * 1.16e13
loc = mticker.LogLocator()
locs = loc.tick_values(*GeV2Kelvin(np.array(ax1.get_xlim())))
ax2.set_xticks(Kelvin2GeV(locs))
ax2.set_xlim(ax1.get_xlim())
f = mticker.ScalarFormatter(useOffset=False, useMathText=True)
g = lambda x,pos : "${}$".format(f._formatSciNotation('%1.10e' % GeV2Kelvin(x)))
fmt = mticker.FuncFormatter(g)
ax2.xaxis.set_major_formatter(mticker.FuncFormatter(fmt))
plt.show()
Проблема заключается в следующем: при использовании ax2.set_xlim(ax1.get_xlim())
, вы в основном устанавливаете предел верхней оси X таким же, как и для нижней оси X. Теперь, если вы делаете
print(ax1.get_xlim())
print(ax2.get_xlim())
вы получаете для обеих осей те же значения, что и
(6.309573444801943e-16, 158489319246.11108)
(6.309573444801943e-16, 158489319246.11108)
но ваша нижняя ось х имеет логарифмическую шкалу. Когда вы назначаете пределы с помощью ax2.set_xlim()
пределы ax2
такие же, но масштаб все еще линейный. Вот почему, когда вы ставите галочки на [.2, .5, .9]
эти значения отображаются в виде галочек в крайнем левом углу верхней оси X, как на рисунке.
Решение состоит в том, чтобы установить верхнюю ось X также в логарифмическом масштабе. Это необходимо, потому что ваш new_tick_locations
соответствует фактическим значениям на нижней оси X. Вы просто хотите переименовать эти значения, чтобы показать метки в Кельвинах. Из ваших имен переменных ясно, что new_tick_locations
соответствует новым тиковым локациям. Я использую некоторые измененные значения new_tick_locations
выделить проблему.
Я использую научное форматирование '%.0e'
потому что 1 ГэВ = 1,16e13 K и, таким образом, 0,5 ГэВ будет очень большим значением со многими нулями.
Ниже приведен пример ответа:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.ticker as mtick
tt = np.logspace(-14,10,100)
yy = np.logspace(-10,-2,100)
fig = plt.figure()
ax1 = fig.add_subplot(111)
ax2 = ax1.twiny()
ax1.loglog(tt,yy)
ax1.set_xlabel('Temperature (GeV)')
new_tick_locations = np.array([0.000002, 0.05, 9000])
def tick_function(X):
V = X*1.16e13
return ["%.1f" % z for z in V]
ax2.set_xscale('log') # Setting the logarithmic scale
ax2.set_xlim(ax1.get_xlim())
ax2.set_xticks(new_tick_locations)
ax2.set_xticklabels(tick_function(new_tick_locations))
ax2.xaxis.set_major_formatter(mtick.FormatStrFormatter('%.0e'))
ax2.set_xlabel('Temp (Kelvin)')
plt.show()