[python] Python / Matplotlib-불연속 축을 만드는 방법이 있습니까?

불연속적인 x 축이있는 플롯을 사용하여 플롯을 만들려고합니다. 이것이 그리는 일반적인 방법은 축이 다음과 같은 것을 갖는 것입니다.

(값) —- // —- (나중 값)

여기서 //는 (값)과 (이후 값) 사이의 모든 것을 건너 뛰고 있음을 나타냅니다.

나는 이것에 대한 예를 찾을 수 없었기 때문에 가능할지 궁금합니다. 예를 들어 금융 데이터에 대한 불연속성에 대한 데이터를 결합 할 수 있다는 것을 알고 있지만 축의 점프를보다 명확하게 만들고 싶습니다. 지금은 서브 플롯 만 사용하고 있지만 결국에는 모든 것이 동일한 그래프에 표시되도록하고 싶습니다.



답변

바울의 대답은이를 수행하는 완벽하게 훌륭한 방법입니다.

그러나 사용자 정의 변환을 원하지 않는 경우 두 개의 서브 플롯을 사용하여 동일한 효과를 만들 수 있습니다.

처음부터 예제를 모으는 대신 matplotlib 예제에서 Paul Ivanov작성한 훌륭한 예제가 있습니다 (몇 달 전에 커밋되었으므로 현재 git 팁에만 있습니다. 아직 웹 페이지에 없습니다.) .

이것은 y 축 대신 불연속적인 x 축을 가지도록이 예제를 간단하게 수정 한 것입니다. (이 게시물을 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()

여기에 이미지 설명 입력

점선 축선 //효과 를 추가하려면 다음을 수행 할 수 있습니다 (다시 Paul Ivanov의 예에서 수정 됨).

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()

여기에 이미지 설명 입력


답변

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')

brokenaxes의 예


답변

비율이 1 : 1이 아닌 gridspec을 사용할 때 대각선 “브레이킹”선의 병렬 방향을 활성화하는 방법에 대한 Frederick Nord의 질문을 처리하면 Paul Ivanov 및 Joe Kingtons의 제안에 따라 다음 변경 사항이 도움이 될 수 있습니다. 너비 비율은 변수 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()


답변

관심있는 사람들을 위해 @Paul 의 답변을 확장하고 ProPlot matplotlib 패키지에 추가했습니다 . 축 “점프”, “속도 향상”및 “슬로우 다운”을 수행 할 수 있습니다 .

현재 Joe의 대답과 같이 이산 점프를 나타내는 “십자”를 추가 할 수있는 방법은 없지만 향후 추가 할 계획입니다. 또한 CutoffScale인수 에 따라 합리적인 기본 틱 위치를 설정하는 기본 “틱 로케이터”를 추가 할 계획 입니다.


답변