Multiple broken axes in Matplotlib: A Rephrased Perspective

Instead of utilizing a logarithmic scale, my intention is to divide the axis, resulting in one half of the subplot’s y-axis ranging from 0 to 10 and the other half ranging from 10 to 100. The gap between the two plots can be modified by: UPDATE: I have nearly solved this issue by implementing gridspec. The remaining concerns include the non-parallelism of the two marker line segments on the broken axis due to the varying length of the y-axis.

Question:

I’m attempting to create a chart with two interruptions in the x-axis. I can generate one disruption using matplotlib.

days = list(range(0,500))
values = list(np.random.randint(low = 10,high=100,size=len(days)))
fig = plt.figure(figsize=(5, 5))
f,(ax,ax2) = plt.subplots(1,2,sharey=True, facecolor='w')
ax.plot(days, values)
ax2.plot(days, values)
ax.set_xlim(0,100)  # x-axis range limited to 0 - 100 
ax2.set_xlim(250, 300)  # x-axis range limited to 250 - 300
# hide the spines between ax and ax2
ax.spines['right'].set_visible(False)
ax2.spines['left'].set_visible(False)
ax.yaxis.tick_left()
ax.tick_params(labelright='off')
d = .015 # how big to make the diagonal lines in axes coordinates
# arguments to pass plot, just so we don't keep repeating them
kwargs = dict(transform=ax.transAxes, color='k', clip_on=False)
ax.plot((1-d,1+d), (-d,+d), **kwargs)
ax.plot((1-d,1+d),(1-d,1+d), **kwargs)
kwargs.update(transform=ax2.transAxes)  # switch to the bottom axes
ax2.plot((-d,+d), (1-d,1+d), **kwargs)
ax2.plot((-d,+d), (-d,+d), **kwargs)
plt.show()

How can I incorporate an additional break, specifically

ax3

, within the range of 400 and 500? Moreover, how can I adjust the length of the x-axis to accurately represent the interval’s length? Ideally, I would like to decrease the length of the right side in the example since it is only half of the interval.

I have attempted to utilize the brokenaxes library, which seems to satisfy the requirements of automatic scaling and enabling multiple breaks. You can refer to the example provided here: https://test-brokenaxes.readthedocs.io/en/latest/auto_examples/plot_usage.html#sphx-glr-auto-examples-plot-usage-py.

Nevertheless, upon executing that code, I encounter

AttributeError: 'SubplotSpec' object has no attribute 'is_last_row'

Any assistance appreciated.


Solution:

The width of the various subplots can be specified by utilizing the argument

gridspec_kw

in

plt.subplots

. Within this argument, the

width_ratios

is defined. For this scenario, the first and third subplots are twice as wide as the middle one, making it possible to employ

(2,1,2)

to set the ratios.

The correct spines for the left axes (

ax1

) should be turned off, while both left and right spines need to be turned off in the middle (

ax2

). Conversely, only the left spine needs to be turned off on the right axes (

ax3

).

By using

ax3.yaxis.tick_right()

, I move the y-axis ticks to the right hand side on the right axes.

To hide the ticks in the middle axes, I utilize

ax2.tick_params(axis='y', length=0)

. It’s important to note that

ax2.set_yticks([])

cannot be used here as it would impact the other axes due to our reliance on

sharey=True

.

Afterward, I utilized the code to sketch the
diagonal lines
from my previous response, incorporating additional lines to accommodate the second break in the x-axis.

All together, that looks like this:

import matplotlib.pyplot as plt
import numpy as np
days = list(range(0,500))
values = list(np.random.randint(low = 10,high=100,size=len(days)))
# use width_ratios to define the width of each subplot
# depending on the range we want to plot
f, (ax1, ax2, ax3) = plt.subplots(1, 3, sharey=True, facecolor='w',
                                  gridspec_kw={'width_ratios': (2, 1, 2)})
ax1.plot(days, values)
ax2.plot(days, values)
ax3.plot(days, values)
ax1.set_xlim(0,100)  # x-axis range limited to 0 - 100 
ax2.set_xlim(250, 300)  # x-axis range limited to 250 - 300
ax3.set_xlim(400, 500)  # x-axis range limited to 400 - 500
# hide the spines between ax and ax2
ax1.spines['right'].set_visible(False)
ax2.spines['left'].set_visible(False)
ax2.spines['right'].set_visible(False)
ax3.spines['left'].set_visible(False)
# Move right hand axes ticks to right hand side
ax3.yaxis.tick_right()
# Turn off ticks on middle axes; so we don't affect the other
# axes ticks, let's just set the length to 0 here
ax2.tick_params(axis='y', length=0)
# Draw the diagonal lines to show broken axes
d = 2.  # proportion of vertical to horizontal extent of the slanted line
kwargs = dict(marker=[(-1, -d), (1, d)], markersize=12,
              linestyle="none", color='k', mec='k', mew=1, clip_on=False)
ax1.plot([1, 1], [0, 1], transform=ax1.transAxes, **kwargs)
ax2.plot([0, 0], [0, 1], transform=ax2.transAxes, **kwargs)
ax2.plot([1, 1], [0, 1], transform=ax2.transAxes, **kwargs)
ax3.plot([0, 0], [0, 1], transform=ax3.transAxes, **kwargs)
plt.savefig('2brokenaxes.png')

Frequently Asked Questions