Как сделать так, чтобы xticks в matplotlib были равномерно распределены, несмотря на их значение, на основе groupby?

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

fig, ax = plt.subplots(figsize=(10,6), sharex=True, sharey=True)

ax.plot(ipo_cut[["IR", "Age", "Timespan"]][(ipo_cut["Timespan"] == "1980-1989") & (ipo_cut["Age"] >= 2)].groupby("Age").mean(), color="r")
ax2 = ax.twinx()
ax2.plot(ipo_cut[["IR", "Age", "Timespan"]][(ipo_cut["Timespan"] == "1990-1998") & (ipo_cut["Age"] >= 2)].groupby("Age").mean(), color = "g")
ax3 = ax.twinx()
ax3.plot(ipo_cut[["IR", "Age", "Timespan"]][(ipo_cut["Timespan"] == "1999-2000") & (ipo_cut["Age"] >= 2)].groupby("Age").mean(), color="grey")
ax4 = ax.twinx()
ax4.plot(ipo_cut[["IR", "Age", "Timespan"]][(ipo_cut["Timespan"] == "2001-2003") & (ipo_cut["Age"] >= 2)].groupby("Age").mean())

ax.set(title ="Average First-day Returns by Age of Firm at Time of IPO",
      xlabel = "Age",
      ylabel = "Average First-Day Return in %")
ax.set_ylim([0,1])
ax2.set_ylim([0,1])
ax3.set_ylim([0,1])
ax4.set_ylim([0,1])
ax.set_xlim([0,70])
ax2.set_xlim([0,70])
ax3.set_xlim([0,70])
ax4.set_xlim([0,70])
ax2.get_yaxis().set_visible(False)
ax3.get_yaxis().set_visible(False)
ax4.get_yaxis().set_visible(False)

plt.xticks([0,1,2,3,4,5,6,7,8,9,10, 11,12,13,15,17,20,30,40,50,60,70])
plt.setp(ax.get_xticklabels(), rotation = 90)

fig.show()

и вывод выглядит следующим образом:Мой выходной график

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

Решение в Seaborn также было бы очень полезно для меня.

РЕДАКТИРОВАТЬ с некоторой дополнительной информацией: форма x-вектора и данных не совпадают. Я отфильтровал свой фрейм данных только для соответствующих возрастов, но некоторая информация отсутствует. Вот минимальный воспроизводимый пример:

import matplotlib.pyplot as py
import numpy as np
    
#create dataframe
x = np.arange(0,11)
df = pd.DataFrame(data = np.random.rand(len(x)), index = x, columns=["IR"])
df.index.name = "Age"
df.loc[[0, 9], "IR"] = np.nan
df.dropna(inplace = True)

# open figure
fig, ax = plt.subplots(figsize=(10,6))
# create x-values
x = [0,1,2,5,7,9,10]
# plot
ax.plot(x, df, color="r")
ax.set(
    title ="Average First-day Returns by Age of Firm at Time of IPO",
    xlabel = "Age",
    ylabel = "Average First-Day Return in %",
    ylim = [0,1],
    xlim = [0,10])
ax.tick_params(axis='x', labelrotation=90) 
fig.show()

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

РЕШЕНИЕ:

import matplotlib.pyplot as py
import numpy as np
    
#create dataframe
x = np.arange(0,10)
df = pd.DataFrame(data = np.random.rand(len(x)), index = x, columns=["IR"])
df.index.name = "Age"
#create nan in sample
df.loc[[0, 9], "IR"] = np.nan
# slice data for unbroken line (solution by max)
lg = df["IR"].isna()
# create ticks for even distribution
n = 10
a = np.arange(n)
# open figure
fig, ax = plt.subplots(figsize=(10,6))
# create x-values fir tick labels
x = (0,5,10,13,15,24,30,40,55,70)
# plot
ax.plot(a[~lg], df[~lg], color="r")
ax.set(
    title ="Average First-day Returns by Age of Firm at Time of IPO",
    xlabel = "Age",
    ylabel = "Average First-Day Return in %",
    ylim = [0,1],
    xlim = [0,10])
ax.xaxis.set_ticks(a) #set the ticks to be a
ax.xaxis.set_ticklabels(x) # change the ticks' names to x
ax.tick_params(axis='x', labelrotation=90) 
fig.show()

Благодаря вводу max и Как сделать галочки равномерно распределенными, несмотря на их ценность? Я мог бы найти решение своей проблемы. Если ваш исходный фрейм данных имеет значения x с размером шага, отличным от единицы, я предлагаю просто reset_index().


person Cosimo    schedule 12.12.2020    source источник


Ответы (1)


Я рекомендую создать нужный x-вектор в самом начале и нанести данные по нему. Затем вы можете позволить matplotlib сделать все остальное. Наоборот, вы искусственно создадите равномерно распределенный график (если вы не укажете значение x, matplotlib предполагает, что данные представляют собой последовательность точек с размером шага 1), вы просто измените внешний вид оси X, а не самого графика.

import matplotlib.pyplot as py
import numpy as np

# open figure
fig, ax = plt.subplots(figsize=(10,6))
# create x-values
x = [0,1,2,3,4,5,6,7,8,9,10, 11,12,13,15,17,20,30,40,50,60,70]
# create (random) y-values
y = np.random.rand(len(x))
# plot
ax.plot(x, y, color="r")
ax.set(
    title ="Average First-day Returns by Age of Firm at Time of IPO",
    xlabel = "Age",
    ylabel = "Average First-Day Return in %",
    ylim = [0,1],
    xlim = [0,70])
ax.tick_params(axis='x', labelrotation=90) 
fig.show()

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

Я удалил ваш код и создал несколько искусственных фиктивных данных. Взгляните на: Как создать минимальный воспроизводимый пример.

person max    schedule 12.12.2020
comment
Спасибо за помощь. Ваш ответ дал мне некоторые идеи, но, к сожалению, не соответствует моим потребностям. Я отредактировал свой вопрос для получения дополнительной информации и минимального воспроизводимого примера. Я надеюсь, что это делает это более ясным. - person Cosimo; 13.12.2020
comment
Чтобы построить непрерывную линию (чтобы не рисовать NaNs), вы можете разрезать данные lg = df["IR"].isna(), а затем построить их ax.plot(x[~lg], df[~lg]) - person max; 14.12.2020