def layout_graphs(self): """ compute a rectangular layout of graphs within the panel and assign them those locations """ self.graph_layout = [] if self.x >= 0: # if the panel has been sized ngraphs = len(self.graphs) best_fit = None min_dxy = None for cols in range(1, ngraphs + 1): for rows in range(1, ngraphs + 1): if rows * cols >= ngraphs: dx = self.width // cols dy = self.height // rows dxy = max(dx, dy) - min(dx, dy) if min_dxy == None or dxy < min_dxy: min_dxy = dxy best_fit = (rows, cols, dy, dx) rows, cols, dy, dx = best_fit x = 0 y = 0 for g in self.graphs: self.graph_layout.append((y, x, dy, dx)) pad = self.get_pad() if pad: g_pad = pad.subpad(dy, dx, y, x) g_canvas = canvas.Canvas(g_pad) g.set_canvas(g_canvas) x += dx if x >= self.width: x = 0 y += dy return self.graph_layout
def main(stdscr): screen_size(40,100) stdscr.clear() python_path = os.path.dirname(os.path.dirname(request.fspath)) c_names = ["X-Series","Pie Labels","Metric 1","Metric 2","Metric 3","Metric 4","Metric 5","Metric 6"] d = DataTable() for c in c_names: d.add_column(Column(name=c)) for idx in range(0,10): d.put(idx,"X-Series",Cell(int_type,idx*10,format_int)) d.put(idx,"Pie Labels",Cell(string_type,"Group %d"%idx,format_string)) d.put(idx,"Metric 1",Cell(float_type,50.0+(idx*20),format_float)) d.put(idx,"Metric 2",Cell(float_type,75.0+(idx*30),format_float)) d.put(idx,"Metric 3",Cell(float_type,100.0+(idx*40),format_float)) d.put(idx,"Metric 4",Cell(float_type,123.0+(idx*23),format_float)) d.put(idx,"Metric 5",Cell(float_type,143+(idx*33),format_float)) d.put(idx,"Metric 6",Cell(float_type,171+(idx*51),format_float)) c = canvas.Canvas(stdscr) max_x,max_y = c.get_maxxy() g = graph.BarGraph(d,"X-Series",["Metric 1","Metric 3","Metric 5"],"Metric Units",None,c,0,"Basic Bar Graph") g.render() dashboard_test_case(stdscr,"gr_basic_bargraph",python_path) c.clear() g = graph.LineGraph(d,"X-Series",["Metric 2","Metric 4","Metric 6"],"Metric Units",None,c,False,"Basic Line Graph") g.render() dashboard_test_case(stdscr,"gr_basic_linegraph",python_path) c.clear() g = graph.PieGraph(d,"Pie Labels",["Metric 3"],None,c,"Basic Pie Graph") g.render() dashboard_test_case(stdscr,"gr_basic_piegraph",python_path) c.clear() g = graph.PieGraph(d,"Pie Labels",["Metric 3","Metric 2","Metric 5","Metric 1","Metric 4"],None,c,"Five Pie Graph") g.render() dashboard_test_case(stdscr,"gr_five_piegraph",python_path) c.clear() g = graph.TableGraph(d,"Pie Labels",["Metric 1","Metric 2","Metric 3","Metric 4","Metric 5","Metric 6"],None,c,"Basic Table") g.render() dashboard_test_case(stdscr,"gr_basic_tablegraph",python_path) c.clear()
def main(stdscr): screen_size(40, 100) stdscr.clear() stdscr.refresh() python_path = os.path.dirname(os.path.dirname(request.fspath)) c = canvas.Canvas(stdscr) max_x, max_y = c.get_maxxy() iy = 0 for ix in range(8, max_x): c.put_pixel(ix, iy, c.red) iy = (iy + 1) % max_y dashboard_test_case(stdscr, "put_pixel", python_path) c.clear() ix = 0 iy = 0 for ic in range(0, min(max_x, max_y) // 10): c.line(max_x // 2, 0, ix, iy, c.cyan) ix = (ix + 15) % max_x iy = (iy + 10) % max_y dashboard_test_case(stdscr, "line", python_path) c.clear() c.circle(max_x // 2, max_y // 2, min(max_x, max_y) // 3, c.white, False) dashboard_test_case(stdscr, "circle_not_filled", python_path) c.clear() c.circle(max_x // 2, max_y // 2, min(max_x, max_y) // 3, curses.color_pair(20), True) dashboard_test_case(stdscr, "circle_filled", python_path) c.clear() a = 0 a1 = 23 for ac in range(20): c.arc(max_x // 2, max_y // 2, min(max_x, max_y) // 3, a, a1, c.white, False) a = a1 a1 = a1 + ac * 5 if a1 > 360: break dashboard_test_case(stdscr, "arc_not_filled", python_path) c.clear() a = 0 a1 = 23 for ac in range(20): c.arc(max_x // 2, max_y // 2, min(max_x, max_y) // 3, a, a1, c.white, True) a = a1 a1 = a1 + ac * 5 if a1 > 360: break dashboard_test_case(stdscr, "arc_filled", python_path) c.clear() ix = 0 iy = 0 for ic in range(0, 5): x = ix + ic * 5 y = iy + ic * 5 c.rect(x, y, x + 5, y + 5, curses.color_pair(9 + (ic * 10)), False) dashboard_test_case(stdscr, "rect_not_filled", python_path) c.clear() ix = 0 iy = 0 for ic in range(0, 5): x = ix + ic * 5 y = iy + ic * 5 c.rect(x, y, x + 5, y + 5, curses.color_pair(9 + (ic * 10)), True) dashboard_test_case(stdscr, "rect_filled", python_path) c.clear() ix = 0 iy = 0 for ic in range(0, 5): x = ix + ic * 5 y = iy + ic * 5 c.textat(x, y, curses.color_pair(9 + (ic * 10)), "Test message %d" % ic) dashboard_test_case(stdscr, "textat", python_path) c.clear() ix = 0 iy = 0 for ic in range(0, 5): x = ix + ic * 16 y = iy + ic * 10 c.polyline([(x, y), (x + 16, y + 16), (x + 8, y), (x, y + 16), (x + 16, y + 8), (x, y + 8), (x + 8, y + 16)], curses.color_pair(9 + (ic * 10))) dashboard_test_case(stdscr, "polyline", python_path) ix = 0 iy = 0 for ic in range(0, 5): x = ix + ic * 16 y = iy + ic * 10 c.polygon([(x, y), (x + 16, y + 8), (x + 16, y + 16), (x + 8, y + 16), (x, y + 8)], curses.color_pair(9 + (ic * 10)), False) dashboard_test_case(stdscr, "polygon_not_filled", python_path) ix = 0 iy = 0 for ic in range(0, 5): x = ix + ic * 16 y = iy + ic * 10 c.polygon([(x, y), (x + 16, y + 8), (x + 16, y + 16), (x + 8, y + 16), (x, y + 8)], curses.color_pair(9 + (ic * 10)), True) dashboard_test_case(stdscr, "polygon_filled", python_path) ix = 0 iy = 0 for ic in range(0, 5): x = ix + ic * 16 y = iy + ic * 10 c.polygon([(x, y), (x + 16, y + 8), (x + 8, y + 8), (x + 8, y + 16), (x, y + 8)], curses.color_pair(9 + (ic * 10)), True) dashboard_test_case(stdscr, "polygon_concave_filled", python_path)
def main(stdscr): screen_size(40, 100) stdscr.clear() stdscr.refresh() python_path = os.path.dirname(os.path.dirname(request.fspath)) c = canvas.Canvas(stdscr) max_x, max_y = c.get_maxxy() d = display_list.DisplayList(canvas=c) r = 1 for ix in range(5): for iy in range(5): x = ix * 11 y = iy * 11 d.add_child( display_list.Rect(x, y, x + 10, y + 10, curses.color_pair(8 + r * 5), True)) r = r + 1 d.render() dashboard_test_case(stdscr, "dl_rect", python_path) c.clear() r = 1 for ix in range(5): for iy in range(5): x = 65 + (ix * (11 * 1.5)) + 5 y = (iy * 11) + 5 d.add_child( display_list.Circle(x, y, 5, curses.color_pair(8 + r * 5), True)) r = r + 1 d.render() dashboard_test_case(stdscr, "dl_circle", python_path) c.clear() a = 0 ia = [20, 15, 40, 110, 45, 25, 80, 25] r = 1 for ac in ia: d.add_child( display_list.Arc(100, 40, 40, a, a + ac, curses.color_pair(8 * r * 5), True)) a = a + ac r = r + 1 d.render() dashboard_test_case(stdscr, "dl_arc", python_path) c.clear() r = 0 for ix in range(5): for iy in range(5): d.add_child( display_list.Text(ix * 10, (iy * 10) + (ix * 2), "Text %d,%d" % (ix, iy), curses.color_pair(8 * r * 5))) r = r + 1 d.render() dashboard_test_case(stdscr, "dl_text", python_path) c.clear() points = [] for a in range(0, 360, 72): points.append(angle_point(0, 0, a, 20)) points.append(angle_point(0, 0, a + 36, 10)) points.append(points[0]) r = 50 d.add_child( display_list.PolyLine([(x + 100, y + 40) for x, y in points], curses.color_pair(8 + r * 8))) d.render() dashboard_test_case(stdscr, "dl_polyline", python_path) c.clear() r += 25 d.add_child( display_list.Polygon([(x + 102, y + 42) for x, y in points], curses.color_pair(8 + r * 8), True)) d.render() dashboard_test_case(stdscr, "dl_polygon", python_path) c.clear()
def main(stdscr): screen_size(40,100) stdscr.clear() stdscr.refresh() python_path = os.path.dirname(os.path.dirname(request.fspath)) c_names = ["X-Series","Pie Labels","Metric 1","Metric 2","Metric 3","Metric 4","Metric 5","Metric 6"] d = DataTable() for c in c_names: d.add_column(Column(name=c)) for idx in range(0,10): d.put(idx,"X-Series",Cell(int_type,idx*10,format_int)) d.put(idx,"Pie Labels",Cell(string_type,"Group %d"%idx,format_string)) d.put(idx,"Metric 1",Cell(float_type,50.0+(idx*20),format_float)) d.put(idx,"Metric 2",Cell(float_type,75.0+(idx*30),format_float)) d.put(idx,"Metric 3",Cell(float_type,100.0+(idx*40),format_float)) d.put(idx,"Metric 4",Cell(float_type,123.0+(idx*23),format_float)) d.put(idx,"Metric 5",Cell(float_type,143+(idx*33),format_float)) d.put(idx,"Metric 6",Cell(float_type,171+(idx*51),format_float)) c = canvas.Canvas(stdscr) max_x,max_y = c.get_maxxy() db = dashboard.Dashboard(stdscr,None,0) p = dashboard.Page(stdscr) pp = dashboard.Panel() g = graph.BarGraph(d,"X-Series",["Metric 1","Metric 3","Metric 5"],"Metric Units",None,c,0,"Basic Bar Graph") pp.add_graph(g) g = graph.LineGraph(d,"X-Series",["Metric 2","Metric 4","Metric 6"],"Metric Units",None,c,False,"Basic Line Graph") pp.add_graph(g) p.add_panel(pp) db.add_page(p) p = dashboard.Page(stdscr) pp = dashboard.Panel() g = graph.PieGraph(d,"Pie Labels",["Metric 3"],None,c,"Basic Pie Graph") pp.add_graph(g) g = graph.TableGraph(d,"Pie Labels",["Metric 1","Metric 2","Metric 3","Metric 4","Metric 5","Metric 6"],None,c,"Basic Table") pp.add_graph(g) p.add_panel(pp) db.add_page(p) # force the timestamp to be the same so the screen diffs will match d.refresh_timestamp = datetime(2020,8,24,9,49,0,0).timestamp() d.changed() db.main([]) dashboard_test_case(stdscr,"db_basic_dashboard",python_path) db.main([curses.KEY_NPAGE]) dashboard_test_case(stdscr,"db_basic_dashboard_1",python_path) db.main([9]) # tab dashboard_test_case(stdscr,"db_basic_dashboard_2",python_path) db.main([curses.KEY_HOME]) dashboard_test_case(stdscr,"db_basic_dashboard_3",python_path) db.main([curses.KEY_ENTER]) dashboard_test_case(stdscr,"db_basic_dashboard_4",python_path) db.main([27,-1]) # esc to exit zoom and redraw dashboard_test_case(stdscr,"db_basic_dashboard_5",python_path)
def main(self, keys=None): """ main input and redraw loop for the dashboard """ self.window.nodelay(1) self.window.notimeout(0) self.window.timeout(1000) self.window.keypad(1) curses.curs_set(0) curses.raw() curses.mousemask(curses.ALL_MOUSE_EVENTS | curses.REPORT_MOUSE_POSITION) start_time = time.time() positions = [] status = "" while True: if keys != None: if len(keys) > 0: ch = keys.pop(0) else: ch = -1 else: ch = self.window.getch() if not self.zoomed: cur_graph = self.get_current_graph() cur_graph[0].set_focus(True) if ch > -1: page = self.get_current_page() py, px = page.get_position() if ch == 27: # esc key return 0 elif ch == 9: # tab key self.next_graph() elif ch == curses.KEY_NPAGE: self.next_page() elif ch == curses.KEY_PPAGE: self.prev_page() elif ch == curses.KEY_HOME: self.first_page() elif ch == curses.KEY_END: self.last_page() elif ch == curses.KEY_RIGHT: page.move(py, px + 1) elif ch == curses.KEY_LEFT: page.move(py, px - 1) elif ch == curses.KEY_UP: page.move(py - 1, px) elif ch == curses.KEY_DOWN: page.move(py + 1, px) elif ch == curses.KEY_F5: for p in self.pages: for pp in p.get_panel_layout(): for gg in pp[0].get_graph_layout(): gg[0].refresh_data() elif ch == curses.KEY_ENTER or ch == 10: # ENTER KEY self.zoomed = True self.zoomed_graph = self.get_current_graph() self.zoomed_canvas = canvas.Canvas(self.window) self.zoomed_restore_canvas = self.zoomed_graph[ 0].get_canvas() self.zoomed_graph[0].set_canvas(self.zoomed_canvas) self.window.clear() continue elif ch == curses.KEY_MOUSE: mid, mx, my, mz, mtype = curses.getmouse() max_y, max_x = self.window.getmaxyx() if mtype & curses.BUTTON1_CLICKED: if mx == 0 and my == 0: self.first_page() elif mx == 0 and my > 0: self.prev_page() elif mx == max_x - 1 and my == max_y - 1: self.last_page() elif mx == max_x - 1 and my < max_y - 1: self.next_page() start_time = time.time() positions = [] if self.auto_tour_delay: if time.time() - start_time > (self.auto_tour_delay / 4): # 4 views per graph if not positions: g = self.next_graph() if not g: self.first_page() g = self.get_current_graph() positions = [(g[1], g[2]), (g[1] + (g[3] // 2), g[2]), (g[1] + (g[3] // 2), g[2] + (g[4] // 2)), (g[1], g[2] + (g[4] // 2))] py, px = positions.pop(0) self.get_current_page().move(py, px) start_time = time.time() if cur_graph[0] != self.get_current_graph()[0]: cur_graph[0].set_focus(False) page = self.get_current_page() if page: page.redraw() page.refresh() if self.zoomed: if ch > -1: if ch == 27: # esc key self.zoomed_graph[0].set_canvas( self.zoomed_restore_canvas) self.zoomed = False self.zoomed_graph = None self.zoomed_canvas = None self.zoomed_restore_canvas = None if self.zoomed_graph and self.zoomed_graph[0].is_modified(): self.zoomed_graph[0].render() self.window.refresh() latest_refresh = 0 for p in self.pages: for pp in p.get_panel_layout(): for gg in pp[0].get_graph_layout(): latest_refresh = max( latest_refresh, gg[0].get_data().get_refresh_timestamp()) self.window.addstr(0, 0, " " * len(status), curses.color_pair(1) | curses.A_REVERSE) status = "Page %d of %d Last Update %s%s" % ( self.current_page + 1, len( self.pages), datetime.fromtimestamp( latest_refresh).strftime("%A, %d. %B %Y %I:%M%p"), " ZOOMED (Press Esc to Exit)" if self.zoomed else "") self.window.addstr(0, 0, status, curses.color_pair(1) | curses.A_REVERSE) if keys != None and len(keys) == 0: return