Python;graph permanent grid print; Canvas

Discussion in 'Programmer's Corner' started by Vindhyachal Takniki, Jul 17, 2015.

  1. Vindhyachal Takniki

    Thread Starter Member

    Nov 3, 2014
    348
    6
    1. I have two made continuous graph of data like in CRO in python, for 2 or 4 channels depending on need.
    2. When graph reaches right corner it again starts from left again. Right now random values are printed which I will replace with voltage values.
    3. Didn't use matplotlib since I didn't find how to do that.
    4. Code for this is below. ( special thx to @strantor for that, I had some issues)
    5. What I do when i reach horizontal pixel, first I delete it completely, then I print the value on it.
    Now how to print grid on it. It gets deleted also.
    6. I also tried to put grid image on canvas & then tried to put graph on it, but then that images also gets deleted pixel by pixel.
    7. Any way to do that or workaround.
    (In actual I have to print graph right to left like in CRO, bur currently i am doing left to right as it is easy).

    Code (Python):
    1.  
    2. import Tkinter
    3. from Tkinter import *
    4. from random import randint
    5.  
    6. class pixelTron():
    7.  
    8.     def __init__(self):
    9.         self.hor_pixel = 5                      #starting point of horizontal pixel
    10.         self.old_ver_pixel_1 = 0                #last pixel value of graph 1
    11.         self.old_ver_pixel_2 = 302              #last pixel value of graph 2
    12.         self.new_ver_pixel_1 = 0                #new pixel value of graph 1
    13.         self.new_ver_pixel_2 = 0                #new pixel value of graph 2
    14.         self.y0_1 = 0                           # y cordinate of graph 1 & 2
    15.         self.y1_1 = 0
    16.         self.y0_2 = 0
    17.         self.y1_2 = 0
    18.         self.screen = Tkinter.Tk()
    19.         self.running = 1
    20.         self.screen.protocol("WM_DELETE_WINDOW", self.suicide)
    21.  
    22.     def pixel(self, C):
    23.         nP1 = self.new_ver_pixel_1
    24.         oP1 = self.old_ver_pixel_1
    25.         nP2 = self.new_ver_pixel_2
    26.         oP2 = self.old_ver_pixel_2
    27.  
    28.              
    29.         hP = self.hor_pixel
    30.         if(nP1 == oP1):
    31.             nP1 = nP1 + 1
    32.         if(nP2 == oP2):
    33.             nP2 = nP2 + 1
    34.  
    35.         if(nP1 > oP1):
    36.             self.y0_1 = oP1
    37.             self.y1_1 = nP1
    38.         else:
    39.             self.y0_1 = nP1
    40.             self.y1_1 = oP1
    41.          
    42.         if(nP2 > oP2):
    43.             self.y0_2 = oP2
    44.             self.y1_2 = nP2
    45.         else:
    46.             self.y0_2 = nP2
    47.             self.y1_2 = oP2
    48.          
    49.         coord = hP, self.y0_1, hP, self.y1_1
    50.         coord2 = hP, self.y0_2, hP, self.y1_2
    51.         print coord2
    52.      
    53.         hP = hP + 1
    54.         if(hP > 400):
    55.             hP = 5;
    56.         self.old_ver_pixel_1 = nP1
    57.         self.old_ver_pixel_2 = nP2
    58.  
    59.         C.create_line(hP , 0 , hP , 300, fill = 'black')
    60.         C.create_line(hP , 302 , hP , 602, fill = 'black')      
    61.         C.create_line(coord, fill = 'red')
    62.         C.create_line(coord2, fill = 'yellow')
    63.         C.pack()
    64.         self.hor_pixel = hP
    65.  
    66.     def graph(self):
    67.         screen = self.screen
    68.  
    69.         graph_index(screen)
    70.      
    71.         screen.title("Analog Channel")
    72.         screen.geometry("800x800")
    73.         C = Tkinter.Canvas(screen , bg = "black", width = 600, height = 602)
    74.         C.create_line(5 , 301 , 400 , 301, fill = 'white')
    75.  
    76.         #photo = PhotoImage(file="../untitled.gif")
    77.         #C.create_image(0,0 ,image = photo)
    78.      
    79.         C.pack()
    80.         pixel = self.pixel
    81.         while self.running:
    82.             self.new_ver_pixel_1 = randint(0,300);
    83.             self.new_ver_pixel_2 = randint(0,300) + 302;
    84.             screen.after(100,pixel(C))
    85.             screen.update()
    86.         screen.mainloop()
    87.  
    88.     def suicide(self):
    89.         self.running = 0
    90.         self.screen.destroy()
    91.  
    92. def my_graph():
    93.     PT = pixelTron()
    94.     PTG = PT.graph
    95.     PTG()
    96.  
    97. def graph_index(screen):
    98.     label = Label(screen , text = "-20")
    99.     label.pack()
    100.     label.place(x = 70, y = 270)
    101.  
    102.     label = Label(screen , text = "-10")
    103.     label.pack()
    104.     label.place(x = 70, y = 215)
    105.  
    106.     label = Label(screen , text = "0")
    107.     label.pack()
    108.     label.place(x = 80, y = 140)      
    109.  
    110.     label = Label(screen , text = "+10")
    111.     label.pack()
    112.     label.place(x = 70, y = 65)
    113.  
    114.     label = Label(screen , text = "+20")
    115.     label.pack()
    116.     label.place(x = 70, y = 0)    
    117.  
    118.     label = Label(screen , text = "+20")
    119.     label.pack()
    120.     label.place(x = 70, y = 302)
    121.  
    122.     label = Label(screen , text = "+10")
    123.     label.pack()
    124.     label.place(x = 70, y = 375)
    125.  
    126.     label = Label(screen , text = "0")
    127.     label.pack()
    128.     label.place(x = 80, y = 450)      
    129.  
    130.     label = Label(screen , text = "-10")
    131.     label.pack()
    132.     label.place(x = 70, y = 525)
    133.  
    134.     label = Label(screen , text = "-20")
    135.     label.pack()
    136.     label.place(x = 70, y = 600)    
    137.  
    138. my_graph()
    139.  
    140.  
     
    Last edited by a moderator: Jul 20, 2015
  2. strantor

    AAC Fanatic!

    Oct 3, 2010
    4,302
    1,988
    This works:
    Code (Python):
    1.  
    2. import Tkinter
    3. from Tkinter import *
    4. from random import randint
    5.  
    6. class pixelTron():
    7.  
    8.     def __init__(self):
    9.         self.hor_pixel = 5                      #starting point of horizontal pixel
    10.         self.old_ver_pixel_1 = 0                #last pixel value of graph 1
    11.         self.old_ver_pixel_2 = 302              #last pixel value of graph 2
    12.         self.new_ver_pixel_1 = 0                #new pixel value of graph 1
    13.         self.new_ver_pixel_2 = 0                #new pixel value of graph 2
    14.         self.y0_1 = 0                           # y cordinate of graph 1 & 2
    15.         self.y1_1 = 0
    16.         self.y0_2 = 0
    17.         self.y1_2 = 0
    18.         self.screen = Tkinter.Tk()
    19.         self.running = 1
    20.         self.screen.protocol("WM_DELETE_WINDOW", self.suicide)
    21.  
    22.     def pixel(self, C):
    23.         nP1 = self.new_ver_pixel_1
    24.         oP1 = self.old_ver_pixel_1
    25.         nP2 = self.new_ver_pixel_2
    26.         oP2 = self.old_ver_pixel_2
    27.  
    28.  
    29.         hP = self.hor_pixel
    30.         if(nP1 == oP1):
    31.             nP1 = nP1 + 1
    32.         if(nP2 == oP2):
    33.             nP2 = nP2 + 1
    34.  
    35.         if(nP1 > oP1):
    36.             self.y0_1 = oP1
    37.             self.y1_1 = nP1
    38.         else:
    39.             self.y0_1 = nP1
    40.             self.y1_1 = oP1
    41.  
    42.         if(nP2 > oP2):
    43.             self.y0_2 = oP2
    44.             self.y1_2 = nP2
    45.         else:
    46.             self.y0_2 = nP2
    47.             self.y1_2 = oP2
    48.  
    49.         coord = hP, self.y0_1, hP, self.y1_1
    50.         coord2 = hP, self.y0_2, hP, self.y1_2
    51.         print coord2
    52.  
    53.         hP = hP + 1
    54.         if(hP > 400):
    55.             hP = 5;
    56.         self.old_ver_pixel_1 = nP1
    57.         self.old_ver_pixel_2 = nP2
    58.  
    59.         #hP is the cycle number (movement along x-axis)
    60.         #this makes vertical black lines every cycle (every x-increment) to create a black background
    61.         C.create_line(hP , 0 , hP , 300, fill = 'black')
    62.         C.create_line(hP , 302 , hP , 602, fill = 'black')
    63.      
    64.         hwls = 50 #Horizontal white line spacing
    65.         vwls = 50 #Vertical white line spacing
    66.      
    67.         #every nTH vertical line, make it white (overwrites previous black line)
    68.         if hP in range (0, 600, vwls):
    69.             C.create_line(hP , 0 , hP , 602, fill = 'white')
    70.  
    71.         #every nTH horizonal pixel of every vertical line, make it white (overwrites previous black pixels)
    72.         for i in range (0, 602, hwls):
    73.             C.create_line(hP, i, hP, i+1, fill = 'white')
    74.  
    75.         C.create_line(coord, fill = 'red')
    76.         C.create_line(coord2, fill = 'yellow')
    77.         C.pack()
    78.         self.hor_pixel = hP
    79.  
    80.     def graph(self):
    81.         screen = self.screen
    82.  
    83.         graph_index(screen)
    84.  
    85.         screen.title("Analog Channel")
    86.         screen.geometry("800x800")
    87.         C = Tkinter.Canvas(screen , bg = "black", width = 600, height = 602)
    88.         C.create_line(5 , 301 , 400 , 301, fill = 'white')
    89.  
    90.         #photo = PhotoImage(file="../untitled.gif")
    91.         #C.create_image(0,0 ,image = photo)
    92.  
    93.         C.pack()
    94.         pixel = self.pixel
    95.         while self.running:
    96.             self.new_ver_pixel_1 = randint(0,300);
    97.             self.new_ver_pixel_2 = randint(0,300) + 302;
    98.             screen.after(10,pixel(C))
    99.             screen.update()
    100.         screen.mainloop()
    101.  
    102.     def suicide(self):
    103.         self.running = 0
    104.         self.screen.destroy()
    105.  
    106. def my_graph():
    107.     PT = pixelTron()
    108.     PTG = PT.graph
    109.     PTG()
    110.  
    111. def graph_index(screen):
    112.     label = Label(screen , text = "-20")
    113.     label.pack()
    114.     label.place(x = 70, y = 270)
    115.  
    116.     label = Label(screen , text = "-10")
    117.     label.pack()
    118.     label.place(x = 70, y = 215)
    119.  
    120.     label = Label(screen , text = "0")
    121.     label.pack()
    122.     label.place(x = 80, y = 140)
    123.  
    124.     label = Label(screen , text = "+10")
    125.     label.pack()
    126.     label.place(x = 70, y = 65)
    127.  
    128.     label = Label(screen , text = "+20")
    129.     label.pack()
    130.     label.place(x = 70, y = 0)
    131.  
    132.     label = Label(screen , text = "+20")
    133.     label.pack()
    134.     label.place(x = 70, y = 302)
    135.  
    136.     label = Label(screen , text = "+10")
    137.     label.pack()
    138.     label.place(x = 70, y = 375)
    139.  
    140.     label = Label(screen , text = "0")
    141.     label.pack()
    142.     label.place(x = 80, y = 450)
    143.  
    144.     label = Label(screen , text = "-10")
    145.     label.pack()
    146.     label.place(x = 70, y = 525)
    147.  
    148.     label = Label(screen , text = "-20")
    149.     label.pack()
    150.     label.place(x = 70, y = 600)
    151.  
    152. my_graph()
     
    Vindhyachal Takniki likes this.
  3. strantor

    AAC Fanatic!

    Oct 3, 2010
    4,302
    1,988
    I am also working on a stripchart project. You may be more pleased with this one. It is more efficient and looks very professional. This code requires no package installations so runs right out of the box, but it is for Python 3; you could modify it to work with Python 2 if you aren't keen on downloading Python 3

    [​IMG]

    The original code I got from stackoverflow, but that code does not work; it has a problem with the way threads are managed, and makes python.exe freeze up when you try to stop or reset the chart. I have corrected that error in the code posted below. The code posted below is a work-in-progress; it's the last "working" version of something that has now evolved quite a bit. I cannot post the most current version as it doesn't work yet and it's really messy. If you're interested, I can post future versions here.

    NOTE there is one known issue with this code; You MUST stop or reset the chart before clicking the "X" close button or else the running thread isn't properly terminated.

    Code (Python):
    1. #http://stackoverflow.com/questions/457246/what-is-the-best-real-time-plotting-widget-for-wxpython
    2. from tkinter import *
    3. import math, random, threading, time
    4.  
    5. class StripChart:
    6.  
    7.     def __init__(self, root):
    8.         self.chartThreadName = "_gen0_"
    9.         self.x=0
    10.         self.data = 0
    11.         self.bg = '#345'
    12.         self.gf = self.makeGraph(root)
    13.         self.cf = self.makeControls(root)
    14.         self.gf.pack()
    15.         self.cf.pack()
    16.         self.Reset()
    17.         self.runcount = 0
    18.  
    19.  
    20.     def makeGraph(self, frame):
    21.         self.sw = 1000
    22.         self.h = 200
    23.         self.top = 2
    24.         gf = Canvas(frame, width=self.sw, height=self.h+10,
    25.                     bg="#002", bd=0, highlightthickness=0)
    26.         gf.p = PhotoImage(width=2*self.sw, height=self.h)
    27.         self.item = gf.create_image(0, self.top, image=gf.p, anchor=NW)
    28.         return(gf)
    29.  
    30.     def makeControls(self, frame):
    31.         cf = Frame(frame, borderwidth=1, relief="raised")
    32.         Button(cf, text="Run", command=self.Run).grid(column=2, row=2)
    33.         Button(cf, text="Stop", command=self.Stop).grid(column=4, row=2)
    34.         Button(cf, text="Reset", command=self.Reset).grid(column=6, row=2)
    35.         self.fps = Label(cf, text="0 fps")
    36.         self.fps.grid(column=2, row=4, columnspan=5)
    37.         return(cf)
    38.  
    39.     def Run(self):
    40.         self.go = 1
    41.         for t in threading.enumerate():
    42.             if t.name == self.chartThreadName:# "_gen_":
    43.             #if t.name == "_gen0_":
    44.                 print("already running")
    45.                 return
    46.         #self.chartThreadName = "_gen" + str(self.runcount) + "_"
    47.         self.chartThread = threading.Thread(target=self.do_start, name=self.chartThreadName)
    48.         self.chartThread.start()
    49.         #self.runcount +=1
    50.         print(self.chartThreadName)
    51.  
    52.     def Stop(self):
    53.         self.go = 0
    54.  
    55.     def Reset(self):
    56.         self.Stop()
    57.         self.clearstrip(self.gf.p, '#345')
    58.  
    59.     def do_start(self):
    60.         t = 0
    61.         y2 = 0
    62.         tx = time.time()
    63.         if not self.go:
    64.             self.chartThread.join()
    65.         while self.go:
    66.             y1 = 0.2*math.sin(0.02*math.pi*t)
    67.             y2 = 0.9*y2 + 0.1*(random.random()-0.5)
    68.             self.scrollstrip(self.gf.p,
    69.                (0.25+y1,   0.25, 0.7+y2,   0.6,     0.7,   0.8),
    70.                ( '#ff4', '#f40', '#4af', '#080', '#0f0', '#080'),
    71.                  "" if t % 65 else "#088")
    72.  
    73.             t += 1
    74.             if not t % 100:
    75.                 tx2 = time.time()
    76.                 self.fps.config(text='%d fps' % int(100/(tx2 - tx)))
    77.                 tx = tx2
    78.             #time.sleep(0.001)
    79.  
    80.     def clearstrip(self, p, color):  # Fill strip with background color
    81.         self.bg = color              # save background color for scroll
    82.         self.data = None             # clear previous data
    83.         self.x = 0
    84.         p.tk.call(p, 'put', color, '-to', 0, 0, p['width'], p['height'])
    85.  
    86.     def scrollstrip(self, p, data, colors, bar=""):   # Scroll the strip, add new data
    87.         self.x = (self.x + 1) % self.sw               # x = double buffer position
    88.         bg = bar if bar else self.bg
    89.         p.tk.call(p, 'put', bg, '-to', self.x, 0,
    90.                   self.x+1, self.h)
    91.         p.tk.call(p, 'put', bg, '-to', self.x+self.sw, 0,
    92.                   self.x+self.sw+1, self.h)
    93.         self.gf.coords(self.item, -1-self.x, self.top)  # scroll to just-written column
    94.         if not self.data:
    95.             self.data = data
    96.         for d in range(len(data)):
    97.             y0 = int((self.h-1) * (1.0-self.data[d]))   # plot all the data points
    98.             y1 = int((self.h-1) * (1.0-data[d]))
    99.             ya, yb = sorted((y0, y1))
    100.             for y in range(ya, yb+1):                   # connect the dots
    101.                 p.put(colors[d], (self.x,y))
    102.                 p.put(colors[d], (self.x+self.sw,y))
    103.         self.data = data            # save for next call
    104.  
    105. def main():
    106.     root = Tk()
    107.     root.title("StripChart")
    108.     app = StripChart(root)
    109.     root.mainloop()
    110.  
    111. main()
     
    popad and Vindhyachal Takniki like this.
  4. Vindhyachal Takniki

    Thread Starter Member

    Nov 3, 2014
    348
    6
    Thx @strantor for this help.
    I was thinking of same. But I thought it would take huge time to print grids again & again on RPI2 board
    I am trying to measure what time it would take to sample adc & print it on graph. So I have changed the code as below. Now will see how much time it.
    On windows code had taken max 1.5 msec.

    Code (Python):
    1.  
    2.     def pixel(self, C):
    3. [B]        time1 = time.clock()
    4.         var1 = sample_adc_1()
    5.         var2 = sample_adc_2()[/B]
    6.         self.new_ver_pixel_1 = get_pixel(var1  , 0)
    7.         self.new_ver_pixel_2 = get_pixel(var2  , 302)
    8.      
    9.         nP1 = self.new_ver_pixel_1
    10.         oP1 = self.old_ver_pixel_1
    11.         nP2 = self.new_ver_pixel_2
    12.         oP2 = self.old_ver_pixel_2
    13.  
    14.  
    15.         hP = self.hor_pixel
    16.         if(nP1 == oP1):
    17.             nP1 = nP1 + 1
    18.         if(nP2 == oP2):
    19.             nP2 = nP2 + 1
    20.  
    21.         if(nP1 > oP1):
    22.             self.y0_1 = oP1
    23.             self.y1_1 = nP1
    24.         else:
    25.             self.y0_1 = nP1
    26.             self.y1_1 = oP1
    27.  
    28.         if(nP2 > oP2):
    29.             self.y0_2 = oP2
    30.             self.y1_2 = nP2
    31.         else:
    32.             self.y0_2 = nP2
    33.             self.y1_2 = oP2
    34.  
    35.         coord = hP, self.y0_1, hP, self.y1_1
    36.         coord2 = hP, self.y0_2, hP, self.y1_2
    37.  
    38.         hP = hP + 1
    39.         if(hP > 400):
    40.             hP = 5;
    41.         self.old_ver_pixel_1 = nP1
    42.         self.old_ver_pixel_2 = nP2
    43.  
    44.         #hP is the cycle number (movement along x-axis)
    45.         #this makes vertical black lines every cycle (every x-increment) to create a black background
    46.         C.create_line(hP , 0 , hP , 300, fill = 'black')
    47.         C.create_line(hP , 302 , hP , 602, fill = 'black')
    48.    
    49.         hwls = 75 #Horizontal white line spacing
    50.         vwls = 50 #Vertical white line spacing
    51.    
    52.         #every nTH vertical line, make it white (overwrites previous black line)
    53.         if hP in range (0, 600, vwls):
    54.             C.create_line(hP , 0 , hP , 602, fill = 'white')
    55.  
    56.         #every nTH horizonal pixel of every vertical line, make it white (overwrites previous black pixels)
    57.         for i in range (0, 602, hwls):
    58.             C.create_line(hP, i, hP, i+1, fill = 'white')
    59.  
    60.         C.create_line(coord, fill = 'red')
    61.         C.create_line(coord2, fill = 'yellow')
    62.         C.pack()
    63.         self.hor_pixel = hP
    64.         [B]print time.clock() - time1[/B]
    65.      
    66.     def graph(self):
    67.         screen = self.screen
    68.  
    69.         graph_index(screen)
    70.  
    71.         screen.title("Analog Channel")
    72.         screen.geometry("800x800")
    73.         C = Tkinter.Canvas(screen , bg = "black", width = 600, height = 602)
    74.  
    75.         C.pack()
    76.         pixel = self.pixel
    77.         while self.running:
    78.             [B]screen.after(100,pixel(C))[/B]
    79.             screen.update()
    80.         screen.mainloop()
    81.  
    Moderators note: set code to python
     
    Last edited by a moderator: Jul 20, 2015
  5. popad

    New Member

    Sep 7, 2016
    1
    0
    Wonderful code. Thank you to share.

    If I want to write annotations with some values on this stripchart, how can I do that ?

    Best regards,

    PopaD
     
Loading...