오디오 편집에 사용 된 것과 매우 유사한 다중 채널 플롯을 만들려고하지만 의료 데이터 용입니다.PyGTK의 카이로 데이터 플로터 : pixbuffer를 사용해야하나요?
이러한 종류의 프로그램은 의미있는 이벤트를 찾아 분류하기 위해 (다른 것들 중에서) 데이터 플롯 위로 수평으로 확대/축소해야하는 사람이 사용해야합니다.
그래서 나는 데이터의 첫 번째와 마지막 인덱스를 기반으로 카이로를 사용하여 gtk.DrawingArea에 플롯 할 데이터 스트림 (수만 개의 샘플 목록)을 갖습니다. 플롯 할 데이터 간격과 그리기 영역의 픽셀 너비 사이의 너비를 지정합니다. 대부분의 이미지 뷰어 및 Google지도와 마찬가지로 데이터를 "드래그"하기 위해 일부 마우스 이벤트를 만들었지 만 (지금까지는 수평축에서만 작업하고 있습니다).
사실 : 패닝이 매우 느리고 다시 그려지기 때문에 다시 그려지는데, 이는 다시 그려지는 간격의 길이에 따라 달라지기 때문에 생각합니다. ("확대/축소"설정과 관련하여 더 많은 것을 보여줍니다. 고밀도 데이터 간격). 나는 전체 플롯을 (큰) pixbuffer로 렌더링해야하는지 궁금하다.이 pixbuffer를 재배치하면 해당 부분이 윈도우 그리기 영역에 커밋된다.
그래서, 내 질문은 :? "보통 Pygtk에서 수행 를 팬/줌 음모를 꾸미고 2D 이러한 종류의 데이터가 어떻게 그 일의 '표준'방법이 있나요 나는 거대한 pixbuffer를 작성해야하는 I 카이로 원천으로 사용할 수 있고 그것을 번역하고 그림 영역 카이로 표면에 '찍기'할 수 있습니까? 사람이 같은 목표를 달성하는 다른 방법에 대한 다른 팁이 있다면
class DataView(gtk.DrawingArea):
""" Plots a 'rectangle' of the data, depending on predefined horizontal and vertical ranges """
def __init__(self, channel):
gtk.DrawingArea.__init__(self)
self.connect("expose_event", self.expose)
self.channel = dados.channel_content[channel]
self.top = int(self.channel['pmax'])
self.bottom = int(self.channel['pmin'])
# this part defines position and size of the plotting
self.x_offset = 0
self.y_offset = 0
self.x_scale = 1
self.y_scale = 0.01
def expose(self, widget, event):
cr = widget.window.cairo_create()
rect = self.get_allocation()
w = rect.width
h = rect.height
cr.translate(0, h/2)
cr.scale(1,-1)
cr.save()
self.x_scale = 1.*w/(signalpanel.end - signalpanel.start)
cr.translate(self.x_offset, self.y_offset)
cr.scale(self.x_scale, self.y_scale)
step = 5
# here I select a slice of my full data list
stream = self.channel['recording'][signalpanel.start:signalpanel.end:step]
# here I draw
cr.move_to(0, stream[0])
for n,s in enumerate(stream[1:]):
cr.line_to((n+1)*step, s)
cr.restore()
cr.set_source_rgb(0,0,0)
cr.set_line_width(1)
cr.stroke()
class ChannelView(gtk.HBox):
""" contains a DataView surrounded by all other satellite widgets """
def __init__(self, channel):
gtk.HBox.__init__(self)
labelpanel = gtk.VBox()
labelpanel.set_size_request(100, 100)
dataview = DataView(channel)
dataview.connect("motion_notify_event", onmove)
dataview.connect("button_press_event", onpress)
dataview.connect("button_release_event", onrelease)
dataview.connect("destroy", gtk.main_quit)
dataview.add_events(gtk.gdk.EXPOSURE_MASK
| gtk.gdk.LEAVE_NOTIFY_MASK
| gtk.gdk.BUTTON_PRESS_MASK
| gtk.gdk.BUTTON_RELEASE_MASK
| gtk.gdk.POINTER_MOTION_MASK
| gtk.gdk.POINTER_MOTION_HINT_MASK)
self.pack_end(dataview, True, True)
self.pack_end(gtk.VSeparator(), False, False)
#populate labelpanel
""" a lot of widget-creating code (ommited) """
# three functions to pan the data with the mouse
def onpress(widget, event):
if event.button == 1:
signalpanel.initial_position = event.x
signalpanel.start_x = signalpanel.start
signalpanel.end_x = signalpanel.end
signalpanel.queue_draw()
def onmove(widget, event):
if signalpanel.initial_position:
signalpanel.start = max(0, int((signalpanel.start_x - (event.x-signalpanel.initial_position))*widget.x_scale))
signalpanel.end = int((signalpanel.end_x - (event.x-signalpanel.initial_position))*widget.x_scale)
print signalpanel.start, signalpanel.end
signalpanel.queue_draw()
def onrelease(widget, event):
signalpanel.initial_position = None
signalpanel.queue_draw()
class PlotterPanel(gtk.VBox):
""" Defines a vertical panel with special features to manage multichannel plots """
def __init__(self):
gtk.VBox.__init__(self)
self.initial_position = None
# now these are the indexes defining the slice to plot
self.start = 0
self.end = 20000 # full list has 120000 values
if __name__ == "__main__":
folder = os.path.expanduser('~/Dropbox/01MIOTEC/06APNÉIA/Samples')
dados = EDF_Reader(folder, 'Osas2002plusQRS.rec') # the file from where the data come from
window = gtk.Window()
signalpanel = PlotterPanel()
signalpanel.pack_start(ChannelView('Resp abdomen'), True, True)
window.add(signalpanel)
window.connect("delete-event", gtk.main_quit)
window.set_position(gtk.WIN_POS_CENTER)
window.show_all()
gtk.main()
또한, 나는 그것을받을 매우 기쁠 :
는 내 코드의 일부는 다음과 수축.
EDIT를 읽기위한
감사합니다 : 나는 플롯에 사용할 수있는 픽셀 사이의 비율에 변수 step
의존하게 코드를 변경하고 데이터의 간격 아이폰에 플롯 할 수 없습니다. 이 방법으로, 창에 1000 픽셀 만있는 경우 전체 샘플 중에서 1000 개의 샘플 값만있는 "슬라이스"가 사용됩니다. 결과가 너무 부드럽지는 않지만 매우 빠르며 자세한 내용을 원하면 확대하여 해상도를 높일 수 있습니다 (따라서 단계 재 계산)
나는 그것이 내가 지금까지 얻었던 (그리고 @ilius 대답이 속도 문제를 해결하지 못했기 때문에) 내 자신의 질문에 대답했다. 물론 다른 대답도 환영한다. – heltonbiker