Friday, November 14, 2014

displaying dynamic graphic (and saving it after a while)

A friend of mine, who plays with a raspberry nano computer, wanted to display a sensor (don't remember which). So I tried to write a program getting a data, displaying it by Tkinter, and saving the graphic.

Un ami, qui s'amuse avec le nano computer raspberry, désirait afficher les données d'une sonde (je ne sais plus laquelle). J'ai donc tenté d'écrire un programme qui reçoit des données, les affiche en continu et les sauve de temps en temps.

This script does:

  • display a dot every second (using the Tkinter after() fonction) at the right of the graphic
  • shift the graphic one pixel per second to the left, letting you see the ten past minutes
  • tag the time (hh:mm) at the 50th second, with a matrixed digit method
  • save the graphic every ten minutes (.PGM, Portable Gray Map, a category of PNM)
  • seem to be python3 compatible (displaying: yes, saving: smog until now)
  • what else?

Ce script:

  • inscrit un point toutes les secondes à la droite du graphique, avec la méthode after() de Tkinter
  • déplace le graphique d'un pixel à droite, permettant de regarder les dix dernières minutes
  • écrit le temps hh:mm à la 50e secondes, avec une routine basée sur une matrice de points
  • sauve le graphique toutes les dix minutes (PGM, Portable Gray Map, une catégorie de PNM)
  • semble être compatible avec python3 (l'affichage, mais la sauvegarde est une purée de pois)
  • quoi d'autre?

The script is more or less commented, but I'm a rather wild scripter.

Calling a routine every second - after(1000, routine) - is not the best way to pace a program, because there are so many things the program does between each call! I prefer to ask every tenth of second whether it's already the next second. You can do better with a call every hundredth of second.

Le script est plus ou moins commenté (en mauvais anglais).

Utiliser une pause d'une seconde par la méthode after(1000, routine) (Tkinter) est une mauvaise chose, parce que le script prend également du temps pour faire tout ce qu'il a à faire entre deux pauses. Je préfère donc demander tous les dixièmes de seconde si le système est passé à la seconde suivante. Vous pouvez faire mieux en faisant un appel tous les 100e de secondes. 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#! /usr/bin/python -Qnew
 
# 2014.11.14 Jean-Christophe Beumier - www.jchr.be
# GPL2, see www.gnu.org/licenses/licenses.html
 
# dynamic display of data from any sensor or computing
# saving graphic files .PNM every 10 minutes
 
import time, os
from Tkinter import *
from math import *
 
# for python 3:
#! /usr/bin/python3
# from tkinter import * 
 
# digit matrix for printdate()
dates=[[6, 9, 9, 9, 9, 9, 6]]
dates+=[[2, 6, 2, 2, 2, 2, 7]]
dates+=[[6, 9, 1, 2, 4, 8, 15]]
dates+=[[6, 9, 1, 2, 1, 9, 6]]
dates+=[[2, 2, 6, 6, 10, 15, 2]]
dates+=[[15, 8, 14, 1, 1, 9, 6]]
dates+=[[6, 8, 14, 9, 9, 9, 6]]
dates+=[[15, 1, 2, 2, 4, 4, 4]]
dates+=[[6, 9, 9, 6, 9, 9, 6]]
dates+=[[6, 9, 9, 9, 7, 1, 6]]
 
tab=[chr(255)]*66000   # list ("table") for image 600x100px
for i in range(600):
  tab[29400+i]=chr(144) # gray horizontal line at mid-height
imgdata="".join(tab) # joining the bytes
p5="P5 600 110 255\n"+imgdata # header and image-data 
 
ang=0
def sensor():
  global ang
  #   on UNIX, 'acpi -t' returns 'Thermal 0: ok, 36.0 degrees C'
  # pfile=os.popen("acpi -t", "r")
  # line=pfile.read()
  # pfile.close()
  # temp=int(round(float(line.split()[3]))) # 4th string of the line
 
  #   not sure you're on Unix, so let's compute something:
  calcul=sin(ang/19)/(1+abs(tan(ang/27)))*39+abs(cos(ang/10))*10
  ang+=1
  return(calcul) 
 
def printdate(x):
  global dates, tab
  if x==1:
    string=time.strftime("%H:%M")
    colour=0 # black digits for time
  else:
    string=time.strftime("%Y.%m.%d")
    colour=80 # dark gray digits for date
  off=0
  for p in string:
    try:
      a=int(p)  # is a number
      cp=0 # vertical offset for digit matrix printing
      for q in dates[a]: # q is a number matrix
        for r in range(4):
          if q & 2**r: # matching bit of number
            tab[600*(102+cp)+549+off+5-r]=chr(colour)
        cp+=1
      off+=5
    except:
      if p==".": # not a number
        tab[600*108+548+off+3]=chr(0)
        off+=3
      elif p==":":
        tab[600*104+549+off+3]=chr(0)
        tab[600*107+549+off+3]=chr(0)
        off+=4
 
h=49 # mid-height
count=int(time.strftime("%S")) # getting the first second
filename=time.strftime("%Y.%m.%d-%Hh%M")
def formage():
  global count, tab, p5, h, filename
  if count%10==0:  # gray dotted vertical line every 10px
    if count==0:   # the first darker
      for i in range(100):
        tab[i*600+599]=chr(64)
    elif count%60==0: # plain line every 60px (minute)
      for i in range(100):
        tab[i*600+599]=chr(144)
    else:
      for i in range(50): # printing date or time
        tab[i*1200+1199]=chr(144)
      if count%60==50:
        if count//60==1:
          printdate(2) # date
        else:
          printdate(1) # time
      
  sortie=sensor()
  h=50+int(sortie)
  if h>99: h=99 # display from 0 to 99, no outside
  if h<0: h=0 
  tab[(99-h)*600+599]=chr(0) # writing the dot into the matrix
 
  p5="P5 600 110 255\n"+"".join(tab) # assembling PNM image
  for i in range(110): # rubbing out the first column
    tab[i*600]=chr(255)
  tab=tab[1:]+[chr(255)] # deleting 1 byte: shifting 1px to left
  tab[29999]=chr(144)    # middle point
  if count%2==1: # 1 out of 2px
    tab[5999]=chr(144)   # adding 90%
    tab[11999]=chr(144)  # adding 80%
    tab[17999]=chr(144)  # adding 70%
    tab[23999]=chr(144)  # adding 60%
    tab[35999]=chr(144)  # adding 40%
    tab[41999]=chr(144)  # adding 30%
    tab[47999]=chr(144)  # adding 20%
    tab[53999]=chr(144)  # adding 10%
 
  count+=1
  if count==600: # saving after 600 dots (image width)
    han=open("tk-%s.pgm" %(filename),"w")
    han.write(p5)
    han.close()
    count=0
    filename=time.strftime("%Y.%m.%d-%Hh%M") # next one
 
  label0.config(text="%5.2f" %(round(sortie,2)))  # rewriting
  image0.config(data=p5)       # image redrawing
  label1.config(image=image0)  # image redisplaying
 
sec0=99
def checktime():
  global sec0
  nsec=int(time.strftime("%S"))
  if nsec!=sec0:
    sec0=nsec    
    formage()
  root0.after(100, checktime)  # waits 0.1sec, before reiteration
 
# tkinter setting:
 
root0=Tk()
root0.geometry("620x150")
label0=Label(root0, text="0.00")
label0.pack()
label0.after(0, checktime)   # waiting 0 sec and calling
image0=PhotoImage(data=p5)
label1=Label(image=image0) # image displaying
label1.image=image0
label1.pack()
 
root0.mainloop()

 

 

Add comment

Add comment

authimage