-
Notifications
You must be signed in to change notification settings - Fork 0
/
MetraPlot
executable file
·152 lines (128 loc) · 4.34 KB
/
MetraPlot
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/python3
# -*- coding: utf-8 -*-
'''
Simple demo program that reads the output of e.g. 'Metra'
and plots the measured values - either over time or by number.
It uses the extra python package 'matplotlib' for visualisation.
Install with: 'apt install python3-matplotlib' if missing.
'''
import sys
import argparse
import csv
import matplotlib.pyplot as plt
# create the parser
ap = argparse.ArgumentParser(description="Plot data - e.g. received from Gossen METRAHit 29S via program 'Metra'")
# add the arguments
ap.add_argument( '-t', '--title',
action = 'store', default = 'MetraPlot',
help = "set the title of the plot, default is 'MetraPlot'")
ap.add_argument( '-f', '--first_sample',
action = 'store', type = int, default = 0,
help = 'first sample to display')
ap.add_argument( '-l', '--last_sample',
action = 'store', type = int, default = sys.maxsize,
help = 'last sample to display')
ap.add_argument( '-V',
action = 'count', dest = 'verbose', default = 0,
help = 'increase verbosity' )
ap.add_argument( 'infile',
type = argparse.FileType( 'r' ), nargs = '?', default = sys.stdin,
help = 'read measurement data from optional infile, use stdin otherwise' )
# parse my argument
options = ap.parse_args()
# Use output of 'OpenMetra'
# Format: no header, values are SI units s and V, separated either by space or comma
# auto-detect the format
# detect also "german" csv (comma as decimal separator and semicolon as field separator)
one_line = options.infile.readline().rstrip('\n') # get one line
options.infile.seek( 0 ) # and rewind the input
if options.verbose:
print( '1st line: "', one_line, '"', sep='' )
time_unit = None
data_unit = None
time_index = None
data_index = None
# data file or csv file?
if ',' in one_line and '.' in one_line: # csv
delim = ','
elif ';' in one_line: # german csv
delim = ';'
else: # data file
delim = ' '
elements = one_line.split( delim )
num_elements = len( elements )
dec_sep = '.'
num_values = one_line.count( dec_sep )
if 0 == num_values and ',' != delim: # german data or csv
dec_sep = ','
num_values = one_line.count( dec_sep )
if num_elements >= 4: # "t.t 's' u.u 'V'"
time_index = 0
time_unit = elements[1]
data_index = 2
data_unit = elements[3]
elif num_elements >= 2:
if num_values == 1: # "u.u 'V'"
data_index = 0
data_unit = elements[1]
else: # "t.t u.u"
time_index = 0
data_index = 1
else: # "u.u"
data_index = 0
if options.verbose:
print( "dec_sep: '", dec_sep, "', delim: '", delim, "'", sep='' )
if options.verbose > 1:
print( "time_index: ", time_index, ", time_unit: '", time_unit,
"', data_index: ", data_index, ", data_unit: '", data_unit, "'", sep='')
# process the data input
capture = csv.reader( options.infile, delimiter=delim )
# separate into one (data) or two (time, data) lists (plus number list)
numbers, time, data = [], [], []
number = -1
for row in capture:
number += 1
if len( row ) < num_elements: # incomplete row
continue
if time_index is not None:
t = row[ time_index ]
if '.' != dec_sep: # german data
t = t.replace( dec_sep, '.' )
t = float( t )
if round( t ) < options.first_sample:
continue
if round( t ) > options.last_sample:
continue
time.append( t )
else:
if number < options.first_sample:
continue
if number > options.last_sample:
continue
numbers.append( number )
if data_index is not None:
d = row[ data_index ]
if '.' != dec_sep:
d = d.replace( dec_sep, '.' )
d = float( d )
data.append( d )
options.infile.close()
if options.verbose > 1:
print( 'numbers_size: ', len( numbers ), ', time_size: ', len( time ), ', data_size: ', len( data ), sep='' )
if data_unit is None:
data_unit = 'Value'
# prepare a nice picture with the help of 'matplotlib.pyplot'
figure, measure = plt.subplots( 1 )
measure.set_title( options.title )
if len( time ):
measure.plot( time, data )
xl = 'Time (s)'
else:
measure.plot( numbers, data )
xl = 'N'
measure.set(xlabel=xl, ylabel=data_unit )
measure.grid( True )
# arrange layout for good readability
figure.tight_layout()
# display everything
plt.show()