具有奇数个子图的 matplotlib
matplotlib with odd number of subplots
我正在尝试创建一个绘图函数,它将所需绘图的数量作为输入并使用 pylab.subplots
和 sharex=True
选项绘制它们。如果所需地块的数量是奇数,那么我想删除最后一个面板并在其正上方的面板上强制刻度标签。我找不到同时使用 sharex=True
选项的方法。子图的数量可能非常大 (>20)。
这是示例代码。在此示例中,我想在 i=3
.
时强制使用 xtick 标签
import numpy as np
import matplotlib.pylab as plt
def main():
n = 5
nx = 100
x = np.arange(nx)
if n % 2 == 0:
f, axs = plt.subplots(n/2, 2, sharex=True)
else:
f, axs = plt.subplots(n/2+1, 2, sharex=True)
for i in range(n):
y = np.random.rand(nx)
if i % 2 == 0:
axs[i/2, 0].plot(x, y, '-', label='plot '+str(i+1))
axs[i/2, 0].legend()
else:
axs[i/2, 1].plot(x, y, '-', label='plot '+str(i+1))
axs[i/2, 1].legend()
if n % 2 != 0:
f.delaxes(axs[i/2, 1])
f.show()
if __name__ == "__main__":
main()
如果您将 main
函数中的最后一个 if
替换为:
if n % 2 != 0:
for l in axs[i/2-1,1].get_xaxis().get_majorticklabels():
l.set_visible(True)
f.delaxes(axs[i/2, 1])
f.show()
它应该可以解决问题:
简单地说,你让你的子图要求偶数(在本例中为 6 个图):
f, ax = plt.subplots(3, 2, figsize=(12, 15))
然后把不需要的删掉:
f.delaxes(ax[2,1]) #The indexing is zero-based here
这个问题和回应是以自动化的方式看待这个问题,但我认为post这里的基本用例是值得的。
对于Python3,可以删除如下:
# I have 5 plots that i want to show in 2 rows. So I do 3 columns. That way i have 6 plots.
f, axes = plt.subplots(2, 3, figsize=(20, 10))
sns.countplot(sales_data['Gender'], order = sales_data['Gender'].value_counts().index, palette = "Set1", ax = axes[0,0])
sns.countplot(sales_data['Age'], order = sales_data['Age'].value_counts().index, palette = "Set1", ax = axes[0,1])
sns.countplot(sales_data['Occupation'], order = sales_data['Occupation'].value_counts().index, palette = "Set1", ax = axes[0,2])
sns.countplot(sales_data['City_Category'], order = sales_data['City_Category'].value_counts().index, palette = "Set1", ax = axes[1,0])
sns.countplot(sales_data['Marital_Status'], order = sales_data['Marital_Status'].value_counts().index, palette = "Set1", ax = axes[1, 1])
# This line will delete the last empty plot
f.delaxes(ax= axes[1,2])
我一直生成任意数量的子图(有时数据导致 3 个子图,有时 13 个,等等)。我写了一个小实用函数,不用再考虑了。
我定义的两个函数如下。您可以更改风格选择以符合您的喜好。
import math
import numpy as np
from matplotlib import pyplot as plt
def choose_subplot_dimensions(k):
if k < 4:
return k, 1
elif k < 11:
return math.ceil(k/2), 2
else:
# I've chosen to have a maximum of 3 columns
return math.ceil(k/3), 3
def generate_subplots(k, row_wise=False):
nrow, ncol = choose_subplot_dimensions(k)
# Choose your share X and share Y parameters as you wish:
figure, axes = plt.subplots(nrow, ncol,
sharex=True,
sharey=False)
# Check if it's an array. If there's only one plot, it's just an Axes obj
if not isinstance(axes, np.ndarray):
return figure, [axes]
else:
# Choose the traversal you'd like: 'F' is col-wise, 'C' is row-wise
axes = axes.flatten(order=('C' if row_wise else 'F'))
# Delete any unused axes from the figure, so that they don't show
# blank x- and y-axis lines
for idx, ax in enumerate(axes[k:]):
figure.delaxes(ax)
# Turn ticks on for the last ax in each column, wherever it lands
idx_to_turn_on_ticks = idx + k - ncol if row_wise else idx + k - 1
for tk in axes[idx_to_turn_on_ticks].get_xticklabels():
tk.set_visible(True)
axes = axes[:k]
return figure, axes
下面是 13 个子图的用法示例:
x_variable = list(range(-5, 6))
parameters = list(range(0, 13))
figure, axes = generate_subplots(len(parameters), row_wise=True)
for parameter, ax in zip(parameters, axes):
ax.plot(x_variable, [x**parameter for x in x_variable])
ax.set_title(label="y=x^{}".format(parameter))
plt.tight_layout()
plt.show()
产生以下结果:
或者,切换到按列遍历顺序(generate_subplots(..., row_wise=False)
)生成:
无需进行计算以检测需要删除哪些子图,您可以检查哪些子图没有打印任何内容。你可以看看 for various methods to check if something is plotted on an axis. Using the function ax.has_Data()
你可以像这样简化你的函数:
def main():
n = 5
max_width = 2 ##images per row
height, width = n//max_width +1, max_width
fig, axs = plt.subplots(height, width, sharex=True)
for i in range(n):
nx = 100
x = np.arange(nx)
y = np.random.rand(nx)
ax = axs.flat[i]
ax.plot(x, y, '-', label='plot '+str(i+1))
ax.legend(loc="upper right")
## access each axes object via axs.flat
for ax in axs.flat:
## check if something was plotted
if not bool(ax.has_data()):
fig.delaxes(ax) ## delete if nothing is plotted in the axes obj
fig.show()
您还可以使用 n
参数指定您想要的图片数量,以及使用 max_width
参数指定每行想要的图片数量。
我正在尝试创建一个绘图函数,它将所需绘图的数量作为输入并使用 pylab.subplots
和 sharex=True
选项绘制它们。如果所需地块的数量是奇数,那么我想删除最后一个面板并在其正上方的面板上强制刻度标签。我找不到同时使用 sharex=True
选项的方法。子图的数量可能非常大 (>20)。
这是示例代码。在此示例中,我想在 i=3
.
import numpy as np
import matplotlib.pylab as plt
def main():
n = 5
nx = 100
x = np.arange(nx)
if n % 2 == 0:
f, axs = plt.subplots(n/2, 2, sharex=True)
else:
f, axs = plt.subplots(n/2+1, 2, sharex=True)
for i in range(n):
y = np.random.rand(nx)
if i % 2 == 0:
axs[i/2, 0].plot(x, y, '-', label='plot '+str(i+1))
axs[i/2, 0].legend()
else:
axs[i/2, 1].plot(x, y, '-', label='plot '+str(i+1))
axs[i/2, 1].legend()
if n % 2 != 0:
f.delaxes(axs[i/2, 1])
f.show()
if __name__ == "__main__":
main()
如果您将 main
函数中的最后一个 if
替换为:
if n % 2 != 0:
for l in axs[i/2-1,1].get_xaxis().get_majorticklabels():
l.set_visible(True)
f.delaxes(axs[i/2, 1])
f.show()
它应该可以解决问题:
简单地说,你让你的子图要求偶数(在本例中为 6 个图):
f, ax = plt.subplots(3, 2, figsize=(12, 15))
然后把不需要的删掉:
f.delaxes(ax[2,1]) #The indexing is zero-based here
这个问题和回应是以自动化的方式看待这个问题,但我认为post这里的基本用例是值得的。
对于Python3,可以删除如下:
# I have 5 plots that i want to show in 2 rows. So I do 3 columns. That way i have 6 plots.
f, axes = plt.subplots(2, 3, figsize=(20, 10))
sns.countplot(sales_data['Gender'], order = sales_data['Gender'].value_counts().index, palette = "Set1", ax = axes[0,0])
sns.countplot(sales_data['Age'], order = sales_data['Age'].value_counts().index, palette = "Set1", ax = axes[0,1])
sns.countplot(sales_data['Occupation'], order = sales_data['Occupation'].value_counts().index, palette = "Set1", ax = axes[0,2])
sns.countplot(sales_data['City_Category'], order = sales_data['City_Category'].value_counts().index, palette = "Set1", ax = axes[1,0])
sns.countplot(sales_data['Marital_Status'], order = sales_data['Marital_Status'].value_counts().index, palette = "Set1", ax = axes[1, 1])
# This line will delete the last empty plot
f.delaxes(ax= axes[1,2])
我一直生成任意数量的子图(有时数据导致 3 个子图,有时 13 个,等等)。我写了一个小实用函数,不用再考虑了。
我定义的两个函数如下。您可以更改风格选择以符合您的喜好。
import math
import numpy as np
from matplotlib import pyplot as plt
def choose_subplot_dimensions(k):
if k < 4:
return k, 1
elif k < 11:
return math.ceil(k/2), 2
else:
# I've chosen to have a maximum of 3 columns
return math.ceil(k/3), 3
def generate_subplots(k, row_wise=False):
nrow, ncol = choose_subplot_dimensions(k)
# Choose your share X and share Y parameters as you wish:
figure, axes = plt.subplots(nrow, ncol,
sharex=True,
sharey=False)
# Check if it's an array. If there's only one plot, it's just an Axes obj
if not isinstance(axes, np.ndarray):
return figure, [axes]
else:
# Choose the traversal you'd like: 'F' is col-wise, 'C' is row-wise
axes = axes.flatten(order=('C' if row_wise else 'F'))
# Delete any unused axes from the figure, so that they don't show
# blank x- and y-axis lines
for idx, ax in enumerate(axes[k:]):
figure.delaxes(ax)
# Turn ticks on for the last ax in each column, wherever it lands
idx_to_turn_on_ticks = idx + k - ncol if row_wise else idx + k - 1
for tk in axes[idx_to_turn_on_ticks].get_xticklabels():
tk.set_visible(True)
axes = axes[:k]
return figure, axes
下面是 13 个子图的用法示例:
x_variable = list(range(-5, 6))
parameters = list(range(0, 13))
figure, axes = generate_subplots(len(parameters), row_wise=True)
for parameter, ax in zip(parameters, axes):
ax.plot(x_variable, [x**parameter for x in x_variable])
ax.set_title(label="y=x^{}".format(parameter))
plt.tight_layout()
plt.show()
产生以下结果:
或者,切换到按列遍历顺序(generate_subplots(..., row_wise=False)
)生成:
无需进行计算以检测需要删除哪些子图,您可以检查哪些子图没有打印任何内容。你可以看看 ax.has_Data()
你可以像这样简化你的函数:
def main():
n = 5
max_width = 2 ##images per row
height, width = n//max_width +1, max_width
fig, axs = plt.subplots(height, width, sharex=True)
for i in range(n):
nx = 100
x = np.arange(nx)
y = np.random.rand(nx)
ax = axs.flat[i]
ax.plot(x, y, '-', label='plot '+str(i+1))
ax.legend(loc="upper right")
## access each axes object via axs.flat
for ax in axs.flat:
## check if something was plotted
if not bool(ax.has_data()):
fig.delaxes(ax) ## delete if nothing is plotted in the axes obj
fig.show()
您还可以使用 n
参数指定您想要的图片数量,以及使用 max_width
参数指定每行想要的图片数量。