Как добавить смещение оси в сюжете matplotlib? - PullRequest
0 голосов
/ 06 мая 2018

Я рисую несколько точечных графиков в морском заливе на одном графике. Ось X является порядковой, а не числовой; порядковые значения одинаковы для каждого точечного графика. Я хотел бы немного сместить каждый график в сторону, параметр wayplot (dodge = ...) делает это в пределах нескольких линий в пределах одного графика, но в этом случае для нескольких различных графиков, нарисованных друг над другом. Как я могу это сделать?

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

Пример, показывающий наложение графиков и затрудняющее их чтение (уклонение внутри каждого графика работает нормально)

import pandas as pd
import seaborn as sns

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
sns.pointplot(data=df1, x='x', y='y', hue='h', ci='sd', errwidth=2, capsize=0.05, dodge=0.1, markers='<')
sns.pointplot(data=df2, x='x', y='y', hue='h', ci='sd', errwidth=2, capsize=0.05, dodge=0.1, markers='>')

Result

Я мог бы использовать что-то кроме seaborn, но автоматические индикаторы доверия / ошибок очень удобны, поэтому я бы предпочел придерживаться здесь seaborn.

1 Ответ

0 голосов
/ 09 мая 2018

Сначала отвечу на этот вопрос в наиболее общем случае. Уловка может быть реализована путем смещения художников на фигуре на некоторое количество. Может быть полезно использовать точки в качестве единиц этого сдвига. Например. Вы можете сместить маркеры на графике на 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

Вы можете использовать это с 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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...