Сначала отвечу на этот вопрос в наиболее общем случае.
Уловка может быть реализована путем смещения художников на фигуре на некоторое количество. Может быть полезно использовать точки в качестве единиц этого сдвига. Например. Вы можете сместить маркеры на графике на 5 баллов.
Этот сдвиг может быть достигнут путем добавления перевода в преобразование данных исполнителя. Здесь я предлагаю ScaledTranslation
.
Теперь, чтобы сохранить это самое общее, можно написать функцию, которая принимает метод построения графика, оси и данные в качестве входных данных, и, кроме того, применяется некоторая уклонение, например,
draw_dodge(ax.errorbar, X, y, yerr =y/4., ax=ax, dodge=d, marker="d" )
Полный функциональный код:
import matplotlib.pyplot as plt
from matplotlib import transforms
import numpy as np
import pandas as pd
def draw_dodge(*args, **kwargs):
func = args[0]
dodge = kwargs.pop("dodge", 0)
ax = kwargs.pop("ax", plt.gca())
trans = ax.transData + transforms.ScaledTranslation(dodge/72., 0,
ax.figure.dpi_scale_trans)
artist = func(*args[1:], **kwargs)
def iterate(artist):
if hasattr(artist, '__iter__'):
for obj in artist:
iterate(obj)
else:
artist.set_transform(trans)
iterate(artist)
return artist
X = ["a", "b"]
Y = np.array([[1,2],[2,2],[3,2],[1,4]])
Dodge = np.arange(len(Y),dtype=float)*10
Dodge -= Dodge.mean()
fig, ax = plt.subplots()
for y,d in zip(Y,Dodge):
draw_dodge(ax.errorbar, X, y, yerr =y/4., ax=ax, dodge=d, marker="d" )
ax.margins(x=0.4)
plt.show()
![enter image description here](https://i.stack.imgur.com/q0QUG.png)
Вы можете использовать это с ax.plot
, ax.scatter
и т. Д. Однако не с любой из функций seaborn, потому что они не возвращают никакого полезного художника для работы.
Теперь для рассматриваемого случая остается проблема получения данных в удобном формате. Одним из вариантов будет следующий.
df1 = pd.DataFrame({'x':list('ffffssss'),
'y':[1,2,3,4,5,6,7,8],
'h':list('abababab')})
df2 = df1.copy()
df2['y'] = df2['y']+0.5
N = len(np.unique(df1["x"].values))*len([df1,df2])
Dodge = np.linspace(-N,N,N)/N*10
fig, ax = plt.subplots()
k = 0
for df in [df1,df2]:
for (n, grp) in df.groupby("h"):
x = grp.groupby("x").mean()
std = grp.groupby("x").std()
draw_dodge(ax.errorbar, x.index, x.values,
yerr =std.values.flatten(), ax=ax,
dodge=Dodge[k], marker="o", label=n)
k+=1
ax.legend()
ax.margins(x=0.4)
plt.show()
![enter image description here](https://i.stack.imgur.com/OO2CN.png)