def serviceHeaderToggles(serviceObject, instance=None): ss = cells.sessionState() ss.setdefault('showNavTree', True) ss.setdefault('showEditor', True) ss.setdefault('showEvaluation', True) return [ cells.Subscribed(lambda: cells.ButtonGroup([ cells.Button( cells.Octicon("list-unordered"), lambda: ss.toggle('showNavTree'), active=ss.showNavTree), cells.Button( cells.Octicon("terminal"), lambda: ss.toggle('showEditor'), active=ss.showEditor), cells.Button( cells.Octicon("graph"), lambda: ss.toggle('showEvaluation'), active=ss.showEvaluation) ]) ) ]
def projectLine(project): def deleter(): def reallyDelete(): project.deleteSelf() setattr(cells.sessionState(), "modalOverlay", None) cells.sessionState().modalOverlay = cells.Modal( f"Really delete project '{project.name}'?", "Because you can't undo this yet.", Cancel=lambda: setattr(cells.sessionState(), "modalOverlay", None), OK=reallyDelete ).tagged("RFE_DeleteProjectModal") def renamer(): cells.sessionState().modalOverlay = ModalEditBox( f"Rename project '{project.name}'", project.name, onOK=lambda newName: ( setattr(project, 'name', newName), setattr(cells.sessionState(), "modalOverlay", None) ), onCancel=lambda: setattr(cells.sessionState(), 'modalOverlay', None) ).tagged("RFE_RenameProjectModal") def isSelected(): if cells.sessionState().selected_module is not None and cells.sessionState().selected_module.exists(): return cells.sessionState().selected_module.project == project return False return cells.Sequence([ cells.Octicon("file-directory").nowrap(), cells.Subscribed( lambda: cells.Text(project.name).width(200).nowrap() .background_color(None if not isSelected() else SELECTED_PROJECT_COLOR) ).nowrap(), cells.Button( cells.Octicon("pencil").color(BUTTON_COLOR), renamer, small=True, style="light" ).nowrap().tagged(f"RFE_RenameProjectButton_{project._identity}"), cells.Button( cells.Octicon("trashcan").color(BUTTON_COLOR), deleter, small=True, style="light" ).nowrap().tagged(f"RFE_DeleteProjectButton_{project._identity}"), cells.Button( cells.Octicon("plus").color(BUTTON_COLOR), lambda: ResearchFrontend.createNewModule(project), small=True, style="light" ).nowrap().tagged(f"RFE_NewModuleButton_{project._identity}") ] ).nowrap()
def moduleLine(module): def selectModule(): cells.sessionState().selected_module = module def deleter(): def reallyDelete(): module.deleteSelf() setattr(cells.sessionState(), "modalOverlay", None) cells.sessionState().modalOverlay = cells.Modal( f"Really delete '{module.project.name}.{module.name}'?", "Because you can't undo this yet.", Cancel=lambda: setattr(cells.sessionState(), "modalOverlay", None), OK=reallyDelete ).tagged("RFE_DeleteModuleModal") def renamer(): cells.sessionState().modalOverlay = ModalEditBox( f"Rename module '{module.project.name}.{module.name}'", module.name, onOK=lambda newName: ( setattr(module, 'name', newName), setattr(cells.sessionState(), "modalOverlay", None) ), onCancel=lambda: setattr(cells.sessionState(), 'modalOverlay', None) ).tagged("RFE_RenameModuleModal") def isSelected(): if cells.sessionState().selected_module is not None and cells.sessionState().selected_module.exists(): return cells.sessionState().selected_module == module return False return cells.Sequence([ cells.Clickable( cells.Octicon("file").nowrap() + cells.Text(module.name).width(200).nowrap(), selectModule ).nowrap().background_color(None if not isSelected() else SELECTED_MODULE_COLOR), cells.Button( cells.Octicon("pencil").color(BUTTON_COLOR), renamer, small=True, style="light" ).nowrap().tagged(f"RFE_RenameModuleButton_{module._identity}"), cells.Button( cells.Octicon("trashcan").color(BUTTON_COLOR), deleter, small=True, style="light" ).nowrap().tagged(f"RFE_DeleteModuleButton_{module._identity}") ] ).nowrap()
def navDisplay(): def projectView(project): expander = cells.Expands( closed=ResearchFrontend.projectLine(project), open=ResearchFrontend.projectLine(project) + cells.SubscribedSequence( lambda: sorted(Module.lookupAll(project=project), key=lambda m: m.name), lambda m: ResearchFrontend.moduleLine(m) ) ).tagged(f"RFE_ProjectExpander_{project._identity}") def onProjectSelectChanged(): if (cells.sessionState().selected_module and cells.sessionState().selected_module.exists() and cells.sessionState().selected_module.project == project and not expander.isExpanded): expander.isExpanded = True expander.markDirty() return expander + cells.Subscribed(onProjectSelectChanged) return cells.Card( cells.SubscribedSequence( lambda: sorted(Project.lookupAll(), key=lambda p: p.name), projectView ) + cells.Code("\n\n\n\n") + cells.Button("New Project", ResearchFrontend.createNewProject).tagged("RFE_NewProjectButton") ).width(400)
def displayForPlot(display): # grab a context object, which tells us how we should filter our cube data for display purposes. # this must be pushed on the stack above us for us to display properly. datasetStatesUnnamed = display.args datasetStatesNamed = display.kwargs def downsamplePlotData(linePlot): data = {} if len(datasetStatesUnnamed) <= 1: for ds in datasetStatesUnnamed: data.update(makePlotData(ds, "", "series")) else: for i, ds in enumerate(datasetStatesUnnamed): data.update(makePlotData(ds, "", "series_" + str(i + 1))) for name, ds in datasetStatesNamed.items(): data.update(makePlotData(ds, name + ":", name)) with Timer("Downsampling plot data"): #because of slow connection speeds, lets not send more than MAX_POINTS_PER_CHART points total seriesCount = len(data) if seriesCount == 0: return data #first, restrict the dataset to what the xy can hold if linePlot.curXYRanges.get() is not None: minX, maxX = linePlot.curXYRanges.get()[0] for series in data: dim = 'timestamp' if 'timestamp' in data[series] else 'x' indexLeft = (max( 0, data[series][dim].searchsorted(minX - (maxX - minX) / 2)) if minX is not None else 0) indexRight = (min( data[series][dim].searchsorted( maxX + (maxX - minX) / 2, 'right'), len(data[series][dim])) if maxX is not None else 0) data[series][dim] = data[series][dim][indexLeft:indexRight] data[series]['y'] = data[series]['y'][indexLeft:indexRight] #now check our output point count totalPoints = sum(len(data[series]['y']) for series in data) colorIx = 0 if totalPoints > 10000 or candlestick.get(): with Timer("Downsampling %s total points", totalPoints): if candlestick.get(): downsampleRatio = int( numpy.ceil(totalPoints / (500 * len(data)))) else: downsampleRatio = int( numpy.ceil(totalPoints / (2000 * len(data)))) for series in data: dim = 'timestamp' if 'timestamp' in data[ series] else 'x' samplePoints = numpy.arange( len(data[series][dim]) // downsampleRatio) * downsampleRatio if candlestick.get(): # take the average of the points in the middle data[series][dim] = ( numpy.add.reduceat(data[series][dim], samplePoints) / numpy.add.reduceat(data[series][dim] * 0 + 1, samplePoints)) data[series]['open'] = data[series]['y'][ samplePoints[:-1]] data[series]['close'] = data[series]['y'][ samplePoints[1:] - 1] data[series]['high'] = numpy.maximum.reduceat( data[series]['y'], samplePoints) data[series]['low'] = numpy.minimum.reduceat( data[series]['y'], samplePoints) data[series]['decreasing'] = data[series][ 'increasing'] = { 'line': { 'color': nthColor(colorIx) } } colorIx += 1 del data[series]['y'] data[series]['type'] = 'candlestick' else: data[series]['line'] = {'color': nthColor(colorIx)} data[series][dim] = data[series][dim][ samplePoints[1:] - 1] data[series]['y'] = data[series]['y'][ samplePoints[1:] - 1] colorIx += 1 else: for series in data: data[series]['line'] = {'color': nthColor(colorIx)} colorIx += 1 return data def makePlotData(toShow, prefix, emptySeriesName): return {emptySeriesName: {'x': numpy.arange(len(toShow)), 'y': toShow}} showChart = cells.Slot(True) candlestick = cells.Slot(False) def cardContents(): if showChart.get(): xySlot = cells.Slot() return cells.Plot(downsamplePlotData, xySlot=xySlot).width("100%") else: seq = [] for plottedSet in list(display.unnamed) + list( display.named.values()): seq.append( research_app.DisplayForDataset.displayForDataset( DatasetDisplay.Dataset(dataset=plottedSet))) return cells.Sequence(seq) res = cells.Card( cells.Subscribed(cardContents), header=cells.HeaderBar( [cells.Text(display.title)] if display.title else [], [], [ cells.Subscribed(lambda: cells.Button( "Show Candlestick", lambda: candlestick.set(not candlestick.get()), active=candlestick.get()) if showChart.get() else None), cells.Subscribed(lambda: cells.ButtonGroup([ cells.Button(cells.Octicon("graph"), lambda: showChart.set(True), active=showChart.get()), cells.Button(cells.Octicon("three-bars"), lambda: showChart.set(False), active=not showChart.get()) ])) ])) return res