Python: Как добавить дополнительную ось x для одной трассировки?

#python #python-3.x #pandas #dataframe #data-visualization

#python #python-3.x #pandas #фрейм данных #визуализация данных

Вопрос:

У меня есть фрейм данных (см. Раздел «Тестовые данные» ниже), и я хотел бы добавить дополнительную ось x (вверху). Но эта ось должна быть от 0 до 38,24 (мс). Это сумма всех значений в столбце ‘Время’. Это выражает общее время, которое потребовалось для выполнения 4 выводов. До сих пор я безуспешно пробовал ‘twinx ()’.

Как я могу это сделать? Возможно ли это или мне не хватает информации?

Тестовые данные:

 raw_data = {'Time': [21.9235, 4.17876, 4.02168, 3.81504, 4.2972],
            'TPU': [33.3, 33.3, 33.3, 33.3, 33.3],
            'CPU': [32, 32, 32, 32, 32],
            'MemUsed': [435.92, 435.90, 436.02, 436.02, 436.19]}

df_m=pd.DataFrame(raw_data, columns = ['Time', 'TPU', 'CPU', 'MemUsed'])

df_m
  
 ##Sum of all values in column Time(ms)
(df_m.iloc[:, 0].sum())

##Time per inference(ms)
ax = df_m.plot(kind = 'line', y = 'MemUsed', grid = True)
ax.set_xlabel("NUMBER OF INFERENCES")
ax.set_ylabel("MemUsed(MB)")
  

Что я пробовал:

 ax = df_m.plot(kind = 'line', y = 'MemUsed', grid = True)
df_m.plot(kind='line', ax=ax.twinx(), secondary_x=range(0, 39))
ax.set_xlabel("NUMBER OF INFERENCES")
ax.set_ylabel("MemUsed(MB)")
  

Выходной график:

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

Как выглядит большая таблица

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

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

1. Возможен ли вариант plotly?

2. Конечно. Я никогда не использовал, хотя. Но графики кажутся очень красивыми.

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

Ответ №1:

В дополнение к вашему положительному комментарию относительно plotly, вот пример того, как добиться мультиаксиальности для вашего набора данных.

Код намного проще, чем кажется. Код выглядит «длинным» из-за того, что я отформатировал dict s для облегчения чтения.

Ключевыми элементами являются:

  • Добавление совокупной суммы time столбца ( time_c ) для использования в xaxis2 .
  • Добавление скрытой трассировки, которая выравнивается по xaxis , и ваших временных данных, которые выравниваются по xaxis2 . Без скрытой трассировки либо обе оси не отображаются, либо они отображаются, но не выровнены из-за того, что отображается только одна трассировка.

(Обновленный) Пример кода:

Следующий код был обновлен для решения проблемы, с которой OP столкнулся с большим набором данных (70 тыс. строк).

Изменение ключа — это обновление для layout['xaxis'] и layout['xaxis2'] dicts, чтобы содержать 'type': 'category' , 'nticks' и определенные 'range' ключи.

 import pandas as pd
from plotly.offline import plot

# Create the dataset.
raw_data = {'time': [21.9235, 4.17876, 4.02168, 3.81504, 4.2972],
            'tpu': [33.3, 33.3, 33.3, 33.3, 33.3],
            'cpu': [32, 32, 32, 32, 32],
            'memused': [435.92, 435.90, 436.02, 436.02, 436.19]}

df = pd.DataFrame(raw_data)
df['time_c'] = df['time'].cumsum().round(2)

# Plotting code.
data = []
layout = {'margin': {'t': 105},
          'title': {'text': 'Example Showing use of Secondary X-Axis', 
                    'y': 0.97}}

# Create a (hidden) trace for the xaxis.
data.append({'x': df.index,
             'y': df['memused'],
             'showlegend': False,
             'mode': 'markers', 
             'marker': {'size': 0.001}})
# Create the visible trace for xaxis2.
data.append({'x': df['time_c'],
             'y': df['memused'],
             'xaxis': 'x2',
             'name': 'Inference'})

# Configure graph layout.
nticks = int(df.shape[0] // (df.shape[0] * 0.05))
layout['xaxis'] = {'title': 'Number of Inferences',
                   'nticks': nticks,
                   'range': [df.index.min(), df.index.max()],
                   'tickangle': 45,
                   'type': 'category'}
layout['xaxis2'] = {'title': 'Time(ms)', 
                    'nticks': nticks,
                    'overlaying': 'x1', 
                    'range': [df['time_c'].min(), df['time_c'].max()],
                    'side': 'top', 
                    'tickangle': 45,
                    'type': 'category'}
layout['yaxis'] = {'title': 'Memory Used (MB)'}

fig = {'data': data, 'layout': layout}
plot(fig, filename='/path/to/graph.html')
  

Пример графика (исходный набор данных):

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

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

Пример графика (новый набор данных):

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

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

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

1. У меня возникают проблемы при использовании большого фрейма данных

2. Это может быть связано с тем, что данные фактически отображаются дважды; Я думаю, у меня есть решение. Похож ли набор данных на то, что вы опубликовали в вопросе? Сколько строк? У меня есть идея для другого подхода xaxis.

3. Да, это похоже. Я добавлю изображение. Имеется 70000 строк

4. Вот так. Я обновил код и графики в исходном ответе, чтобы решить проблему, с которой вы столкнулись. Кроме того, я опубликовал второй ответ (sshhhh), чтобы предоставить вам другой вариант, который устраняет необходимость построения двух трасс по 70 тыс. точек данных каждая. Надеюсь, это поможет!

5. Это сработало. Это быстрее. Я проанализирую ваш код.

Ответ №2:

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

Этот пример отличается от исходного запроса вторичной оси x по двум причинам:

  1. Из-за размера (нового) набора данных построение «скрытого» слоя данных не является оптимальным.
  2. Для правильного отображения дополнительной оси x необходимо построить второй тренд, и, учитывая предыдущую причину, это больше не вариант.

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

Пример графика:

Примечание: Это (очевидно) синтезированные данные, чтобы достичь количества строк (70k) в обновленном вопросе.

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

Пример кода:

 import numpy as np
import pandas as pd
from plotly.offline import plot

# Synthesised dataset. (This code can be ignored.)
np.random.seed(0)
a = np.random.exponential(size=70000)*4
t = pd.Series(a).rolling(window=2000, min_periods=50).mean().to_numpy()
r = np.arange(70000).astype(str)
m = t*100

df = pd.DataFrame({'run': r, 
                   'time': t,
                   'memused': m}).dropna()

# Add cumulative time column.
df['time_c'] = df['time'].cumsum().round(1)


# --- Graphing code starts here ---

def create_labels(x):
    """Function to create xaxis labels."""
    return f"({x['run']}): {x['time_c']}"

# Create xaxis labels.
df['xaxis'] = df.apply(create_labels, axis=1)

# Create the graph.
data = []
layout = {'title': 'Combined X-Axis Labeling'}
data.append({'x': df['xaxis'], 
             'y': df['memused']})

layout['xaxis'] = {'title': '(Inference): Cumulative Time (ms)', 
                   'type': 'category', 
                   'nticks': df.shape[0] // 3500,
                   'tickangle': 45}
layout['yaxis'] = {'title': 'Memory Used (MB)'}


fig = {'data': data, 'layout': layout}
plot(fig, filename='/path/to/graph.html')