|
| 1 | +""" |
| 2 | +Broken axis example, where the y-axis will have a portion cut out. |
| 3 | +""" |
| 4 | +import matplotlib.pylab as plt |
| 5 | +import numpy as np |
| 6 | + |
| 7 | + |
| 8 | +# 30 points between 0 0.2] originally made using np.random.rand(30)*.2 |
| 9 | +pts = np.array([ 0.015, 0.166, 0.133, 0.159, 0.041, 0.024, 0.195, |
| 10 | + 0.039, 0.161, 0.018, 0.143, 0.056, 0.125, 0.096, 0.094, 0.051, |
| 11 | + 0.043, 0.021, 0.138, 0.075, 0.109, 0.195, 0.05 , 0.074, 0.079, |
| 12 | + 0.155, 0.02 , 0.01 , 0.061, 0.008]) |
| 13 | + |
| 14 | +# Now let's make two outlier points which are far away from everything. |
| 15 | +pts[[3,14]] += .8 |
| 16 | + |
| 17 | +# If we were to simply plot pts, we'd lose most of the interesting |
| 18 | +# details due to the outliers. So let's 'break' or 'cut-out' the y-axis |
| 19 | +# into two portions - use the top (ax) for the outliers, and the bottom |
| 20 | +# (ax2) for the details of the majority of our data |
| 21 | +f,(ax,ax2) = plt.subplots(2,1,sharex=True) |
| 22 | + |
| 23 | +# plot the same data on both axes |
| 24 | +ax.plot(pts) |
| 25 | +ax2.plot(pts) |
| 26 | + |
| 27 | +# zoom-in / limit the view to different portions of the data |
| 28 | +ax.set_ylim(.78,1.) # outliers only |
| 29 | +ax2.set_ylim(0,.22) # most of the data |
| 30 | + |
| 31 | +# hide the spines between ax and ax2 |
| 32 | +ax.spines['bottom'].set_visible(False) |
| 33 | +ax2.spines['top'].set_visible(False) |
| 34 | +ax.xaxis.tick_top() |
| 35 | +ax.tick_params(labeltop='off') # don't put tick labels at the top |
| 36 | +ax2.xaxis.tick_bottom() |
| 37 | + |
| 38 | +# This looks pretty good, and was fairly painless, but you can get that |
| 39 | +# cut-out diagonal lines look with just a bit more work. The important |
| 40 | +# thing to know here is that in axes coordinates, which are always |
| 41 | +# between 0-1, spine endpoints are at these locations (0,0), (0,1), |
| 42 | +# (1,0), and (1,1). Thus, we just need to put the diagonals in the |
| 43 | +# appropriate corners of each of our axes, and so long as we use the |
| 44 | +# right transform and disable clipping. |
| 45 | + |
| 46 | +d = .015 # how big to make the diagonal lines in axes coordinates |
| 47 | +# arguments to pass plot, just so we don't keep repeating them |
| 48 | +kwargs = dict(transform=ax.transAxes, color='k', clip_on=False) |
| 49 | +ax.plot((-d,+d),(-d,+d), **kwargs) # top-left diagonal |
| 50 | +ax.plot((1-d,1+d),(-d,+d), **kwargs) # top-right diagonal |
| 51 | + |
| 52 | +kwargs.update(transform=ax2.transAxes) # switch to the bottom axes |
| 53 | +ax2.plot((-d,+d),(1-d,1+d), **kwargs) # bottom-left diagonal |
| 54 | +ax2.plot((1-d,1+d),(1-d,1+d), **kwargs) # bottom-right diagonal |
| 55 | + |
| 56 | +# What's cool about this is that now if we vary the distance between |
| 57 | +# ax and ax2 via f.subplots_adjust(hspace=...) or plt.subplot_tool(), |
| 58 | +# the diagonal lines will move accordingly, and stay right at the tips |
| 59 | +# of the spines they are 'breaking' |
| 60 | + |
| 61 | +plt.show() |
0 commit comments