def output(self, months=3): """Render out the image of the rrd""" def1 = DEF(rrdfile=self.datafile, vname='bookmark_count', dsName=self.ds1.name) def2 = DEF(rrdfile=self.datafile, vname='unique_count', dsName=self.ds2.name) def3 = DEF(rrdfile=self.datafile, vname='tag_count', dsName=self.ds3.name) line1 = LINE(defObj=def1, color='#01FF13', legend='Bookmarks', stack=True) line2 = LINE(defObj=def2, color='#DA7202', legend='Unique', stack=True) line3 = LINE(defObj=def3, color='#BD4902', legend='Tags', stack=True) # area1 = AREA(defObj=def1, color='#FFA902', legend='Bookmarks') # area2 = AREA(defObj=def2, color='#DA7202', legend='Unique') # area3 = AREA(defObj=def3, color='#BD4902', legend='Tags') # Let's configure some custom colors for the graph ca = ColorAttributes() ca.back = '#333333' ca.canvas = '#333333' ca.shadea = '#000000' ca.shadeb = '#111111' ca.mgrid = '#CCCCCC' ca.axis = '#FFFFFF' ca.frame = '#AAAAAA' ca.font = '#FFFFFF' ca.arrow = '#FFFFFF' # Now that we've got everything set up, let's make a graph start_date = time.mktime((today - timedelta(weeks=28)).timetuple()) end_date = time.mktime(today.timetuple()) g = Graph(self.outputfile, start=int(start_date), end=int(end_date), vertical_label='count', color=ca) g.data.extend([def1, def2, def3, line3, line2, line1]) if not os.path.exists(os.path.dirname(self.outputfile)): os.makedirs(os.path.dirname(self.outputfile)) g.write()
def graph_request(self, period='day'): def1 = DEF(rrdfile=self.rrdfile, vname='request', dsName="requests", cdef="AVERAGE") vdef1 = VDEF(vname='max', rpn='request,MAXIMUM') vdef2 = VDEF(vname='avg', rpn='request,AVERAGE') vdef3 = VDEF(vname='last', rpn='request,LAST') area1 = AREA(defObj=def1, color='#336600', legend='Requests') gprint1 = GPRINT(vdef1, "Max\\: %5.1lf %S") gprint2 = GPRINT(vdef2, "Avg\\: %5.1lf %S") gprint3 = GPRINT(vdef3, "Current\\: %5.1lf %Sreq/sec") ca = ColorAttributes() ca.back = '#333333' ca.canvas = '#333333' ca.shadea = '#000000' ca.shadeb = '#111111' ca.mgrid = '#CCCCCC' ca.axis = '#FFFFFF' ca.frame = '#AAAAAA' ca.font = '#FFFFFF' ca.arrow = '#FFFFFF' img = "request-%s.png" % period imgname = self.static_path +"/"+ img start = '-1'+period g = Graph(imgname, imgformat='PNG', step=start, vertical_label='request/sec', color=ca, width=700, height=150) g.data.extend([def1, vdef1, vdef2, vdef3, area1, gprint1, gprint2, gprint3]) g.write()
def drawsimplegraph(req, rrdpathname, rrd, ds, rra, height=600, width=1200, start='default', end='default' ): filename = Rrdpath.objects.get(name=str(rrdpathname)).path fullfilename = filename + '/' + rrd if os.path.isfile(fullfilename): rrdobj = RRD(fullfilename, mode='r') info = rrdobj.getData() ds = str(ds) rra = str(rra) #step = info['step'] if (start == 'default'): start = info['lastupdate'] - (7 * 86400) if (end == 'default'): end = info['lastupdate'] gitems = [] gitems.append(DEF(rrdfile=fullfilename, vname="fudge", dsName=ds)) gitems.append(CDEF(vname='kmh', rpn='%s' % gitems[0].vname)) gitems.append(AREA(defObj=gitems[1], color='#006600', legend=rrd+" "+str(start)+" "+str(end))) g = Graph('-', imgformat='png', start=str(start), end=str(end), vertical_label=ds) g.title = rrd + '/' + ds + '/' + rra g.full_size_mode = True g.only_graph = req.GET.get('onlygraph', False) g.no_legend = req.GET.get('nolegend', True) g.height = req.GET.get('height', 600) g.width = req.GET.get('width', 1200) g.data.extend(gitems) a = g.write() return HttpResponse(a,content_type="image/png")
def render(stringName, key, startTime, endTime): if debug: print "Enter Function render(filename, value)" #balken zeichnen def1 = DEF(rrdfile = baseDir + stringName + "_" + key + ".rrd", vname='kW', dsName="kW") #command fetches data from the rrd area1 = AREA(defObj=def1, color='#FFA902', legend='kW') #mittelwert linie zeichnen (muss noch berechnet werden line1 = LINE(value=100, color='#990000', legend='Average') # Let's configure some custom colors for the graph ca = ColorAttributes() ca.back = '#333333' ca.canvas = '#333333' ca.shadea = '#000000' ca.shadeb = '#111111' ca.mgrid = '#CCCCCC' ca.axis = '#FFFFFF' ca.frame = '#AAAAAA' ca.font = '#FFFFFF' ca.arrow = '#FFFFFF' # Now that we've got everything set up, let's make a graph #startTime = endTime - (10 * 60 * 60) #10h anzeigen, sollte noch variabel sein g = Graph(baseDir + stringName + "_" + key + ".png", start=startTime, end=endTime, vertical_label='data', color=ca) g.data.extend([def1, area1, line1]) g.width = 800 g.height = 400 g.write()
def rrd_stuff(): filename = 'test.rrd' #dataSource = from_file() #def1 = DEF(rrdfile=filename, vname='myspeed', # dsName=dataSource.name) def1 = DEF(rrdfile=filename, vname='myspeed', dsName='speed') cdef1 = CDEF(vname='kmh', rpn='%s,3600,*' % def1.vname) cdef2 = CDEF(vname='fast', rpn='kmh,100,GT,kmh,0,IF') cdef3 = CDEF(vname='good', rpn='kmh,100,GT,0,kmh,IF') vdef1 = VDEF(vname='mymax', rpn='%s,MAXIMUM' % def1.vname) vdef2 = VDEF(vname='myavg', rpn='%s,AVERAGE' % def1.vname) line1 = LINE(value=100, color='#990000', legend='Maximum Allowed') area1 = AREA(defObj=cdef3, color='#006600', legend='Good Speed') area2 = AREA(defObj=cdef2, color='#CC6633', legend='Too Fast') line2 = LINE(defObj=vdef2, color='#000099', legend='My Average', stack=True) gprint1 = GPRINT(vdef2, '%6.2lf kph') from pyrrd.graph import ColorAttributes ca = ColorAttributes() ca.back = '#333333' ca.canvas = '#333333' ca.shadea = '#000000' ca.shadeb = '#111111' ca.mgrid = '#CCCCCC' ca.axis = '#FFFFFF' ca.frame = '#AAAAAA' ca.font = '#FFFFFF' ca.arrow = '#FFFFFF' from pyrrd.graph import Graph graphfile = "rrdgraph.png" g = Graph(graphfile, start=920805000, end=920810000, vertical_label='km/h', color=ca) g.data.extend([def1, cdef1, cdef2, cdef3, vdef1, vdef2, line1, area1, area2, line2, gprint1]) g.write()
def _generate_defs(self): """ FOR INTERNAL USE ONLY This generates an RRD DEF objects for every data source in every device (rrd file) and saves them in the list self._defs. Additionally it generates a dictionary def_map with key is DEF name and value is a lookup key for metadata Saves meta information for DEFs and CDEFs like device, data source and cf in metadata """ def_count = 0 self._defs = [] self._def_map = {} for device in self.devices: rrd_file = get_rrd_file(device, self.plugin, self.data_source) if os.path.isfile(rrd_file): # Get all data sources from rrd for data_source in get_data_sources(rrd_file): for cf in self._cf_map.keys(): metadata_key = cf + str(def_count) # generate definition def_vname = 'def_%s_%s_%s' % (data_source, cf, str(def_count)) self._def_map[def_vname] = metadata_key self._metadata.setdefault(metadata_key, {}) self._metadata[metadata_key][ 'data_source'] = data_source self._metadata[metadata_key]['device'] = device self._metadata[metadata_key]['cf'] = cf self._defs.append( DEF(rrdfile=rrd_file, dsName=data_source, cdef=cf.upper(), vname=def_vname)) def_count += 1
if i % 100 == 0: myRRD.update(debug=False) # let's do two different sets of periodic values value1 = int(sin(i % 200) * 1000) value2 = int(sin((i % 2000) / (200 * random())) * 200) value3 = int(sin((i % 4000) / (400 * random())) * 400) value4 = int(sin((i % 6000) / (600 * random())) * 600) # when you pass more than one value to update buffer like this, # they get applied to the DSs in the order that the DSs were # "defined" or added to the RRD object. myRRD.bufferValue(currentTime, value1, value2, value3, value4) # add anything remaining in the buffer myRRD.update() # Let's set up the objects that will be added to the graph def1 = DEF(rrdfile=myRRD.filename, vname='myspeed', dsName=ds1.name) def2 = DEF(rrdfile=myRRD.filename, vname='mysilliness', dsName=ds2.name) def3 = DEF(rrdfile=myRRD.filename, vname='myinsanity', dsName=ds3.name) def4 = DEF(rrdfile=myRRD.filename, vname='mydementia', dsName=ds4.name) vdef1 = VDEF(vname='myavg', rpn='%s,AVERAGE' % def1.vname) area1 = AREA(defObj=def1, color='#FFA902', legend='Raw Data 4') area2 = AREA(defObj=def2, color='#DA7202', legend='Raw Data 3') area3 = AREA(defObj=def3, color='#BD4902', legend='Raw Data 2') area4 = AREA(defObj=def4, color='#A32001', legend='Raw Data 1') line1 = LINE(defObj=vdef1, color='#01FF13', legend='Average', stack=True) # Let's configure some custom colors for the graph ca = ColorAttributes() ca.back = '#333333' ca.canvas = '#333333' ca.shadea = '#000000'
# let's generate some data... currentTime = startTime for i in xrange(maxSteps): currentTime += step # lets update the RRD/purge the buffer ever 100 entires if i % 100 == 0 and myRRD.values: #print "updating RRD..." myRRD.update(debug=False) # let's do periodic values value = int(sin(i % 200) * 1000) myRRD.bufferValue(currentTime, value) # add anything remaining in the buffer myRRD.update() # Let's set up the objects that will be added to the graph def1 = DEF(rrdfile=myRRD.filename, vname='myspeed', dsName=ds1.name) vdef1 = VDEF(vname='myavg', rpn='%s,AVERAGE' % def1.vname) area1 = AREA(defObj=def1, color='#FFA902', legend='Raw Data') line1 = LINE(defObj=vdef1, color='#01FF13', legend='Average', stack=True) # Let's configure some custom colors for the graph ca = ColorAttributes() ca.back = '#333333' ca.canvas = '#333333' ca.shadea = '#000000' ca.shadeb = '#111111' ca.mgrid = '#CCCCCC' ca.axis = '#FFFFFF' ca.frame = '#AAAAAA' ca.font = '#FFFFFF' ca.arrow = '#FFFFFF'
myRRD.bufferValue('920806200', '12373') myRRD.bufferValue('920806500', '12383') myRRD.update() myRRD.bufferValue('920806800', '12393') myRRD.bufferValue('920807100', '12399') myRRD.bufferValue('920807400', '12405') myRRD.bufferValue('920807700', '12411') myRRD.bufferValue('920808000', '12415') myRRD.bufferValue('920808300', '12420') myRRD.bufferValue('920808600', '12422') myRRD.bufferValue('920808900', '12423') myRRD.update() from pyrrd.graph import DEF, CDEF, VDEF, LINE, AREA, GPRINT def1 = DEF(rrdfile=myRRD.filename, vname='myspeed', dsName=dataSource.name) cdef1 = CDEF(vname='kmh', rpn='%s,3600,*' % def1.vname) cdef2 = CDEF(vname='fast', rpn='kmh,100,GT,kmh,0,IF') cdef3 = CDEF(vname='good', rpn='kmh,100,GT,0,kmh,IF') vdef1 = VDEF(vname='mymax', rpn='%s,MAXIMUM' % def1.vname) vdef2 = VDEF(vname='myavg', rpn='%s,AVERAGE' % def1.vname) line1 = LINE(value=100, color='#990000', legend='Maximum Allowed') area1 = AREA(defObj=cdef3, color='#006600', legend='Good Speed') area2 = AREA(defObj=cdef2, color='#CC6633', legend='Too Fast') line2 = LINE(defObj=vdef2, color='#000099', legend='My Average', stack=True) gprint1 = GPRINT(vdef2, '%6.2lf kph') from pyrrd.graph import ColorAttributes ca = ColorAttributes() ca.back = '#333333'
def graph_connection(self, period='day'): def1 = DEF(rrdfile=self.rrdfile, vname='connections', dsName="connections", cdef="AVERAGE") def2 = DEF(rrdfile=self.rrdfile, vname='reading', dsName="reading", cdef="AVERAGE") def3 = DEF(rrdfile=self.rrdfile, vname='writing', dsName="writing", cdef="AVERAGE") def4 = DEF(rrdfile=self.rrdfile, vname='waiting', dsName="waiting", cdef="AVERAGE") # TOTAL vdef1 = VDEF(vname='max', rpn='connections,MAXIMUM') vdef2 = VDEF(vname='avg', rpn='connections,AVERAGE') vdef3 = VDEF(vname='last', rpn='connections,LAST') vdef4 = VDEF(vname='min', rpn='connections,MINIMUM') line1 = LINE(1, defObj=def1, color='#22FF22', legend='Total') gprint1 = GPRINT(vdef1, "Max\\: %5.1lf %S") gprint2 = GPRINT(vdef2, "Avg\\: %5.1lf %S") gprint3 = GPRINT(vdef3, "Current\\: %5.1lf %S") gprint4 = GPRINT(vdef4, "Min\\: %5.1lf %S\\n") # READING reading_vdef1 = VDEF(vname='rmax', rpn='reading,MAXIMUM') reading_vdef2 = VDEF(vname='ravg', rpn='reading,AVERAGE') reading_vdef3 = VDEF(vname='rlast', rpn='reading,LAST') reading_vdef4 = VDEF(vname='rmin', rpn='reading,MINIMUM') line2 = LINE(1, defObj=def2, color='#0022FF', legend='Reading') reading_gprint1 = GPRINT(reading_vdef1, "Max\\: %5.1lf %S") reading_gprint2 = GPRINT(reading_vdef2, "Avg\\: %5.1lf %S") reading_gprint3 = GPRINT(reading_vdef3, "Current\\: %5.1lf %S") reading_gprint4 = GPRINT(reading_vdef4, "Min\\: %5.1lf %S\\n") # writing writing_vdef1 = VDEF(vname='wmax', rpn='writing,MAXIMUM') writing_vdef2 = VDEF(vname='wavg', rpn='writing,AVERAGE') writing_vdef3 = VDEF(vname='wlast', rpn='writing,LAST') writing_vdef4 = VDEF(vname='wmin', rpn='writing,MINIMUM') line3 = LINE(1, defObj=def3, color='#FF0000', legend='Writing') writing_gprint1 = GPRINT(writing_vdef1, "Max\\: %5.1lf %S") writing_gprint2 = GPRINT(writing_vdef2, "Avg\\: %5.1lf %S") writing_gprint3 = GPRINT(writing_vdef3, "Current\\: %5.1lf %S") writing_gprint4 = GPRINT(writing_vdef4, "Min\\: %5.1lf %S\\n") # WAITING waiting_vdef1 = VDEF(vname='wamax', rpn='waiting,MAXIMUM') waiting_vdef2 = VDEF(vname='waavg', rpn='waiting,AVERAGE') waiting_vdef3 = VDEF(vname='walast', rpn='waiting,LAST') waiting_vdef4 = VDEF(vname='wamin', rpn='waiting,MINIMUM') line4 = LINE(1, defObj=def4, color='#00AAAA', legend='Waiting') waiting_gprint1 = GPRINT(waiting_vdef1, "Max\\: %5.1lf %S") waiting_gprint2 = GPRINT(waiting_vdef2, "Avg\\: %5.1lf %S") waiting_gprint3 = GPRINT(waiting_vdef3, "Current\\: %5.1lf %S") waiting_gprint4 = GPRINT(waiting_vdef4, "Min\\: %5.1lf %S\\n") ca = ColorAttributes() ca.back = '#333333' ca.canvas = '#333333' ca.shadea = '#000000' ca.shadeb = '#111111' ca.mgrid = '#CCCCCC' ca.axis = '#FFFFFF' ca.frame = '#AAAAAA' ca.font = '#FFFFFF' ca.arrow = '#FFFFFF' img = "connection-%s.png" % period imgname = self.static_path +"/"+ img start = '-1'+period g = Graph(imgname, imgformat='PNG', step=start, vertical_label='connections', color=ca, width=700, height=150) g.data.extend([def1, vdef1, vdef2, vdef3, vdef4, line1, gprint1, gprint2, gprint3, gprint4]) g.data.extend([def2, reading_vdef1, reading_vdef2, reading_vdef3, reading_vdef4, line2, reading_gprint1, reading_gprint2, reading_gprint3, reading_gprint4]) g.data.extend([def3, writing_vdef1, writing_vdef2, writing_vdef3, writing_vdef4, line3, writing_gprint1, writing_gprint2, writing_gprint3, writing_gprint4]) g.data.extend([def4, waiting_vdef1, waiting_vdef2, waiting_vdef3, waiting_vdef4, line4, waiting_gprint1, waiting_gprint2, waiting_gprint3, waiting_gprint4]) g.write()
def drawgraph(req, graphid): now = int(time.time()) ginfo = Rrdgraph.objects.get(pk=graphid) gobjects = GraphItems.objects.filter(graph__id=graphid).order_by('seq') gitems = [] secondsago = secsago(req) if secondsago == 0: secondsago = 3600 # secsago = ginfo.timespan end = int(req.GET.get('end', now)) start = int(req.GET.get('start', end - secondsago)) for gobject in gobjects: #cycle through graph items...need to order this above if gobject.itemtype == 'S': #Handle Static RRD DataSources rootdir = gobject.rrdds.rootdir.path subpath = gobject.rrdds.subpath rrdds = gobject.rrdds.ds filename = rootdir + '/' + gobject.rrdds.subpath rra = gobject.rra namesuff = str(gobject.seq) legendtext = subpath+" "+rrdds+" "+rra+ " " gitems.append(DEF(rrdfile=filename, vname='d'+namesuff, dsName=rrdds)) gitems.append(CDEF(vname='c'+namesuff, rpn='%s' % 'd'+namesuff)) linetype = gobject.linetype.upper() mycolor = '#' + gobject.color + gobject.transparency if linetype == 'A': gitems.append(AREA(value='c'+namesuff, color=mycolor, legend=legendtext, stack=gobject.stack)) elif linetype[:1] == 'L': gitems.append(LINE(linetype[-1:], 'c'+namesuff, color=mycolor, legend=legendtext, stack=gobject.stack)) else: gitems.append(LINE(0, 'c'+namesuff, color=mycolor, legend=legendtext, stack=gobject.stack)) if gobject.itemtype == 'R': #Handle Regex regtextarr = gobject.option_text.rsplit(' ',2) rrddslist = Rrdfiles.objects.filter(rootdir__name__regex=regtextarr[0]).filter(subpath__regex=regtextarr[1]).filter(ds__regex=regtextarr[2]) i = 0 colors = [] colorset = GraphItemColorCycleColor.objects.filter(name='weeee').order_by('seq') for x in colorset: colors.append(str('#' + x.color)) for rrdds in rrddslist: rootdir = rrdds.rootdir.path subpath = rrdds.subpath rrdds = rrdds.ds filename = rootdir + subpath rra = gobject.rra linetype = gobject.linetype.upper() mycolor = colors[i % len(colors)] namesuff = str(gobject.seq) + '_' + str(i) legendtext = subpath+" "+rrdds+" ("+rra+ ") " gitems.append(DEF(rrdfile=filename, vname='d'+namesuff, dsName=rrdds)) gitems.append(CDEF(vname='c'+namesuff, rpn='%s' % 'd'+namesuff)) if linetype == 'A': gitems.append(AREA(value='c'+namesuff, color=mycolor, legend=legendtext, stack=gobject.stack)) elif linetype[:1] == 'L': gitems.append(LINE(linetype[-1:], 'c'+namesuff, color=mycolor, legend=legendtext, stack=gobject.stack)) else: gitems.append(LINE(0, 'c'+namesuff, color=mycolor, legend=legendtext, stack=gobject.stack)) prnFmt = '%6.2lf' vdef = VDEF(vname='va'+namesuff, rpn='%s,AVERAGE' % ('d'+namesuff) ) gitems.append(vdef) gitems.append(GPRINT(vdef, ('Avg\:'+prnFmt))) vdef = VDEF(vname='vn'+namesuff, rpn='%s,MINIMUM' % ('d'+namesuff) ) gitems.append(vdef) gitems.append(GPRINT(vdef, ('Min\:'+prnFmt))) vdef = VDEF(vname='vx'+namesuff, rpn='%s,MAXIMUM' % ('d'+namesuff) ) gitems.append(vdef) gitems.append(GPRINT(vdef, ('Max\:'+prnFmt))) vdef = VDEF(vname='vl'+namesuff, rpn='%s,LAST' % ('d'+namesuff) ) gitems.append(vdef) gitems.append(GPRINT(vdef, ('LAST\:'+prnFmt+'\\n'))) #gitems.append(COMMENT('\\n', False)) i = i + 1 if gobject.itemtype == 'C': #Handle Custom CDEFS pass if gobject.itemtype == 'V': #Handle Custom VDEFs pass cs = req.GET.get('cs', ginfo.gcolorscheme) colsch = GraphColorScheme.objects.get(pk=cs) ca = ColorAttributes() ca.back = '#' + colsch.cback + colsch.tback ca.canvas = '#' + colsch.ccanvas + colsch.tcanvas ca.shadea = '#' + colsch.cshadea + colsch.tshadea ca.shadeb = '#' + colsch.cshadeb + colsch.tshadeb ca.mgrid = '#' + colsch.cmgrid + colsch.tmgrid ca.axis = '#' + colsch.caxis + colsch.taxis ca.frame = '#' + colsch.cframe + colsch.tframe ca.font = '#' + colsch.cfont + colsch.tfont ca.arrow = '#' + colsch.carrow + colsch.tarrow #make a pyrrd Graph object, destination standard out (-) g = Graph('-', imgformat='png', start=start, end=end, color=ca, vertical_label='"'+ginfo.vertical_label+'"') #populate it with our url params, defaulting to Rrdgraph instance (ginfo) options fullsizemode = req.GET.get('fullsizemode') if (fullsizemode in ['0', 'False' , 'false', 'no', 'No']): g.full_size_mode = False else: g.full_size_mode = True graphonly = req.GET.get('graphonly') if (graphonly in ['1', 'True' , 'true', 'yes']): g.only_graph = True noleg = req.GET.get('nolegend') if (noleg in ['1', 'True' , 'true', 'yes']): g.no_legend = True log = req.GET.get('logarithmic') if (log in ['1', 'True' , 'true', 'yes', 'Yes']): g.logarithmic = True elif (log in ['0', 'False' , 'false', 'no', 'No']): g.logarithmic = False else: g.logarithmic = getattr(ginfo, 'logarithmic', False) g.disable_rrdtool_tags = True g.height = req.GET.get('height', 600) g.width = req.GET.get('width', 1200) g.title = '"'+ginfo.name+'"' g.data.extend(gitems) #write in our gitems we generated a = g.write() #gets the binary image finally #minetype #just a thing to cause an error and debug return HttpResponse(a,mimetype="image/png")
counter += 1 val1 = dsNames.get(ds1.name) or 'U' val2 = dsNames.get(ds2.name) or 'U' val3 = dsNames.get(ds3.name) or 'U' val4 = dsNames.get(ds4.name) or 'U' # Add the values myRRD.bufferValue(time, val1, val2, val3, val4) # Lets update the RRD/purge the buffer ever 100 entires if counter % 100 == 0: myRRD.update(debug=False) # Add anything remaining in the buffer myRRD.update(debug=False) # Let's set up the objects that will be added to the graph def1 = DEF(rrdfile=myRRD.filename, vname='in', dsName=ds1.name) def2 = DEF(rrdfile=myRRD.filename, vname='out', dsName=ds2.name) # Here we're just going to mulitply the in bits by 100, solely for # the purpose of display cdef1 = CDEF(vname='hundredin', rpn='%s,%s,*' % (def1.vname, 100)) cdef2 = CDEF(vname='negout', rpn='%s,-1,*' % def2.vname) area1 = AREA(defObj=cdef1, color='#FFA902', legend='Bits In') area2 = AREA(defObj=cdef2, color='#A32001', legend='Bits Out') # Let's configure some custom colors for the graph ca = ColorAttributes() ca.back = '#333333' ca.canvas = '#333333' ca.shadea = '#000000' ca.shadeb = '#111111' ca.mgrid = '#CCCCCC'