简体   繁体   English

Plot 子图内子图 matplotlib

[英]Plot subplots inside subplots matplotlib

Context: I'd like to plot multiple subplots (sparated by legend) based on patterns from the columns of a dataframe inside a subplot however, I'm not being able to separate each subplots into another set of subplots.背景:我想 plot 多个子图(由图例分隔)基于子图中 dataframe 列中的模式但是,我无法将每个子图分成另一组子图。

This is what I have:这就是我所拥有的:

import matplotlib.pyplot as plt
col_patterns = ['pattern1','pattern2']
# define subplot grid
fig, axs = plt.subplots(nrows=len(col_patterns), ncols=1, figsize=(30, 80))
plt.subplots_adjust()
fig.suptitle("Title", fontsize=18, y=0.95)
for col_pat,ax in zip(col_patterns,axs.ravel()):
    col_pat_columns = [col for col in df.columns if col_pat in col]

    df[col_pat_columns].plot(x='Week',ax=ax)
    # chart formatting
    ax.set_title(col_pat.upper())
    ax.set_xlabel("")

Which results in something like this:结果是这样的:

子图

How could I make it so that each one of those suplots turn into another 6 subplots all layed out horizontally?我怎样才能使这些子图中的每一个都变成另外 6 个子图,全部水平布置? (ie each figure legend would be its own subplot) (即每个图例都是它自己的子图)

Thank you!谢谢!

In your example, you're defining a 2x1 subplot and only looping through two axes objects that get created.在您的示例中,您定义了一个 2x1 子图,并且仅循环通过创建的两个轴对象。 In each of the two loops, when you call df[col_pat_columns].plot(x='Week',ax=ax) , since col_pat_columns is a list and you're passing it to df , you're just plotting multiple columns from your dataframe.在这两个循环中的每一个中,当您调用df[col_pat_columns].plot(x='Week',ax=ax)时,由于col_pat_columns是一个列表并且您将其传递给df ,您只是从你的 dataframe。 That's why it's multiple series on a single plot.这就是为什么它在单个 plot 上有多个系列。

@fdireito is correct—you just need to set the ncols argument of plt.subplots() to the right number that you need, but you'd need to adjust your loops to accommodate. @fdireito 是正确的——您只需将plt.subplots()ncols参数设置为您需要的正确数字,但您需要调整循环以适应。

If you want to stay in matplotlib, then here's a basic example.如果你想留在matplotlib,那么这里有一个基本的例子。 I had to take some guesses as to how your dataframe was structured and so on.我不得不猜测您的 dataframe 的结构等等。

# import matplotlib
import matplotlib.pyplot as plt

# create some fake data
x = [1, 2, 3, 4, 5]

df = pd.DataFrame({
    'a':[1, 1, 1, 1, 1],    # horizontal line
    'b':[3, 6, 9, 6, 3],    # pyramid
    'c':[4, 8, 12, 16, 20], # steep line
    'd':[1, 10, 3, 13, 5]   # zig-zag
})

# a list of lists, where each inner list is a set of
# columns we want in the same row of subplots
col_patterns = [['a', 'b', 'c'], ['b', 'c', 'd']]

The following is a simplified example of what your code ends up doing.以下是您的代码最终执行的简化示例。

fig, axes = plt.subplots(len(col_patterns), 1)

for pat, ax in zip(col_patterns, axes):
    ax.plot(x, df[pat])

2x1 subplot (what you have right now) 2x1 子图(您现在拥有的)

I use enumerate() with col_patterns to iterate through the subplot rows, and then use enumerate() with each column name in a given pattern to iterate through the subplot columns.我使用enumerate()col_patterns来遍历子图行,然后使用enumerate()和给定模式中的每个列名来遍历子图列。

# the following will size your subplots according to
# - number of different column patterns you want matched (rows)
# - largest number of columns in a given column pattern (columns)
subplot_rows = len(col_patterns)
subplot_cols = max([len(x) for x in col_patterns])
fig, axes = plt.subplots(subplot_rows, subplot_cols)

for nrow, pat in enumerate(col_patterns):
    for ncol, col in enumerate(pat):
        axes[nrow][ncol].plot(x, df[col])

Correctly sized subplot正确大小的子图

Here's all the code, with a couple additions I omitted from the code above for simplicity's sake.这是所有代码,为简单起见,我从上面的代码中省略了一些附加内容。

import matplotlib.pyplot as plt

x = [1, 2, 3, 4, 5]

df = pd.DataFrame({
    'a':[1, 1, 1, 1, 1],    # horizontal line
    'b':[3, 6, 9, 6, 3],    # pyramid
    'c':[4, 8, 12, 16, 20], # steep line
    'd':[1, 10, 3, 13, 5]   # zig-zag
})

col_patterns = [['a', 'b', 'c'], ['b', 'c', 'd']]

# what you have now
fig, axes = plt.subplots(len(col_patterns), 1, figsize=(12, 8))

for pat, ax in zip(col_patterns, axes):
    ax.plot(x, df[pat])
    ax.legend(pat, loc='upper left')

# what I think you want
subplot_rows = len(col_patterns)
subplot_cols = max([len(x) for x in col_patterns])

fig, axes = plt.subplots(subplot_rows, subplot_cols, figsize=(16, 8), sharex=True, sharey=True, tight_layout=True)

for nrow, pat in enumerate(col_patterns):
    for ncol, col in enumerate(pat):
        axes[nrow][ncol].plot(x, df[col], label=col)
        axes[nrow][ncol].legend(loc='upper left')

Another option you can consider is ditching matplotlib and using Seaborn relplots .您可以考虑的另一个选择是放弃 matplotlib 并使用Seaborn relplots There are several examples on that page that should help.该页面上有几个示例应该有所帮助。 If you have your dataframe set up correctly (long or "tidy" format), then to achieve the same as above, your one-liner would look something like this:如果您的 dataframe 设置正确(长或“整齐”的格式),那么要实现与上述相同的效果,您的单线将如下所示:

# import seaborn as sns

sns.relplot(data=df, kind='line', x=x_vals, y=y_vals, row=col_pattern, col=num_weeks_rolling)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM