Python 如何在xticks(每个类别有多个数据集)上方左右移动分类散点标记?

Python 如何在xticks(每个类别有多个数据集)上方左右移动分类散点标记?,python,pandas,matplotlib,Python,Pandas,Matplotlib,我有一个简单的熊猫数据框,我想用matplotlib打印: import pandas as pd import matplotlib.pyplot as plt df = pd.read_excel('SAT_data.xlsx', index_col = 'State') plt.figure() plt.scatter(df['Year'], df['Reading'], c = 'blue', s = 25) plt.scatter(df['Year'], df['Math'], c

我有一个简单的熊猫数据框,我想用matplotlib打印:

import pandas as pd
import matplotlib.pyplot as plt

df = pd.read_excel('SAT_data.xlsx', index_col = 'State')

plt.figure()
plt.scatter(df['Year'], df['Reading'], c = 'blue', s = 25)
plt.scatter(df['Year'], df['Math'], c = 'orange', s = 25)
plt.scatter(df['Year'], df['Writing'], c = 'red', s = 25)
以下是我的情节:


我想把蓝色的数据点移到左边一点,红色的数据点移到右边一点,这样每年x轴上都有三个小的分散数据列,而不是所有三个数据集重叠。我试图正确使用“verts”参数,但失败了。有更好的方法吗?

一种快速而肮脏的方法是创建一个小偏移量
dx
,然后从蓝点的
x
值中减去它,然后将其加到红点的
x
值中

dx = 0.1
plt.scatter(df['Year'] - dx, df['Reading'], c = 'blue', s = 25) 
plt.scatter(df['Year'],      df['Math'], c = 'orange', s = 25) 
plt.scatter(df['Year'] + dx, df['Writing'], c = 'red', s = 25)
另一个选项是使用
seaborn
库中的函数。有必要将原始数据帧融合成长格式,以便每行包含一年、一次测试和一个分数。然后做一个
stripplot
将年份指定为
x
,得分为
y
,测试为
hue
split
关键字参数用于控制将类别打印为每个
x
的单独条带。还有一个
jitter
参数,它会给
x
值添加一些噪声,使它们占据一些小面积,而不是在一条垂直线上

import pandas as pd
import seaborn as sns

# make up example data
np.random.seed(2017)
df = pd.DataFrame(columns = ['Reading','Math','Writing'], 
                  data = np.random.normal(540,30,size=(1000,3)))
df['Year'] = np.random.choice(np.arange(2006,2016),size=1000)

# melt the data into long form
df1 = pd.melt(df, var_name='Test', value_name='Score',id_vars=['Year'])

# make a stripplot
fig, ax = plt.subplots(figsize=(10,7))
sns.stripplot(data = df1, x='Year', y = 'Score', hue = 'Test', 
              jitter = True, split = True, alpha = 0.7, 
              palette = ['blue','orange','red'])
输出:


使用偏移变换将允许以点为单位而不是以数据为单位将散射点偏移一定量。这样做的好处是,它们将始终紧靠在一起,不受体形大小、缩放级别等的影响

import matplotlib.pyplot as plt
import numpy as np; np.random.seed(0)
import matplotlib.transforms as transforms

year = np.random.choice(np.arange(2006,2017), size=(300) ) 
values = np.random.rand(300, 3)

plt.figure()

offset = lambda p: transforms.ScaledTranslation(p/72.,0, plt.gcf().dpi_scale_trans)
trans = plt.gca().transData

sc1 = plt.scatter(year, values[:,0], c = 'blue', s = 25, transform=trans+offset(-5))
plt.scatter(year, values[:,1], c = 'orange', s = 25)
plt.scatter(year, values[:,2], c = 'red', s = 25, transform=trans+offset(5))

plt.show()
宽幅图:

正常数字:

缩放

一些解释:

问题是,我们希望在数据坐标中的某些数据上添加点偏移。当数据坐标使用
transData
自动转换为显示坐标时(我们通常在曲面上看不到),添加一些偏移需要我们更改转换。
我们通过添加偏移量来实现这一点。虽然我们可以只添加以像素为单位的偏移量(显示坐标),但添加以点为单位的偏移量更方便,因此使用与中给出的散射点大小相同的单位(它们的大小实际上是点的平方)。 所以我们想知道有多少像素是
p
点?这是通过将
p
除以ppi(每英寸点数)得到英寸,然后乘以dpi(每英寸点数)得到显示像素。此计算在ScaledTranslation中完成。
虽然每英寸点数在原则上是可变的(并由
dpi\u scale\u trans
变换处理),但每英寸点数是固定的。Matplotlib使用72 ppi,这是一种很好的解决方案。

这里发生了一些严重的黑魔法=)。你介意解释一下偏移量变换中的数字72是从哪里来的吗?我在答案中添加了一个解释。希望有帮助。