def load_existing_ekgAnnotations(startTime, endTime, ekgNote): """Loads existing annotations from file. Parameters -- from column file headers ---------- startTime:str Timestamp marking beginning of annotation, preferably in ISO format. endTime:str Timestamp marking end of annotation, preferably in ISO format. ekgNote:str Annotation code for EKG (e.g. "EKG Interpretable") Returns ------- """ ekgIdx = annotatorSettings.ekgCodes.index(ekgNote) ekgComments = BoxAnnotation( fill_color=annotatorSettings.ekgColorSelector[ekgIdx]) views.ekgViewer.add_layout(ekgComments) # FIXME: Timestamp issue likely in the future. # I honestly do not know why these values work...but there is a current issue with Bokeh datetime. # I subtracted the timestamp provided by x1 and the known epoch UTC timestamp of 1/1/2020 to get 18000000000000. # I divided by various magnitudes of 10 until timestamp on bokeh was correct. ekgComments.left = pd.to_datetime(str(startTime)).tz_localize('Etc/GMT+4') ekgComments.right = pd.to_datetime(str(endTime)).tz_localize('Etc/GMT+4')
def load_existing_ekgAnnotations(startTime, endTime, ekgNote): """Loads existing annotations from file. Parameters -- from column file headers ---------- startTime:str Timestamp marking beginning of annotation, preferably in ISO format. endTime:str Timestamp marking end of annotation, preferably in ISO format. ekgNote:str Annotation code for EKG (e.g. "EKG Interpretable") Returns ------- """ global ekgColorSelector ekgIdx = annotatorSettings.ekgCodes.index(ekgNote) ekgComments = BoxAnnotation(fill_color=ekgColorSelector[ekgIdx]) ekgViewer.add_layout(ekgComments) # FIXME: Timestamp issue likely in the future. # I honestly do not know why these values work...but there is a current issue with Bokeh datetime. # I subtracted the timestamp provided by x1 and the known epoch UTC timestamp of 1/1/2020 to get 18000000000000. # I divided by various magnitudes of 10 until timestamp on bokeh was correct. ekgComments.left = pd.to_datetime(str(startTime)).tz_localize('Etc/GMT+4') ekgComments.right = pd.to_datetime(str(endTime)).tz_localize('Etc/GMT+4')
def load_existing_ppgQos_annotations(startTime, endTime, ppgNote, qosNote): """Loads existing annotations from file. Parameters -- from file column headers ---------- startTime:str Timestamp marking beginning of annotation, preferably in ISO format. endTime:str Timestamp marking end of annotation, preferably in ISO format. ppgNote:str Annotation code for PPG (e.g. "PPG Interpretable") qosNote:str Annotation code for QoS (e.g. "QoS Correct") Returns ------- """ global ppgColorSelector, ppgViewer ppgIdx = annotatorSettings.ppgCodes.index(ppgNote) qosIdx = annotatorSettings.qosCodes.index(qosNote) # Use ppgNote and qosNote to determine color of loaded annotation to add to plot. ppgComments = BoxAnnotation(fill_color=ppgColorSelector[ppgIdx]) ppgViewer.add_layout(ppgComments) # FIXME: Timestamp issue likely in the future. # I honestly do not know why these values work...but there is a current issue with Bokeh datetime. # I subtracted the timestamp provided by x1 and the known epoch UTC timestamp of 1/1/2020 to get 18000000000000. # I divided by various magnitudes of 10 until timestamp on bokeh was correct. ppgComments.left = (pd.to_datetime(str(startTime)).value + 18000000000000) / 1000000 ppgComments.right = (pd.to_datetime(str(endTime)).value + 18000000000000) / 1000000 qosComments = BoxAnnotation(fill_color=qosColorSelector[qosIdx], fill_alpha=1) ppgViewer.add_layout(qosComments) qosComments.top = annotatorSettings.ppgYRange[1] qosComments.bottom = annotatorSettings.ppgYRange[1] - 100 qosComments.left = (pd.to_datetime(str(startTime)).value + 18000000000000) / 1000000 qosComments.right = (pd.to_datetime(str(endTime)).value + 18000000000000) / 1000000
def ppgViewerSelectionCallback(attr, old, new): """Create an annotation based on the geometry of the box select tool. Parameters ---------- attr:str 'geometries' old:list e.g. [{'vx0': 464, 'vy0': 23.7869873046875, 'y0': 0, 'y1': 4503.400000000001, 'type': 'rect', 'x0': 1481149362095.9377, 'vx1': 552, 'x1': 1481149364565.3564, 'vy1': 341.03603515625}] new:list e.g. [{'vx0': 464, 'vy0': 23.7869873046875, 'y0': 0, 'y1': 4503.400000000001, 'type': 'rect', 'x0': 1481149362095.9377, 'vx1': 552, 'x1': 1481149364565.3564, 'vy1': 341.03603515625}] Returns ------- """ # Provide globals to help reader know what is local and global global ppgViewer, ppgDataFrame, args, ppgColorSelector, qosColorSelector, ppgButtonGroup, qosButtonGroup # Edge case. Make sure minimum x value for annotation is 0. if new[0]['x0'] < 0: x0 = 0 else: x0 = abs(int(new[0]['x0'])) x1 = abs(int(new[0]['x1'])) # Create box annotation. Color of annotation depends on which button in a group is selected (active). ppgComments = BoxAnnotation( fill_color=ppgColorSelector[ppgButtonGroup.active]) ppgViewer.add_layout(ppgComments) ppgComments.left = x0 ppgComments.right = x1 # Create box annotation. Color of annotation depends on which button in a group is selected (active). qosComments = BoxAnnotation( fill_color=qosColorSelector[qosButtonGroup.active], fill_alpha=1) ppgViewer.add_layout(qosComments) qosComments.top = annotatorSettings.ppgYRange[1] qosComments.bottom = annotatorSettings.ppgYRange[1] - 100 qosComments.left = x0 qosComments.right = x1 save_annotation_dimensions(x0, x1, args.spo2QosAnnotatedFile)
def ppgViewerSelectionCallback(attr, old, new): """Create an annotation based on the geometry of the box select tool. Parameters ---------- attr:str 'geometries' old:list e.g. [{'vx0': 464, 'vy0': 23.7869873046875, 'y0': 0, 'y1': 4503.400000000001, 'type': 'rect', 'x0': 1481149362095.9377, 'vx1': 552, 'x1': 1481149364565.3564, 'vy1': 341.03603515625}] new:list e.g. [{'vx0': 464, 'vy0': 23.7869873046875, 'y0': 0, 'y1': 4503.400000000001, 'type': 'rect', 'x0': 1481149362095.9377, 'vx1': 552, 'x1': 1481149364565.3564, 'vy1': 341.03603515625}] Returns ------- """ # Provide globals to help reader know what is local and global global ppgViewer, ppgDataFrame, args, ppgColorSelector, qosColorSelector, ppgButtonGroup, qosButtonGroup # Edge case. Make sure minimum x value for annotation is 0. if new[0]['x0'] < 0: x0 = 0 else: x0 = abs(int(new[0]['x0'])) x1 = abs(int(new[0]['x1'])) # Create box annotation. Color of annotation depends on which button in a group is selected (active). ppgComments = BoxAnnotation(fill_color=ppgColorSelector[ppgButtonGroup.active]) ppgViewer.add_layout(ppgComments) ppgComments.left = x0 ppgComments.right = x1 # # Create box annotation. Color of annotation depends on which button in a group is selected (active). # qosComments = BoxAnnotation(fill_color=qosColorSelector[qosButtonGroup.active], fill_alpha=1) # ppgViewer.add_layout(qosComments) # # qosComments.top = annotatorSettings.ppgYRange[1] # qosComments.bottom = annotatorSettings.ppgYRange[1] - 100 # qosComments.left = x0 # qosComments.right = x1 save_annotation_dimensions(x0,x1,args.spo2QosAnnotatedFile)
def ekgViewerSelectionCallback(attr, old, new): """Create an annotation based on the geometry of the box select tool. Parameters ---------- attr:str 'geometries' old:list e.g. [{'vx0': 464, 'vy0': 23.7869873046875, 'y0': 0, 'y1': 4503.400000000001, 'type': 'rect', 'x0': 1481149362095.9377, 'vx1': 552, 'x1': 1481149364565.3564, 'vy1': 341.03603515625}] new:list e.g. [{'vx0': 464, 'vy0': 23.7869873046875, 'y0': 0, 'y1': 4503.400000000001, 'type': 'rect', 'x0': 1481149362095.9377, 'vx1': 552, 'x1': 1481149364565.3564, 'vy1': 341.03603515625}] Returns ------- """ # Provide globals to help reader know what is local and global global ekgViewer, args, ekgColorSelector, ekgButtonGroup # Edge case. Make sure minimum x value for annotation is 0. if new[0]['x0'] < 0: x0 = 0 else: x0 = abs(int(new[0]['x0'])) x1 = abs(int(new[0]['x1'])) # Create box annotation. Color of annotation depends on which button in a group is selected (active). ekgComments = BoxAnnotation( fill_color=ekgColorSelector[ekgButtonGroup.active]) ekgComments.left = x0 ekgComments.right = x1 ekgViewer.add_layout(ekgComments) save_annotation_dimensions(x0, x1, args.ekgAnnotatedFile)
def ekgViewerSelectionCallback(attr, old, new): """Create an annotation based on the geometry of the box select tool. Parameters ---------- attr:str 'geometries' old:list e.g. [{'vx0': 464, 'vy0': 23.7869873046875, 'y0': 0, 'y1': 4503.400000000001, 'type': 'rect', 'x0': 1481149362095.9377, 'vx1': 552, 'x1': 1481149364565.3564, 'vy1': 341.03603515625}] new:list e.g. [{'vx0': 464, 'vy0': 23.7869873046875, 'y0': 0, 'y1': 4503.400000000001, 'type': 'rect', 'x0': 1481149362095.9377, 'vx1': 552, 'x1': 1481149364565.3564, 'vy1': 341.03603515625}] Returns ------- """ # Provide globals to help reader know what is local and global global ekgViewer, args, ekgColorSelector, ekgButtonGroup # Edge case. Make sure minimum x value for annotation is 0. if new[0]['x0'] < 0: x0 = 0 else: x0 = abs(int(new[0]['x0'])) x1 = abs(int(new[0]['x1'])) # Create box annotation. Color of annotation depends on which button in a group is selected (active). ekgComments = BoxAnnotation(fill_color=ekgColorSelector[ekgButtonGroup.active]) ekgComments.left = x0 ekgComments.right = x1 ekgViewer.add_layout(ekgComments) save_annotation_dimensions(x0,x1,args.ekgAnnotatedFile)
def load_existing_ppgQos_annotations(startTime, endTime, ppgNote, qosNote): """Loads existing annotations from file. Parameters -- from file column headers ---------- startTime:str Timestamp marking beginning of annotation, preferably in ISO format. endTime:str Timestamp marking end of annotation, preferably in ISO format. ppgNote:str Annotation code for PPG (e.g. "PPG Interpretable") qosNote:str Annotation code for QoS (e.g. "QoS Correct") Returns ------- """ global ppgColorSelector, ppgViewer if ppgNote != '': ppgIdx = annotatorSettings.ppgCodes.index(ppgNote) # Use ppgNote and qosNote to determine color of loaded annotation to add to plot. ppgComments = BoxAnnotation(fill_color=ppgColorSelector[ppgIdx]) ppgViewer.add_layout(ppgComments) # FIXME: Timestamp issue likely in the future. # I honestly do not know why these values work...but there is a current issue with Bokeh datetime. # I subtracted the timestamp provided by x1 and the known epoch UTC timestamp of 1/1/2020 to get 18000000000000. # I divided by various magnitudes of 10 until timestamp on bokeh was correct. ppgComments.left = pd.to_datetime(str(startTime)).tz_localize('Etc/GMT+4') ppgComments.right = pd.to_datetime(str(endTime)).tz_localize('Etc/GMT+4') if qosNote != '': qosIdx = annotatorSettings.qosCodes.index(qosNote) qosComments = BoxAnnotation(fill_color=qosColorSelector[qosIdx],fill_alpha=0.5) ppgViewer2.add_layout(qosComments) # qosComments.top = annotatorSettings.ppgYRange[1] # qosComments.bottom = annotatorSettings.ppgYRange[1] - 100 qosComments.left = pd.to_datetime(str(startTime)).tz_localize('Etc/GMT+4') qosComments.right = pd.to_datetime(str(endTime)).tz_localize('Etc/GMT+4')
def add_anno(): alarm = alarms.alarms[alarmNumber] ala = BoxAnnotation(fill_color=annotatorSettings.alarmColor, fill_alpha=0.5) ala2 = BoxAnnotation(fill_color=annotatorSettings.alarmColor, fill_alpha=0.5) ala3 = BoxAnnotation(fill_color=annotatorSettings.alarmColor, fill_alpha=0.5) ala5 = BoxAnnotation(fill_color=annotatorSettings.alarmColor, fill_alpha=0.5) ala6 = BoxAnnotation(fill_color=annotatorSettings.alarmColor, fill_alpha=0.5) ala7 = BoxAnnotation(fill_color=annotatorSettings.alarmColor, fill_alpha=0.5) views.ekgViewer.add_layout(ala) views.ppgViewer.add_layout(ala2) views.hrViewer.add_layout(ala3) views.bpViewer.add_layout(ala5) views.spo2Viewer.add_layout(ala6) views.ppgViewer2.add_layout(ala7) ala.left = pd.to_datetime(str(alarm)) - pd.Timedelta('0.25 seconds') ala.right = pd.to_datetime(str(alarm)) + pd.Timedelta('0.25 seconds') ala2.left = pd.to_datetime(str(alarm)) - pd.Timedelta('0.25 seconds') ala2.right = pd.to_datetime(str(alarm)) + pd.Timedelta('0.25 seconds') ala3.left = pd.to_datetime(str(alarm)) - pd.Timedelta('0.25 seconds') ala3.right = pd.to_datetime(str(alarm)) + pd.Timedelta('0.25 seconds') ala5.left = pd.to_datetime(str(alarm)) - pd.Timedelta('0.25 seconds') ala5.right = pd.to_datetime(str(alarm)) + pd.Timedelta('0.25 seconds') ala6.left = pd.to_datetime(str(alarm)) - pd.Timedelta('0.25 seconds') ala6.right = pd.to_datetime(str(alarm)) + pd.Timedelta('0.25 seconds') ala7.left = pd.to_datetime(str(alarm)) - pd.Timedelta('0.25 seconds') ala7.right = pd.to_datetime(str(alarm)) + pd.Timedelta('0.25 seconds')
# Availability: https://github.com/bokeh/bokeh # ################################################# from bokeh.core.properties import Bool, List, Instance, String, Enum, Int from bokeh.models.annotations import Label from bokeh.models.tools import Drag, BoxAnnotation from bokeh.models.renderers import Renderer from bokeh.models.callbacks import Callback from bokeh.core.enums import Dimensions _DEFAULT_BOX_ANNOTATION = lambda: BoxAnnotation(level="overlay", render_mode="css", top_units="screen", left_units="screen", bottom_units="screen", right_units="screen", fill_color="#ff3333", fill_alpha=0.3, line_color="red", line_alpha=1.0, line_width=2, line_dash=[4, 4]) class MeasureJTool(Drag): __implementation__ = "measureJTool.ts" names = List(String) renderers = List(Instance(Renderer))
with open(spo2QosAnnotatedFile, 'r') as readfile: reader = csv.reader(readfile) next(reader) for row in reader: load_existing_ppgQos_annotations(row[0], row[1], row[2], row[3]) with open(ekgAnnotatedFile, 'r') as readfile: reader = csv.reader(readfile) next(reader) for row in reader: load_existing_ekgAnnotations(row[0], row[1], row[2]) for alarm in alarms: ala = BoxAnnotation(fill_color=annotatorSettings.alarmColor, fill_alpha=0.5) ala2 = BoxAnnotation(fill_color=annotatorSettings.alarmColor, fill_alpha=0.5) ala3 = BoxAnnotation(fill_color=annotatorSettings.alarmColor, fill_alpha=0.5) ala4 = BoxAnnotation(fill_color=annotatorSettings.alarmColor, fill_alpha=0.5) ala5 = BoxAnnotation(fill_color=annotatorSettings.alarmColor, fill_alpha=0.5) ala6 = BoxAnnotation(fill_color=annotatorSettings.alarmColor, fill_alpha=0.5) ekgViewer.add_layout(ala) ppgViewer.add_layout(ala2) hrViewer.add_layout(ala3) ekgViewer.add_layout(ala4)
with open(spo2QosAnnotatedFile,'r') as readfile: reader = csv.reader(readfile) next(reader) for row in reader: load_existing_ppgQos_annotations(row[0], row[1], row[2], row[3]) with open(ekgAnnotatedFile,'r') as readfile: reader = csv.reader(readfile) next(reader) for row in reader: load_existing_ekgAnnotations(row[0], row[1], row[2]) for alarm in alarms: ala = BoxAnnotation(fill_color=annotatorSettings.alarmColor,fill_alpha=0.5) ala2 = BoxAnnotation(fill_color=annotatorSettings.alarmColor,fill_alpha=0.5) ala3 = BoxAnnotation(fill_color=annotatorSettings.alarmColor,fill_alpha=0.5) ala4 = BoxAnnotation(fill_color=annotatorSettings.alarmColor,fill_alpha=0.5) ala5 = BoxAnnotation(fill_color=annotatorSettings.alarmColor,fill_alpha=0.5) ala6 = BoxAnnotation(fill_color=annotatorSettings.alarmColor,fill_alpha=0.5) ekgViewer.add_layout(ala) ppgViewer.add_layout(ala2) hrViewer.add_layout(ala3) ekgViewer.add_layout(ala4) bpViewer.add_layout(ala5) spo2Viewer.add_layout(ala6) ala.left = pd.to_datetime(str(alarm))-pd.Timedelta('0.25 seconds')