图例位于单独的子图和网格中

时间:2018-11-13 14:59:41

标签: python-3.x matplotlib legend subplot

我有一组地块,分布在两个网格中。在左侧网格中,顶部有一个图(整个宽度),底部有两个图(并排)。底部的两个共享图例。在我的右侧网格中,我想要图例,它是很多数据系列,并且我希望使用图形的整个高度。

数据系列的外观具有动画效果,但我希望不要出现图例。

我的想法是在带有图例的右侧网格中绘制时间序列,然后隐藏数据序列。但是我唯一的解决方案是ax.set_visible(False),它将删除所有内容。

这主要是脚本的外观(简化版):

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.animation as anim
from matplotlib.gridspec import GridSpec

data = np.array([[1],[2],[3],[4]])
sett = np.array([1,2,3,4])

data1 = np.hstack((data,data*2, data*3, data*4))
data2 = np.hstack((3*data, 3*data/2, 3*data/3, 3*data/4))
df1 = pd.DataFrame(data = np.array(data1), index = [1,2,3,4], columns = 
sett).transpose()
df2 = pd.DataFrame(data = np.array(data2), index = [1,2,3,4], columns = 
sett).transpose()

gs1 = GridSpec(2,2)
gs1.update(left=0.05, right = 0.80, hspace = 0.05)
gs2 = GridSpec(3,1)
gs2.update(left=0.85, right = 0.98, hspace = 0.05)
figure = plt.figure()
plt.clf()
ax1 = plt.subplot(gs1[0,:])
ax2 = plt.subplot(gs1[1,0])
ax3 = plt.subplot(gs1[1,1], sharey = ax2)
ax4 = plt.subplot(gs2[:,0])
ax1.set_ylim(0,25)

label = ['s0', 's1', 's2', 's3', 's4']
ax4.plot(df1[1], df2[:])
ax4.legend(labels = label)

def make_frame(i):
    ct=sett[i]

    ax2.plot(df1[1], df1[ct])

    ax3.plot(df1[1], df2[ct])
    ax3.legend(labels = label)

ani = anim.FuncAnimation(figure, make_frame, frames = len(sett), 
                     interval =500, repeat = False)

plt.show()

如何删除数据系列并将图例保留在gs2 / ax4中?

不要打扰我在ax2和ax3中两次绘制第一个数据系列-在我的原始脚本中没关系。但是-如果有人可以启发我为什么这样做,我们将不胜感激。

2 个答案:

答案 0 :(得分:0)

我不太确定所需的输出是什么。您是否要立即将图例放在ax4的位置,但目前没有在ax4中显示的情节。

我的解决方案是根本不创建ax4。相反,您可以使用bbox_to_anchor移动图例的位置。在这里,我使用从ax1开始的变换来建立相对于ax1的位置,然后将图例稍微移到ax1的右边缘和顶部。

请参见"legend guide" for more information

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.animation as anim
from matplotlib.gridspec import GridSpec

data = np.array([[1], [2], [3], [4]])
sett = np.array([1, 2, 3, 4])

data1 = np.hstack((data, data * 2, data * 3, data * 4))
data2 = np.hstack((3 * data, 3 * data / 2, 3 * data / 3, 3 * data / 4))
df1 = pd.DataFrame(data=np.array(data1), index=[1, 2, 3, 4], columns=sett).transpose()
df2 = pd.DataFrame(data=np.array(data2), index=[1, 2, 3, 4], columns=sett).transpose()

gs1 = GridSpec(2, 2)
gs1.update(left=0.05, right=0.80, hspace=0.05)
figure = plt.figure()
plt.clf()
ax1 = plt.subplot(gs1[0, :])
ax2 = plt.subplot(gs1[1, 0])
ax3 = plt.subplot(gs1[1, 1], sharey=ax2)

label = ['s0', 's1', 's2', 's3', 's4']


def make_frame(i):
    ct = sett[i]

    ax2.plot(df1[1], df1[ct])

    ax3.plot(df1[1], df2[ct])
    ax3.legend(labels=label, loc='upper left', bbox_to_anchor=(1.05, 1.), bbox_transform=ax1.transAxes)


ani = anim.FuncAnimation(figure, make_frame, frames=len(sett),
                         interval=500, repeat=False)

plt.show()

enter image description here

编辑:在动画开始之前使用proxy artist创建所有图例

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.animation as anim
from matplotlib.gridspec import GridSpec

data = np.array([[1], [2], [3], [4]])
sett = np.array([1, 2, 3, 4])

data1 = np.hstack((data, data * 2, data * 3, data * 4))
data2 = np.hstack((3 * data, 3 * data / 2, 3 * data / 3, 3 * data / 4))
df1 = pd.DataFrame(data=np.array(data1), index=[1, 2, 3, 4], columns=sett).transpose()
df2 = pd.DataFrame(data=np.array(data2), index=[1, 2, 3, 4], columns=sett).transpose()

gs1 = GridSpec(2, 2)
gs1.update(left=0.05, right=0.80, hspace=0.05)

figure = plt.figure()
plt.clf()
ax1 = plt.subplot(gs1[0, :])
ax2 = plt.subplot(gs1[1, 0])
ax3 = plt.subplot(gs1[1, 1], sharey=ax2)

ax1.set_ylim(0, 25)

labels = ['s0', 's1', 's2', 's3', 's4']
colors = ['C0', 'C1', 'C2', 'C3', 'C4']
proxies = [plt.plot([], [], c=c)[0] for c in colors]
ax1.legend(proxies, labels, bbox_to_anchor=(1., 1.), loc="upper left")


def init_frame():
    pass


def make_frame(i):
    ct = sett[i]
    ax2.plot(df1[1], df1[ct], c=colors[i], label=labels[i])
    ax3.plot(df1[1], df2[ct], c=colors[i], label=labels[i])
    ax3.legend()


ani = anim.FuncAnimation(figure, make_frame, init_func=init_frame, frames=len(sett),
                         interval=500, repeat=False)

plt.show()

enter image description here

答案 1 :(得分:0)

我将在制作动画之前创建折线图。您可以使用空列表初始化它们,然后一一设置数据。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.animation as anim
from matplotlib.gridspec import GridSpec

data = np.array([1,2,3,4,5])

data1 = np.vstack((data,data*2, data*3, data*4))
data2 = np.vstack((3*data, 3*data/2, 3*data/3, 3*data/4))
df1 = pd.DataFrame(data1)
df2 = pd.DataFrame(data2)

sett = np.arange(len(df1.columns))

gs1 = GridSpec(2,2)
gs1.update(left=0.05, right = 0.80, hspace = 0.05)

figure = plt.figure()

ax1 = plt.subplot(gs1[0,:])
ax2 = plt.subplot(gs1[1,0])
ax3 = plt.subplot(gs1[1,1], sharey = ax2, sharex= ax2)

ax2.set_ylim(0,25)


lines1 = ax2.plot(*[[] for _ in range(len(sett)*2)])
lines2 = ax3.plot(*[[] for _ in range(len(sett)*2)])

label = ['s0', 's1', 's2', 's3', 's4']
ax1.legend(handles = lines1, labels=label, bbox_to_anchor=(1.05,1), loc="upper left")

def init():
    for line in lines1+lines2:
        line.set_data([],[])

def make_frame(i):
    ct=sett[i]
    lines1[i].set_data(df1.index, df1[ct])
    lines2[i].set_data(df1.index, df2[ct])
    ax2.relim()
    ax2.autoscale_view()

ani = anim.FuncAnimation(figure, make_frame, init_func=init, frames = len(sett), 
                     interval =500, repeat = False)
ani.save("anigif.gif", writer="imagemagick")
plt.show()

enter image description here