Как вывести на барплот значение, которое сильно меняет свой порядок от начала до конца временного ряда
Требуется, чтобы на большм диапазоне данных было видно начальные бары. Т.е. условно, значение растет от 10 до 1 млн на нескольких временных точках по x. Как сделать, чтобы первые бары графика были хорошо читаемы (не сливались с нулем) и при этом выводилось их фактическое значение по оси y.?
Нужно получить что-то вроде такого графика, только укрупнить столбцы в начале. Чтобы они не сливались в линию. Плюс в 1-2-3 барах есть отрицательные значения, которые должно быть хорошо видно ниже линии 0.
x = ['2022','2023','2024','2025','2026','2027','2028','2029','2030']
y = [45, 3792, 33708, 251604, 605088, 919392, 1233696, 1548000, 1862304]
y2 = [-7168, -13044, -10928, 77554, 348029, 598680, 849331, 1099982, 1351329]
Ответы (4 шт):
если данные меняются постепенно на всем протяжении временного интервала, то должно помочь использование логарифмических или кастомных шкал. примеры смотрите здесь.
ну а если это просто отдельные выбросы, которые вы хотите тоже показать, то есть еще вариант с разорванной шкалой. пример здесь.
UPD
еще, как вариант, можно разбить данные на несколько интервалов и для каждого задать свою шкалу. примерно вот так (хотя это равносильно тому, чтобы построить несколько отдельных графиков):
import pandas as pd
import matplotlib.pyplot as plt
fruits = ['apple', 'pear', 'melon', 'blueberry', 'cherry', 'orange', 'mango', 'tomato', 'peach']
counts = [-1, 3, 4, 40, 30, 55, 1000, 1500, 1800]
s = pd.Series(counts,index=fruits)
fig, ax = plt.subplots(figsize=(15,5))
twin1 = ax.twinx()
twin2 = ax.twinx()
twin2.spines.right.set_position(("axes", 1.05))
b1 = ax.bar(s[s<10].index, s[s<10], color='b', label='low')
b2 = twin1.bar(s[(10<=s)&(s<100)].index, s[(10<=s)&(s<100)], color='g', label='midle')
b3 = twin2.bar(s[s>=100].index, s[s>=100], color='r', label='high')
ax.bar_label(b1, padding=-20, color='w')
twin1.bar_label(b2, padding=-20, color='w')
twin2.bar_label(b3, padding=-20, color='w')
ax.set_xlabel("fruits")
ax.set_ylabel("low_total")
twin1.set_ylabel("mid_total")
twin2.set_ylabel("hi_total")
ax.yaxis.label.set_color('b')
twin1.yaxis.label.set_color('g')
twin2.yaxis.label.set_color('r')
ax.tick_params(axis='y', colors='b', size=4, width=1.5)
twin1.tick_params(axis='y', colors='g', size=4, width=1.5)
twin2.tick_params(axis='y', colors='r', size=4, width=1.5)
ax.tick_params(axis='x', size=4, width=1.5)
ax.legend(handles=[b1, b2, b3], loc='upper left')
plt.show()
UPD2
если применить этот подход к вашим данным, то можно получить что-то вроде такого:

но как по мне, этот график не только сильно перегружен, но и совсем не наглядный
самая первая ссылка в том ответе дает вот такой результат. мне кажется, это примерно то, что вы хотите. метки можете по оси можете сделать другие
df = pd.DataFrame({'x': x, 'y': y, 'y2': y2})
fig, ax = plt.subplots()
ax.bar(df.x, df.y - df.y2, bottom=df.y2)
ax.set_yscale('function', functions=(lambda x: np.sign(x)*np.abs(x)**(1/2), lambda x: np.sign(x)*np.abs(x)**2))
ax.grid(True)
plt.show()
import plotly.graph_objects as go
years = ['2022','2023','2024','2025','2026','2027','2028','2029','2030']
fig = go.Figure()
fig.add_trace(go.Bar(x=years,
y=[45, 3792, 33708, 251604, 605088, 919392, 1233696, 1548000, 1862304],
name='Gross',
marker_color='rgb(55, 83, 109)'
))
fig.add_trace(go.Bar(x=years,
y=[-7168, -13044, -10928, 77554, 348029, 598680, 849331, 1099982, 1351329],
name='Revenue',
marker_color='rgb(26, 118, 255)'
))
fig.update_layout(
title='График дохода',
xaxis_tickfont_size=14,
yaxis=dict(
title='График дохода',
titlefont_size=16,
tickfont_size=14,
),
legend=dict(
x=0,
y=1.0,
bgcolor='rgba(255, 255, 255, 0)',
bordercolor='rgba(255, 255, 255, 0)'
),
barmode='group',
bargap=0.15, # gap between bars of adjacent location coordinates.
bargroupgap=0.1 # gap between bars of the same location coordinate.
)
fig.update_layout(yaxis_range=[-14000,20000])
fig.show()
Получается похоже на желаемый вариант, если ограничивать значения оси Y (собственно сокращать диапазон данных).
В matplotlib вот достаточно выбрать правильную шкалу (симметричную логарифмическую) чтобы получить что-то наподобие нужного вам:
import matplotlib.pylab as plt
x = ['2022','2023','2024','2025','2026','2027','2028','2029','2030']
y = [45, 3792, 33708, 251604, 605088, 919392, 1233696, 1548000, 1862304]
y2 = [-7168, -13044, -10928, 77554, 348029, 598680, 849331, 1099982, 1351329]
plt.bar(x, y, color='b')
plt.bar(x, y2, color='r')
plt.yscale('symlog')
Более "человеческую" шкалу можно сделать так:
from matplotlib import ticker
fig, ax = plt.subplots()
...
plt.yscale('symlog')
ax.yaxis.set_major_formatter(ticker.FormatStrFormatter("%d"))






