marscolonizer
marscolonizer

Reputation: 1

Matplotlib - how to add a break in the x and y axis (only have y so far)

I am trying to add a break in the X axis between the 2 and the 5 (similar to the break in the Y axis between 8 and 36), but cannot figure out how to accomplish both with the current code. Would love some help here!

Per the photo, I'd like to remove the highlighted yellow spot and replace it with diagonal marks (seen in red)

Visual for reference

Code below `

`import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np

# x axis = plan size
# y axis = price

# Create a figure containing a single axes.
fig, ax = plt.subplots()  

#define data
xAxis = [0.5,1,2,5]
apples = [41.99,41.99,41.99,61.99]
bananas = [39.99,39.99,39.99,39.99]
cucumbers = [0.02,0.02,0.40,0.10]
dill = [0.04,0.04,0.08,0.2]
eel = [0.08,0.08,0.16,0.40]
figs = [0.99,1.50,3.00,4.00]
grapes = [1.50,1.50,6.00,6.00]
ax.scatter(xAxis,apples, label='apples')
ax.scatter(xAxis,bananas, label='bananas')
ax.scatter(xAxis,cucumbers, label='cucumbers')
ax.scatter(xAxis,dill, label='dill')
ax.scatter(xAxis,eel, label='eel')
ax.scatter(xAxis,figs, label='figs')
ax.scatter(xAxis,grapes, label='grapes')

#broken axis
f, (ax, ax2) = plt.subplots(2, 1, sharex=False)

# plot the same data on both axes
ax.scatter(xAxis,apples, label='apples')
ax.scatter(xAxis,bananas, label='bananas')
ax.scatter(xAxis,cucumbers, label='cucumbers')
ax.scatter(xAxis,dill, label='dill')
ax.scatter(xAxis,eel, label='eel')
ax.scatter(xAxis,figs, label='figs')
ax.scatter(xAxis,grapes, label='grapes')
ax.set_title('Food spend',loc='Center')

ax2.scatter(xAxis,apples, label='apples')
ax2.scatter(xAxis,bananas, label='bananas')
ax2.scatter(xAxis,cucumbers, label='cucumbers')
ax2.scatter(xAxis,dill, label='dill')
ax2.scatter(xAxis,eel, label='eel')
ax2.scatter(xAxis,figs, label='figs')
ax2.scatter(xAxis,grapes, label='grapes')

# zoom-in / limit the view to different portions of the data
ax.set_ylim(36, 64)  # outliers only
ax2.set_ylim(0, 8)  # most of the data

# hide the spines between ax and ax2
ax.spines['bottom'].set_visible(False)
ax.spines['top'].set_visible(False)
ax.spines.right.set_visible(False) #added by Romeo
ax2.spines.right.set_visible(False) #added by Romeo

ax2.spines['top'].set_visible(False)
ax.xaxis.tick_top()
ax.set_xticks([])
ax.tick_params(labeltop='off')  # don't put tick labels at the top
ax2.xaxis.tick_bottom()
ax2.set_xticks([0,0.5, 1, 2, 5])

d = .015  # how big to make the diagonal lines in axes coordinates
# arguments to pass to plot, just so we don't keep repeating them
kwargs = dict(transform=ax.transAxes, color='k', clip_on=False)
ax.plot((-d, +d), (-d, +d), **kwargs)        # top-left diagonal

kwargs.update(transform=ax2.transAxes)  # switch to the bottom axes
ax2.plot((-d, +d), (1 - d, 1 + d), **kwargs)  # bottom-left diagonal

ax2.set_xlabel('Plan Size', loc= 'center')
ax2.set_ylabel('Cost in USD', loc='top')

ax.legend(loc='center right', bbox_to_anchor=(1.10,0.5), shadow=True)
plt.show()

``

Upvotes: 0

Views: 141

Answers (1)

Martí
Martí

Reputation: 721

Here's a suggestion. Using the same approach but with 4 (top/bottom, left/right) subplots instead of only 2 (top/bottom):

import matplotlib.pyplot as plt
import numpy as np

# x axis = plan size
# y axis = price

#define data
xAxis = [0.5,1,2,5]
apples = [41.99,41.99,41.99,61.99]
bananas = [39.99,39.99,39.99,39.99]
cucumbers = [0.02,0.02,0.40,0.10]
dill = [0.04,0.04,0.08,0.2]
eel = [0.08,0.08,0.16,0.40]
figs = [0.99,1.50,3.00,4.00]
grapes = [1.50,1.50,6.00,6.00]

#broken axis
f = plt.figure(tight_layout=True)
axs = f.subplots(2, 2)
f.suptitle('Food Spend')

# plot the same data on both axes
for ax in axs.flatten():
    ax.scatter(xAxis,apples, label='apples')
    ax.scatter(xAxis,bananas, label='bananas')
    ax.scatter(xAxis,cucumbers, label='cucumbers')
    ax.scatter(xAxis,dill, label='dill')
    ax.scatter(xAxis,eel, label='eel')
    ax.scatter(xAxis,figs, label='figs')
    ax.scatter(xAxis,grapes, label='grapes')


# zoom-in / limit the view to different portions of the data
axs[0, 0].set_xlim(0, 2.5)  # outliers only
axs[0, 1].set_xlim(4, 5.5)  # most of the data
axs[1, 0].set_xlim(0, 2.5)  # outliers only
axs[1, 1].set_xlim(4, 5.5)  # most of the data
axs[0, 0].set_ylim(36, 64)  # outliers only
axs[0, 1].set_ylim(36, 64)  # outliers only
axs[1, 0].set_ylim(0, 8)  # most of the data
axs[1, 1].set_ylim(0, 8)  # most of the data

# hide the spines
axs[0, 0].spines['bottom'].set_visible(False)
axs[0, 1].spines['bottom'].set_visible(False)
axs[1, 0].spines['top'].set_visible(False)
axs[1, 1].spines['top'].set_visible(False)
axs[0, 0].spines.right.set_visible(False)
axs[1, 0].spines.right.set_visible(False)
axs[0, 1].spines.left.set_visible(False)
axs[1, 1].spines.left.set_visible(False)

# hide ticks
axs[0, 0].set_xticks([])
axs[0, 1].set_xticks([])
axs[0, 1].set_yticks([])
axs[1, 1].set_yticks([])
axs[1, 0].set_xticks([0, 0.5, 1, 2])
axs[1, 1].set_xticks([4, 4.5, 5])

d = .015  # how big to make the diagonal lines in axes coordinates
# arguments to pass to plot, just so we don't keep repeating them
kwargs = dict(transform=axs[0, 0].transAxes, color='k', clip_on=False)
axs[0, 0].plot((-d, +d), (-d, +d), **kwargs)        # top-left diagonal
kwargs.update(transform=axs[1, 0].transAxes)  # switch to the bottom axes
axs[1, 0].plot((-d, +d), (1 - d, 1 + d), **kwargs)  # bottom-left diagonal
axs[1, 0].plot((1-d, 1+d), (-d, +d), **kwargs)  # bottom-center-left diagonal
kwargs.update(transform=axs[1, 1].transAxes)  # switch to the bottom axes
axs[1, 1].plot((-d, +d), (-d, d), **kwargs)  # bottom-left diagonal

axs[1, 0].set_xlabel('Plan Size', loc= 'right')
axs[1, 0].set_ylabel('Cost in USD', loc='top')
axs[0, 1].legend(loc='best', bbox_to_anchor=(1.10,0.5), shadow=True)
plt.show()

It can surely be improved, but it's a start. Good luck!

enter image description here

Upvotes: 1

Related Questions