我試圖創建一個使用pyplot具有不連續的x軸的情節。這是畫的常用方法是,軸將是這樣的:Python/Matplotlib - 有沒有辦法讓一個不連續的軸?
(值)---- ---- //(後值)
其中//表示你跳過(值)和(後面的值)之間的所有內容。
我一直沒能找到任何這樣的例子,所以我想知道如果它甚至是可能的。我知道你可以通過不連續的方式加入數據,例如財務數據,但是我想讓這個軸的跳轉更加明確。目前我只是使用子圖,但我最終希望最終能夠在同一張圖上顯示所有內容。
我試圖創建一個使用pyplot具有不連續的x軸的情節。這是畫的常用方法是,軸將是這樣的:Python/Matplotlib - 有沒有辦法讓一個不連續的軸?
(值)---- ---- //(後值)
其中//表示你跳過(值)和(後面的值)之間的所有內容。
我一直沒能找到任何這樣的例子,所以我想知道如果它甚至是可能的。我知道你可以通過不連續的方式加入數據,例如財務數據,但是我想讓這個軸的跳轉更加明確。目前我只是使用子圖,但我最終希望最終能夠在同一張圖上顯示所有內容。
保羅的回答是這樣的一個完全正常的方法。
但是,如果您不想進行自定義轉換,則可以使用兩個子圖創建相同的效果。
matplotlib示例中只有一個an excellent example of this written by Paul Ivanov(僅在當前的git提示中,因爲它僅在幾個月前提交,尚未在網頁上提供),而不是從頭開始構建示例。
這只是本示例的一個簡單修改,它具有不連續的x軸而不是y軸。 (這就是爲什麼我在做這個職位的CW)
基本上,你只是做這樣的事情:
import matplotlib.pylab as plt
import numpy as np
# If you're not familiar with np.r_, don't worry too much about this. It's just
# a series with points from 0 to 1 spaced at 0.1, and 9 to 10 with the same spacing.
x = np.r_[0:1:0.1, 9:10:0.1]
y = np.sin(x)
fig,(ax,ax2) = plt.subplots(1, 2, sharey=True)
# plot the same data on both axes
ax.plot(x, y, 'bo')
ax2.plot(x, y, 'bo')
# zoom-in/limit the view to different portions of the data
ax.set_xlim(0,1) # most of the data
ax2.set_xlim(9,10) # outliers only
# 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(labeltop='off') # don't put tick labels at the top
ax2.yaxis.tick_right()
# Make the spacing between the two axes a bit smaller
plt.subplots_adjust(wspace=0.15)
plt.show()
要添加破軸線//
效果,我們可以做這(再次,從保羅·伊萬諾夫的例子修改):
import matplotlib.pylab as plt
import numpy as np
# If you're not familiar with np.r_, don't worry too much about this. It's just
# a series with points from 0 to 1 spaced at 0.1, and 9 to 10 with the same spacing.
x = np.r_[0:1:0.1, 9:10:0.1]
y = np.sin(x)
fig,(ax,ax2) = plt.subplots(1, 2, sharey=True)
# plot the same data on both axes
ax.plot(x, y, 'bo')
ax2.plot(x, y, 'bo')
# zoom-in/limit the view to different portions of the data
ax.set_xlim(0,1) # most of the data
ax2.set_xlim(9,10) # outliers only
# 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(labeltop='off') # don't put tick labels at the top
ax2.yaxis.tick_right()
# Make the spacing between the two axes a bit smaller
plt.subplots_adjust(wspace=0.15)
# This looks pretty good, and was fairly painless, but you can get that
# cut-out diagonal lines look with just a bit more work. The important
# thing to know here is that in axes coordinates, which are always
# between 0-1, spine endpoints are at these locations (0,0), (0,1),
# (1,0), and (1,1). Thus, we just need to put the diagonals in the
# appropriate corners of each of our axes, and so long as we use the
# right transform and disable clipping.
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) # top-left diagonal
ax.plot((1-d,1+d),(1-d,1+d), **kwargs) # bottom-left diagonal
kwargs.update(transform=ax2.transAxes) # switch to the bottom axes
ax2.plot((-d,d),(-d,+d), **kwargs) # top-right diagonal
ax2.plot((-d,d),(1-d,1+d), **kwargs) # bottom-right diagonal
# What's cool about this is that now if we vary the distance between
# ax and ax2 via f.subplots_adjust(hspace=...) or plt.subplot_tool(),
# the diagonal lines will move accordingly, and stay right at the tips
# of the spines they are 'breaking'
plt.show()
我看到這個功能的許多建議,但沒有表明它已經實施。這是一個可行的解決方案。它對x軸應用了階躍函數變換。這是很多代碼,但它很簡單,因爲它大部分都是樣板自定義比例。我沒有添加任何圖形來指示休息的位置,因爲這是一個風格問題。祝你好運完成這份工作。
from matplotlib import pyplot as plt
from matplotlib import scale as mscale
from matplotlib import transforms as mtransforms
import numpy as np
def CustomScaleFactory(l, u):
class CustomScale(mscale.ScaleBase):
name = 'custom'
def __init__(self, axis, **kwargs):
mscale.ScaleBase.__init__(self)
self.thresh = None #thresh
def get_transform(self):
return self.CustomTransform(self.thresh)
def set_default_locators_and_formatters(self, axis):
pass
class CustomTransform(mtransforms.Transform):
input_dims = 1
output_dims = 1
is_separable = True
lower = l
upper = u
def __init__(self, thresh):
mtransforms.Transform.__init__(self)
self.thresh = thresh
def transform(self, a):
aa = a.copy()
aa[a>self.lower] = a[a>self.lower]-(self.upper-self.lower)
aa[(a>self.lower)&(a<self.upper)] = self.lower
return aa
def inverted(self):
return CustomScale.InvertedCustomTransform(self.thresh)
class InvertedCustomTransform(mtransforms.Transform):
input_dims = 1
output_dims = 1
is_separable = True
lower = l
upper = u
def __init__(self, thresh):
mtransforms.Transform.__init__(self)
self.thresh = thresh
def transform(self, a):
aa = a.copy()
aa[a>self.lower] = a[a>self.lower]+(self.upper-self.lower)
return aa
def inverted(self):
return CustomScale.CustomTransform(self.thresh)
return CustomScale
mscale.register_scale(CustomScaleFactory(1.12, 8.88))
x = np.concatenate((np.linspace(0,1,10), np.linspace(9,10,10)))
xticks = np.concatenate((np.linspace(0,1,6), np.linspace(9,10,6)))
y = np.sin(x)
plt.plot(x, y, '.')
ax = plt.gca()
ax.set_xscale('custom')
ax.set_xticks(xticks)
plt.show()
我想這將只是現在做的事。這將是我第一次搞亂自定義軸,所以我們只需要看看它是如何發展的。 – 2011-04-14 19:35:40
'InvertedCustomTransform'的'def transform'中有一個小錯字,它應該讀取'self.upper'而不是'upper'。儘管感謝這個偉大的例子! – 2012-01-10 17:11:22
你可以添加幾行來演示如何使用你的類嗎? – 2015-04-23 13:34:35
關於弗雷德裏克諾德的問題如何在使用比例不等於1:1的網格時允許對角「斷裂」線的平行定向,根據保羅伊萬諾夫和喬金頓的建議進行以下更改可能會有幫助。寬度比率可以使用變量n和m來改變。
import matplotlib.pylab as plt
import numpy as np
import matplotlib.gridspec as gridspec
x = np.r_[0:1:0.1, 9:10:0.1]
y = np.sin(x)
n = 5; m = 1;
gs = gridspec.GridSpec(1,2, width_ratios = [n,m])
plt.figure(figsize=(10,8))
ax = plt.subplot(gs[0,0])
ax2 = plt.subplot(gs[0,1], sharey = ax)
plt.setp(ax2.get_yticklabels(), visible=False)
plt.subplots_adjust(wspace = 0.1)
ax.plot(x, y, 'bo')
ax2.plot(x, y, 'bo')
ax.set_xlim(0,1)
ax2.set_xlim(10,8)
# 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(labeltop='off') # don't put tick labels at the top
ax2.yaxis.tick_right()
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)
on = (n+m)/n; om = (n+m)/m;
ax.plot((1-d*on,1+d*on),(-d,d), **kwargs) # bottom-left diagonal
ax.plot((1-d*on,1+d*on),(1-d,1+d), **kwargs) # top-left diagonal
kwargs.update(transform=ax2.transAxes) # switch to the bottom axes
ax2.plot((-d*om,d*om),(-d,d), **kwargs) # bottom-right diagonal
ax2.plot((-d*om,d*om),(1-d,1+d), **kwargs) # top-right diagonal
plt.show()
檢查brokenaxes包:
import matplotlib.pyplot as plt
from brokenaxes import brokenaxes
import numpy as np
fig = plt.figure(figsize=(5,2))
bax = brokenaxes(xlims=((0, .1), (.4, .7)), ylims=((-1, .7), (.79, 1)), hspace=.05)
x = np.linspace(0, 1, 100)
bax.plot(x, np.sin(10 * x), label='sin')
bax.plot(x, np.cos(10 * x), label='cos')
bax.legend(loc=3)
bax.set_xlabel('time')
bax.set_ylabel('value')
安裝完畢後,Pycharm Community 2016.3.2不能從'brokenaxes導入brokenaxes''。 @ ben.dichter – 2017-08-21 07:24:41
有一個錯誤。我修好了它。請運行'pip install brokenaxes == 0.2'來安裝固定版本的代碼。 – 2017-08-22 13:35:52
似乎與ax.grid交互不良(True) – innisfree 2017-12-12 00:09:15
我自己不能說得更好;) – 2011-08-02 18:13:57
只有子圖的比例爲1:1時,纔會使'//效果的方法好用。你知道如何使它以任何比例工作,例如'GridSpec(width_ratio = [N,M])'? – 2014-03-17 23:40:46