【问题标题】:Creating function to plot multiple distribution plots for every unique value in column创建函数为列中的每个唯一值绘制多个分布图
【发布时间】:2019-11-25 17:39:59
【问题描述】:

我正在为这个功能而苦苦挣扎。 我需要这个函数做的是为列中的每个唯一值绘制 X 个 seaborn 分布图(在单独的图中)。 在下面的示例中,我使用 iris 数据集转换为添加了三个附加列的数据框:city,color,period

import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
from scipy import stats
from matplotlib import rcParams
from sklearn.datasets import load_iris

iris=load_iris()
df=pd.DataFrame(data= np.c_[iris['data'], iris['target']],columns= iris['feature_names'] + ['target'])

df['city']=np.random.choice(['New York','Paris','London'],size=len(df))
df['period']=np.random.choice(['before','after'],size=len(df))
df['color']=np.random.choice(['red','black','blue'],size=len(df))

unique_vals = df['period'].unique()
targets = [df.loc[df['period'] == val] for val in unique_vals]
for target in targets:
    sns.distplot(target[[r'petal width (cm)']], hist=False,label='shouldbedynamic')
    sns.distplot(target[[r'sepal width (cm)']], hist=False,label='shouldbedynamic')
    plt.legend()

plt.show()

到目前为止,这段代码能够绘制出我定义的由 X 变量拆分的两个度量(在本例中为 period)。 假设现在我想看到完全相同的输出(相同的测量值并由period 绘制),但是对于city 列中的每个值,将生成一个新的绘图/图形。我当然可以通过一次过滤一个值来手动执行此操作,但如果 city 有 50 个唯一值,我需要一个函数来迭代并绘制 50 个单独的分布。

除此之外,我还有两个小问题

  • 在现有代码中,如何设置label 选项以动态生成显示彩色线条代表的图例?
  • 类似问题:是否可以在现有功能范围内将颜色线设置为另一种颜色?

编辑:只是想弄清楚我想要的是能够在单独的图中绘制分布(不在同一个图中)。所以如果city 有 50 个不同的值,则会生成图片中的相同数字每个城市的数据:纽约、巴黎、伦敦等。

【问题讨论】:

  • 看看在本期结束时提出的 FacetGrid 解决方案(带有图片的那个):github.com/mwaskom/seaborn/issues/861。我无法想象一个有 50 个分布在彼此之上的图有很多实用性。您可能需要重新考虑可视化。
  • 谢谢,这实际上似乎比我目前用“周期”变量分割的方式更有效。但我正在寻找的是为每个 city 变量生成 50 个单独的数字(不在同一个数字中)。
  • 那么您的图像非常混乱。查看FacetGrid 主要文档,这是它的预期目的。在页面中搜索“将具有多个级别的列变量包装到行中:”

标签: python function for-loop matplotlib seaborn


【解决方案1】:

您的意思是您想要 50 个单独的地块(每个城市一个地块,并按时间段划分)?或者你想在同一个地块中有 50 个分布(每个城市一个,不按时间段划分)?

获取动态标签很简单,只需使用groupby 而不是unique

for period, group in df.groupby('period'):
    sns.distplot(group[[r'petal width (cm)']], hist=False, label=f'petal: {period}')
    sns.distplot(group[[r'sepal width (cm)']], hist=False, label=f'sepal: {period}')

plt.legend() 

您还可以设置sns.distplotcolor 参数来选择您想要的任何颜色,但您可能想查看colormaps 的50 个绘图

编辑:

现在你想要什么更清楚了,你可以试试这样的东西

def plot_city(city_name, data):
    """ generate plot for one city """

   measures = {
        'petal width (cm)': 'tab:orange',
        'sepal width (cm)': 'tab:blue',
    }

    line_styles = {
        'before': '--',
        'after': '-',
    }

    fig, ax = plt.subplots(figsize=(12, 9))

    for measure, colour in measures.items():
        for period, group in data.groupby('period'):
            sns.distplot(
                ax=ax,
                a=group[measure], 
                hist=False, 
                label=f'petal: {period}', 
                color=colour,
                kde_kws={'linestyle':line_styles[period]}
            )

    ax.set_title(city_name, fontsize=24)
    ax.set_xlabel('width (cm)', fontsize=18)
    plt.legend(fontsize=18) 

    return fig


for city_name, data in df.groupby('city'):
    fig = plot_city(city_name, data)
    fig.savefig(f'./{city_name}.png', bbox_inches='tight')
    plt.show()

【讨论】:

  • 我想要 50 个单独的地块 - 每个城市一个地块,但仍被 period 列分开。 groupby 完美运行,谢谢。虽然我已经尝试添加颜色选项,但由于每个度量都按周期分割,我得到了同一图表的 2 种颜色,这是我不想要的。我会检查颜色图。
  • 我编辑了我的答案。这将保存 50 个不同的地块。或者,您可以使用plt.subplots(nrows=5, ncols=10) 将它们全部放入一个包含 50 个子图的巨型图上
  • 非常感谢,这似乎正是我所需要的。
猜你喜欢
  • 2021-06-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-21
  • 1970-01-01
  • 2021-11-19
  • 2017-07-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多