Reputation: 57
I want to animate a picture in Python with a longer header and subheader. Unfortunately, the graph is moving upwards such that the extra spacing is lost.
#%% Import packages
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
from matplotlib.animation import FuncAnimation
#%% Get data
x = pd.date_range('2015-12-31','2020-10-31',freq='B')
y0 = np.exp(np.random.normal(loc=0.05/260, scale=0.15/16, size=len(x)).cumsum())
y1 = 100+(np.random.binomial(2,0.5,size=len(x))-1).cumsum()
df_plot0 = pd.DataFrame(index=x, data=y0)
df_plot1 = pd.DataFrame(index=x, data=y1)
#%% Init und Animate
def init():
return line0, line1
def animate(iTime):
line0.set_xdata(df_plot0.index[:iTime])
line0.set_ydata(df_plot0.iloc[:iTime])
line1.set_xdata(df_plot1.index[:iTime])
line1.set_ydata(df_plot1.iloc[:iTime])
return line0, line1
#%% Draw once
sns.set_context('notebook')
plt.rcParams['figure.constrained_layout.use'] = True
fig = plt.figure(num='figPort', figsize=(8,4.5),dpi=240, constrained_layout=True)
g_spec = gridspec.GridSpec(ncols=1, nrows=2, figure=fig, height_ratios=[2,2], width_ratios=[1])
sns.set_style('ticks', rc={'axes.grid': True, 'axes.spines.right': False, 'axes.spines.top': False, 'grid.color': 'lightgrey', 'grid.linestyle': 'dotted'})
ax0 = fig.add_subplot(g_spec[0,0])
line0 = ax0.plot(df_plot0, axes=ax0)[0]
ax1 = fig.add_subplot(g_spec[1,0])
line1 = ax1.plot(df_plot1, axes=ax1)[0]
sns.despine(ax=ax0, offset={'left':10, 'bottom':10})
sns.despine(ax=ax1, left=False, bottom=True, top=False,offset={'left':10, 'top':10})
title_main = 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor'
title_sub = 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna\naliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea\ntakimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy.\n'
ax0.annotate(title_main, xy=(0.025, 0.99), xycoords=('figure fraction'), size=12, ha='left', va='top') #<-- if 1.01 instead of 0.99, then the height of axes goes to zero
ax0.annotate(title_sub, xy=(0.025, 0.955), xycoords='figure fraction', size=10, ha='left', va='top')
init()
iTime = np.int(df_plot1.shape[0]*3/4)
animate(iTime)
plt.show()
#%% Animation
anim = FuncAnimation(fig=fig, func=animate, frames=range(100), interval=4, repeat=False, blit=True)
anim.save('test.mp4', fps=60)
Any help how to place the title and suptitle correctly?
If I use .title or .suptitle, I cannot place the header correctly.
If I use .annotate(), then the axes will take over the complete figure such that I won't see the titles correctly anymore.
If I place the text above 1, e.g. 1.01 instead of below 1, e.g. 0.99, then the axes will be shrinked to zero height - see commentary in code.
I do get the following error messages: "UserWarning: This figure was using constrained_layout==True, but that is incompatible with subplots_adjust and or tight_layout: setting constrained_layout==False."
Upvotes: 0
Views: 244
Reputation: 57
Solved.
I have used the ax.get_position() and ax.set_position() after the first plot, before running the animation.
for ax in [ax0, ax1]:
print(ax.get_position())
factor = 0.9
box1 = ax1.get_position()
box0 = ax0.get_position()
ax0.set_position([box0.x0, box0.y0 - (1-factor)*box1.height, box0.width, factor*box0.height])
ax1.set_position([box1.x0, box1.y0 , box1.width, factor * box1.height])
for ax in [ax0, ax1]:
print(ax.get_position())
@ Diziet Asahi How does this translates into fig.subplots_adjust(top = ?, bottom = ?) Do I need to address different adjustment for the different axes ax0 and ax1?
Upvotes: 0