最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

python - Overlaping subplots vertically stacked - Stack Overflow

programmeradmin0浏览0评论

While reading a paper for my thesis I encountered this graph (b):

I've tried to recreate the second graph which is the one I would like to use for my results:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec
years = np.linspace(1300, 2000, 700)

np.random.seed(42)

delta_13C = np.cumsum(np.random.normal(0, 0.1, 700))
delta_13C = delta_13C - np.mean(delta_13C)
delta_18O = np.cumsum(np.random.normal(0, 0.08, 700))
delta_18O = delta_18O - np.mean(delta_18O)
temp_anomaly = np.cumsum(np.random.normal(0, 0.03, 700))
temp_anomaly = temp_anomaly - np.mean(temp_anomaly)
temp_anomaly[-100:] += np.linspace(0, 1.5, 100)

plt.style.use('default')
plt.rcParams['font.size'] = 12
plt.rcParams['axes.linewidth'] = 1.5
plt.rcParams['axes.labelsize'] = 14

fig = plt.figure(figsize=(10, 8))
gs = GridSpec(3, 1, height_ratios=[1, 1, 1], hspace=0.2)

ax1 = fig.add_subplot(gs[0])
ax1.plot(years, delta_13C, color='green', linewidth=1.0)
ax1.set_ylabel('First', color='green', labelpad=10)
ax1.tick_params(axis='y', colors='green')
ax1.set_xlim(1300, 2000)
ax1.set_ylim(-4, 4)
ax1.xaxis.set_visible(False)
ax1.spines['top'].set_visible(False)
ax1.spines['bottom'].set_visible(False)
ax1.spines['right'].set_visible(False)
ax1.spines['left'].set_color('green')

ax2 = fig.add_subplot(gs[1])
ax2.plot(years, delta_18O, color='blue', linewidth=1.0)
ax2.yaxis.tick_right()
ax2.yaxis.set_label_position("right")
ax2.set_ylabel('Second', color='blue', labelpad=10)
ax2.tick_params(axis='y', colors='blue')
ax2.set_xlim(1300, 2000)
ax2.set_ylim(-3, 3)
ax2.xaxis.set_visible(False)
ax2.spines['top'].set_visible(False)
ax2.spines['bottom'].set_visible(False)
ax2.spines['left'].set_visible(False)
ax2.spines['right'].set_color('blue')

ax3 = fig.add_subplot(gs[2])
ax3.plot(years, temp_anomaly, color='gray', linewidth=1.0)
ax3.set_ylabel('Third', color='black', labelpad=10)
ax3.set_xlim(1300, 2000)
ax3.set_ylim(-1.0, 1.5)
ax3.set_xlabel('Year (CE)')
ax3.spines['top'].set_visible(False)
ax3.spines['right'].set_visible(False)
plt.show()

But the result is a bit different:

How can I bring the subplots closer together without blocking each other? As you can see in the graphic in the reference paper, the lines of the subplots almost touch each other.

While reading a paper for my thesis I encountered this graph (b):

I've tried to recreate the second graph which is the one I would like to use for my results:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec
years = np.linspace(1300, 2000, 700)

np.random.seed(42)

delta_13C = np.cumsum(np.random.normal(0, 0.1, 700))
delta_13C = delta_13C - np.mean(delta_13C)
delta_18O = np.cumsum(np.random.normal(0, 0.08, 700))
delta_18O = delta_18O - np.mean(delta_18O)
temp_anomaly = np.cumsum(np.random.normal(0, 0.03, 700))
temp_anomaly = temp_anomaly - np.mean(temp_anomaly)
temp_anomaly[-100:] += np.linspace(0, 1.5, 100)

plt.style.use('default')
plt.rcParams['font.size'] = 12
plt.rcParams['axes.linewidth'] = 1.5
plt.rcParams['axes.labelsize'] = 14

fig = plt.figure(figsize=(10, 8))
gs = GridSpec(3, 1, height_ratios=[1, 1, 1], hspace=0.2)

ax1 = fig.add_subplot(gs[0])
ax1.plot(years, delta_13C, color='green', linewidth=1.0)
ax1.set_ylabel('First', color='green', labelpad=10)
ax1.tick_params(axis='y', colors='green')
ax1.set_xlim(1300, 2000)
ax1.set_ylim(-4, 4)
ax1.xaxis.set_visible(False)
ax1.spines['top'].set_visible(False)
ax1.spines['bottom'].set_visible(False)
ax1.spines['right'].set_visible(False)
ax1.spines['left'].set_color('green')

ax2 = fig.add_subplot(gs[1])
ax2.plot(years, delta_18O, color='blue', linewidth=1.0)
ax2.yaxis.tick_right()
ax2.yaxis.set_label_position("right")
ax2.set_ylabel('Second', color='blue', labelpad=10)
ax2.tick_params(axis='y', colors='blue')
ax2.set_xlim(1300, 2000)
ax2.set_ylim(-3, 3)
ax2.xaxis.set_visible(False)
ax2.spines['top'].set_visible(False)
ax2.spines['bottom'].set_visible(False)
ax2.spines['left'].set_visible(False)
ax2.spines['right'].set_color('blue')

ax3 = fig.add_subplot(gs[2])
ax3.plot(years, temp_anomaly, color='gray', linewidth=1.0)
ax3.set_ylabel('Third', color='black', labelpad=10)
ax3.set_xlim(1300, 2000)
ax3.set_ylim(-1.0, 1.5)
ax3.set_xlabel('Year (CE)')
ax3.spines['top'].set_visible(False)
ax3.spines['right'].set_visible(False)
plt.show()

But the result is a bit different:

How can I bring the subplots closer together without blocking each other? As you can see in the graphic in the reference paper, the lines of the subplots almost touch each other.

Share Improve this question edited 10 hours ago Jason Aller 3,65228 gold badges41 silver badges39 bronze badges asked 11 hours ago JohnJohn 3512 silver badges9 bronze badges 1
  • If you use add_axes instead of add_subplot then you can place the axes in arbitrary positions. – RuthC Commented 11 hours ago
Add a comment  | 

1 Answer 1

Reset to default 1

The main change you'll need to make is to make the background color of your Axes transparent and to use a negative hspace to force the graphs to overlap a bit more:

plt.rcParams['axes.facecolor'] = 'none'                  # transparent Axes background
gs = GridSpec(3, 1, height_ratios=[1, 1, 1], hspace=-.1) # negative hspace for overlap

Adjusting the y-axis on your second chart will also be necessary here since they currently clip out just a touch of data.

ax2.set_ylim(-3.5, 3.5)

Putting it all back into your script:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec
years = np.linspace(1300, 2000, 700)

np.random.seed(42)

delta_13C = np.cumsum(np.random.normal(0, 0.1, 700))
delta_13C = delta_13C - np.mean(delta_13C)
delta_18O = np.cumsum(np.random.normal(0, 0.08, 700))
delta_18O = delta_18O - np.mean(delta_18O)
temp_anomaly = np.cumsum(np.random.normal(0, 0.03, 700))
temp_anomaly = temp_anomaly - np.mean(temp_anomaly)
temp_anomaly[-100:] += np.linspace(0, 1.5, 100)

plt.style.use('default')
plt.rcParams['font.size'] = 12
plt.rcParams['axes.linewidth'] = 1.5
plt.rcParams['axes.labelsize'] = 14
plt.rcParams['axes.facecolor'] = 'none' # make facecolor transparent

fig = plt.figure(figsize=(10, 8))
gs = GridSpec(3, 1, height_ratios=[1, 1, 1], hspace=-.1) # negative hspace for overlap

ax1 = fig.add_subplot(gs[0])
ax1.plot(years, delta_13C, color='green', linewidth=1.0)
ax1.set_ylabel('First', color='green', labelpad=10)
ax1.tick_params(axis='y', colors='green')
ax1.set_xlim(1300, 2000)
ax1.set_ylim(-4, 4)
ax1.xaxis.set_visible(False)
ax1.spines['top'].set_visible(False)
ax1.spines['bottom'].set_visible(False)
ax1.spines['right'].set_visible(False)
ax1.spines['left'].set_color('green')

ax2 = fig.add_subplot(gs[1])
ax2.plot(years, delta_18O, color='blue', linewidth=1.0)
ax2.yaxis.tick_right()
ax2.yaxis.set_label_position("right")
ax2.set_ylabel('Second', color='blue', labelpad=10)
ax2.tick_params(axis='y', colors='blue')
ax2.set_xlim(1300, 2000)
ax2.set_ylim(-3.5, 3.5) # changed the y-limits ever slightly since the previous clipped data
ax2.xaxis.set_visible(False)
ax2.spines['top'].set_visible(False)
ax2.spines['bottom'].set_visible(False)
ax2.spines['left'].set_visible(False)
ax2.spines['right'].set_color('blue')

ax3 = fig.add_subplot(gs[2])
ax3.plot(years, temp_anomaly, color='gray', linewidth=1.0)
ax3.set_ylabel('Third', color='black', labelpad=10)
ax3.set_xlim(1300, 2000)
ax3.set_ylim(-1.0, 1.5)
ax3.set_xlabel('Year (CE)')
ax3.spines['top'].set_visible(False)
ax3.spines['right'].set_visible(False)

plt.show()

Of course a touch of structure can clean up the script a bit as well:

from collections import namedtuple

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec
years = np.linspace(1300, 2000, 700)

np.random.seed(42)

delta_13C = np.cumsum(np.random.normal(0, 0.1, 700))
delta_13C = delta_13C - np.mean(delta_13C)
delta_18O = np.cumsum(np.random.normal(0, 0.08, 700))
delta_18O = delta_18O - np.mean(delta_18O)
temp_anomaly = np.cumsum(np.random.normal(0, 0.03, 700))
temp_anomaly = temp_anomaly - np.mean(temp_anomaly)
temp_anomaly[-100:] += np.linspace(0, 1.5, 100)

plt.style.use('default')
plt.rc('font', size=12)
plt.rc('axes', linewidth=1.5, labelsize=14, facecolor='none')

PlotSettings = namedtuple('PlotSettings', ['data', 'linecolor', 'labelcolor', 'ylabel', 'yrange'])

configurations = [
    PlotSettings(delta_13C,    linecolor='green', labelcolor='green', ylabel='First',  yrange=(-4  , 4  )),
    PlotSettings(delta_18O,    linecolor='blue',  labelcolor='blue',  ylabel='Second', yrange=(-3.5, 3.5)),
    PlotSettings(temp_anomaly, linecolor='gray',  labelcolor='black', ylabel='Third',  yrange=(-1  , 1.5)),
]

fig, axes = plt.subplots(
    nrows=len(configurations), ncols=1, figsize=(10, 8),
    sharex=True, sharey=False,
    gridspec_kw={'hspace': -.1},
)

for i, (config, ax) in enumerate(zip(configurations, axes.flat)):
    ax.plot(years, config.data, color=config.linecolor, linewidth=1.0)

    # Format the X/Y Axes
    ax.set_ylabel(config.ylabel, color=config.labelcolor, labelpad=10)
    ax.tick_params(axis='y', colors=config.labelcolor)
    ax.set_ylim(*config.yrange)
    ax.xaxis.set_visible(False)

    # Format the spines
    ax.spines[['top', 'bottom']].set_visible(False)
    if (i % 2) == 0:
        ax.spines['right'].set_visible(False)
        ax.spines['left' ].set_visible(True)
        ax.spines['left' ].set_color(config.labelcolor)
    else:
        ax.spines['right'].set_visible(True)
        ax.spines['left' ].set_visible(False)
        ax.spines['right'].set_color(config.labelcolor)
        ax.yaxis.tick_right()
        ax.yaxis.set_label_position("right")

# Make special adjustments to the bottom-most plot
axes.flat[-1].spines['bottom'].set_visible(True)
axes.flat[-1].xaxis.set_visible(True)
axes.flat[-1].set_xlabel('Year (CE)')
axes.flat[-1].set_xlim(1300, 2000)

plt.show()
发布评论

评论列表(0)

  1. 暂无评论