如何将分类分散标记移动到 xticks 上方的左侧和右侧(每个类别有多个数据集)?

Tar*_*a S 4 python matplotlib pandas

我有一个简单的 pandas 数据框,我想用 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)
Run Code Online (Sandbox Code Playgroud)

这是我的情节:

我的数据图

我想将蓝色数据点向左移动一点,将红色数据点向右移动一点,因此每年 x 轴上都有三个迷你散点数据列,而不是所有三个数据集都重叠。我尝试并未能正确使用“verts”参数。有一个更好的方法吗?

Imp*_*est 8

使用偏移变换将允许以点为单位而不是数据单位将散点移动一定量。优点是它们总是相互紧靠,与图形大小、缩放级别等无关。

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()
Run Code Online (Sandbox Code Playgroud)

大致图:
在此输入图像描述
正常图:
在此输入图像描述
飞涨
在此输入图像描述

一些解释:

问题是我们想要向数据坐标中的某些数据添加以点为单位的偏移量。虽然数据坐标会自动转换为使用transData(我们通常在表面上看不到)显示坐标,但添加一些偏移量需要我们更改转换。
我们通过添加偏移量来做到这一点。虽然我们可以只添加以像素(显示坐标)为单位的偏移量,但添加以点为单位的偏移量会更方便,从而使用与中给出的散点大小相同的单位(它们的大小实际上是点的平方)。那么我们想知道点有多少像素p?通过除以pppi(每英寸点数)得到英寸,然后乘以 dpi(每英寸点数)得到显示像素。此计算在 ScaledTranslation 中完成。虽然每英寸点数原则上是可变的(并由变换处理dpi_scale_trans),但每英寸点数是固定的。Matplotlib 使用 72 ppi,这是一种排版标准


ger*_*eth 2

一种快速而肮脏的方法是创建一个小的偏移量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)
Run Code Online (Sandbox Code Playgroud)

另一种选择可能是使用库中的stripplot函数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'])
Run Code Online (Sandbox Code Playgroud)

输出:

在此输入图像描述