oml-plot-tools 0.9.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. oml_plot_tools/__init__.py +24 -0
  2. oml_plot_tools/common.py +172 -0
  3. oml_plot_tools/consum.py +187 -0
  4. oml_plot_tools/main.py +49 -0
  5. oml_plot_tools/radio.py +184 -0
  6. oml_plot_tools/tests/__init__.py +22 -0
  7. oml_plot_tools/tests/common.py +126 -0
  8. oml_plot_tools/tests/common_test.py +133 -0
  9. oml_plot_tools/tests/consum_test.py +201 -0
  10. oml_plot_tools/tests/examples/consumption.oml +4179 -0
  11. oml_plot_tools/tests/examples/consumption_all.png +0 -0
  12. oml_plot_tools/tests/examples/consumption_clock.png +0 -0
  13. oml_plot_tools/tests/examples/consumption_current.png +0 -0
  14. oml_plot_tools/tests/examples/consumption_only_one.oml +10 -0
  15. oml_plot_tools/tests/examples/grenoble-iotlab.png +0 -0
  16. oml_plot_tools/tests/examples/radio.oml +2009 -0
  17. oml_plot_tools/tests/examples/radio_clock.png +0 -0
  18. oml_plot_tools/tests/examples/radio_separated_last.png +0 -0
  19. oml_plot_tools/tests/examples/radio_single.png +0 -0
  20. oml_plot_tools/tests/examples/robot.oml +1447 -0
  21. oml_plot_tools/tests/examples/trajectory_all.png +0 -0
  22. oml_plot_tools/tests/examples/trajectory_angle.png +0 -0
  23. oml_plot_tools/tests/examples/trajectory_circuit.png +0 -0
  24. oml_plot_tools/tests/examples/trajectory_clock.png +0 -0
  25. oml_plot_tools/tests/examples/trajectory_only.png +0 -0
  26. oml_plot_tools/tests/main_parser_test.py +51 -0
  27. oml_plot_tools/tests/radio_test.py +173 -0
  28. oml_plot_tools/tests/traj_test.py +223 -0
  29. oml_plot_tools/traj.py +352 -0
  30. oml_plot_tools-0.9.1.dist-info/METADATA +35 -0
  31. oml_plot_tools-0.9.1.dist-info/RECORD +35 -0
  32. oml_plot_tools-0.9.1.dist-info/WHEEL +4 -0
  33. oml_plot_tools-0.9.1.dist-info/entry_points.txt +5 -0
  34. oml_plot_tools-0.9.1.dist-info/licenses/AUTHORS +1 -0
  35. oml_plot_tools-0.9.1.dist-info/licenses/COPYING +518 -0
@@ -0,0 +1,24 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ # This file is a part of IoT-LAB oml-plot-tools
4
+ # Copyright (C) 2015 INRIA (Contact: admin@iot-lab.info)
5
+ # Contributor(s) : see AUTHORS file
6
+ #
7
+ # This software is governed by the CeCILL license under French law
8
+ # and abiding by the rules of distribution of free software. You can use,
9
+ # modify and/ or redistribute the software under the terms of the CeCILL
10
+ # license as circulated by CEA, CNRS and INRIA at the following URL
11
+ # http://www.cecill.info.
12
+ #
13
+ # As a counterpart to the access to the source code and rights to copy,
14
+ # modify and redistribute granted by the license, users are provided only
15
+ # with a limited warranty and the software's author, the holder of the
16
+ # economic rights, and the successive licensors have only limited
17
+ # liability.
18
+ #
19
+ # The fact that you are presently reading this means that you have had
20
+ # knowledge of the CeCILL license and that you accept its terms.
21
+
22
+ """List of tools to display iot-lab oml generated files"""
23
+
24
+ __version__ = "0.9.1"
@@ -0,0 +1,172 @@
1
+ #!/usr/bin/python
2
+ # -*- coding: utf-8 -*-
3
+
4
+ # This file is a part of IoT-LAB oml-plot-tools
5
+ # Copyright (C) 2015 INRIA (Contact: admin@iot-lab.info)
6
+ # Contributor(s) : see AUTHORS file
7
+ #
8
+ # This software is governed by the CeCILL license under French law
9
+ # and abiding by the rules of distribution of free software. You can use,
10
+ # modify and/ or redistribute the software under the terms of the CeCILL
11
+ # license as circulated by CEA, CNRS and INRIA at the following URL
12
+ # http://www.cecill.info.
13
+ #
14
+ # As a counterpart to the access to the source code and rights to copy,
15
+ # modify and redistribute granted by the license, users are provided only
16
+ # with a limited warranty and the software's author, the holder of the
17
+ # economic rights, and the successive licensors have only limited
18
+ # liability.
19
+ #
20
+ # The fact that you are presently reading this means that you have had
21
+ # knowledge of the CeCILL license and that you accept its terms.
22
+
23
+ """Common functions for all oml types"""
24
+
25
+ # Issues with numpy
26
+ # pylint:disable=no-member
27
+
28
+ from collections import OrderedDict, namedtuple
29
+
30
+ import matplotlib.pyplot as plt
31
+ import numpy
32
+
33
+ OML_HEADER_LEN = 9
34
+
35
+ OML_TYPES = {
36
+ "consumption": 1,
37
+ "radio": 2,
38
+ "event": 3,
39
+ "sniffer": 4,
40
+ "robot_pose": 10,
41
+ }
42
+
43
+ TIMESTAMP_LABEL = "Sample Time (sec)"
44
+ OML_FIELDS = [
45
+ ("timestamp", float),
46
+ ("type", numpy.str_, 16),
47
+ ("num", int),
48
+ ("t_s", int),
49
+ ("t_us", int),
50
+ ]
51
+
52
+ MeasureTuple = namedtuple("MeasureTuple", ["name", "type", "label"])
53
+
54
+
55
+ def measures_dict(*measures_tuples):
56
+ """Create a dict of 'MeasuresTuple' with given measures"""
57
+ measures_list = [(m[0], MeasureTuple(*m)) for m in measures_tuples]
58
+ return OrderedDict(measures_list)
59
+
60
+
61
+ def oml_load(filename, meas_type, measures):
62
+ """Load oml file
63
+ :returns: numpy array
64
+ :measures: list of MeasureTuple"""
65
+
66
+ meas_dtypes = [(m.name, m.type) for m in measures]
67
+
68
+ try:
69
+ data = _oml_read(filename, meas_type, meas_dtypes)
70
+ except IOError as err:
71
+ raise ValueError(f"Error opening oml file:\n{err}\n")
72
+ except (ValueError, StopIteration, IndexError) as err:
73
+ raise ValueError(f"Error reading oml file:\n{err}\n")
74
+ except TypeError as err:
75
+ raise ValueError(f"{err}")
76
+
77
+ # No error when only one value
78
+ data = numpy.atleast_1d(data)
79
+
80
+ # No empty measures
81
+ # I think not reproducible anymore with genfromtxt however.
82
+ if array_empty(data): # pragma: no cover
83
+ raise ValueError("No values, not an oml file")
84
+
85
+ return data
86
+
87
+
88
+ def oml_plot_clock(data, title="Clock time verification"):
89
+ """Print clock diff between measures
90
+ :params data: oml_load returned array
91
+ """
92
+ time = data["timestamp"]
93
+ clock_diff = numpy.diff(time) * 1000
94
+
95
+ print(f"Time from {time[0]:f} to {time[-1]:f}")
96
+ print("NB Points =", len(time))
97
+ print("Duration (s)=", time[-1] - time[0])
98
+ print("Steptime (ms)=", 1000 * (time[-1] - time[0]) / len(time))
99
+ print("Clock mean (ms)=", numpy.mean(clock_diff))
100
+ print("Clock std (ms)=", numpy.std(clock_diff))
101
+ print("Clock max (ms)=", numpy.max(clock_diff))
102
+ print("Clock min (ms)=", numpy.min(clock_diff))
103
+
104
+ plt.figure()
105
+ plt.title(title)
106
+ plt.grid()
107
+ plt.plot(clock_diff)
108
+
109
+ return True
110
+
111
+
112
+ def plot(data, title, field, ylabel, xlabel=TIMESTAMP_LABEL):
113
+ """Plot data"""
114
+ plt.title(title)
115
+ plt.grid()
116
+ plt.xlabel(xlabel)
117
+ plt.ylabel(ylabel)
118
+ plt.plot(data["timestamp"], data[field])
119
+
120
+
121
+ def plot_show():
122
+ """Show image."""
123
+ plt.tight_layout()
124
+ plt.show()
125
+
126
+
127
+ # Help functions
128
+
129
+
130
+ def _oml_read(filename, meas_type, fields_dtypes=()):
131
+ """Read oml file
132
+ :measures: list of MeasureTuple"""
133
+
134
+ # Select values
135
+ dtypes = OML_FIELDS + list(fields_dtypes)
136
+ names = [entry[0] for entry in dtypes]
137
+
138
+ # Read values from file
139
+ c_meas_type = {names.index("type"): _valid_oml_f(meas_type)}
140
+ data = numpy.genfromtxt(
141
+ filename,
142
+ skip_header=OML_HEADER_LEN,
143
+ names=names,
144
+ dtype=dtypes,
145
+ converters=c_meas_type,
146
+ invalid_raise=False,
147
+ )
148
+
149
+ # Update 'timestamp' field with the cn calculated timestamp
150
+ for row in numpy.nditer(data, op_flags=["readwrite"]):
151
+ timestamp = row["t_s"] + row["t_us"] / 1e6
152
+ row["timestamp"] = timestamp
153
+
154
+ return data
155
+
156
+
157
+ def _valid_oml_f(meas_type):
158
+ """Return a function that validates oml type"""
159
+
160
+ def _validate(value):
161
+ """Check that 'meas_type' column matchs requested"""
162
+ value = int(value)
163
+ if int(value) == OML_TYPES[meas_type]:
164
+ return meas_type
165
+ raise TypeError(f"OML file is not: {meas_type}")
166
+
167
+ return _validate
168
+
169
+
170
+ def array_empty(array):
171
+ """Test if array is not None or not empty."""
172
+ return array is None or len(array) == 0
@@ -0,0 +1,187 @@
1
+ #!/usr/bin/python
2
+ # -*- coding: utf-8 -*-
3
+
4
+ # This file is a part of IoT-LAB oml-plot-tools
5
+ # Copyright (C) 2015 INRIA (Contact: admin@iot-lab.info)
6
+ # Contributor(s) : see AUTHORS file
7
+ #
8
+ # This software is governed by the CeCILL license under French law
9
+ # and abiding by the rules of distribution of free software. You can use,
10
+ # modify and/ or redistribute the software under the terms of the CeCILL
11
+ # license as circulated by CEA, CNRS and INRIA at the following URL
12
+ # http://www.cecill.info.
13
+ #
14
+ # As a counterpart to the access to the source code and rights to copy,
15
+ # modify and redistribute granted by the license, users are provided only
16
+ # with a limited warranty and the software's author, the holder of the
17
+ # economic rights, and the successive licensors have only limited
18
+ # liability.
19
+ #
20
+ # The fact that you are presently reading this means that you have had
21
+ # knowledge of the CeCILL license and that you accept its terms.
22
+
23
+
24
+ """
25
+ usage: plot_oml_consum [-h] -i DATA [-l TITLE] [-b BEGIN] [-e END] [-a] [-p]
26
+ [-v] [-c] [-t]
27
+
28
+ Plot iot-lab consumption OML files
29
+
30
+ options:
31
+ -h, --help show this help message and exit
32
+ -i, --input DATA Node consumption values
33
+ -l, --label TITLE Graph title
34
+ -b, --begin BEGIN Sample start
35
+ -e, --end END Sample end
36
+
37
+ plot:
38
+ Plot selection
39
+
40
+ -a, --all Plot power/voltage/current on one figure (default)
41
+ -p, --power Plot power
42
+ -v, --voltage Plot voltage
43
+ -c, --current Plot current
44
+ -t, --time Plot time verification
45
+ """ # noqa: E501
46
+
47
+ import argparse
48
+ import sys
49
+
50
+ import matplotlib.pyplot as plt
51
+
52
+ from . import common
53
+
54
+ # Selection variables
55
+ _POWER = "power"
56
+ _VOLTAGE = "voltage"
57
+ _CURRENT = "current"
58
+ _ALL = "all"
59
+ _TIME = "time"
60
+ _TITLE = "Node"
61
+
62
+
63
+ MEASURES_D = common.measures_dict(
64
+ (_POWER, float, "Power (W)"),
65
+ (_VOLTAGE, float, "Voltage (V)"),
66
+ (_CURRENT, float, "Current (A)"),
67
+ )
68
+
69
+
70
+ def oml_load(filename):
71
+ """Load consumption oml file"""
72
+ data = common.oml_load(filename, "consumption", MEASURES_D.values())
73
+ return data
74
+
75
+
76
+ PARSER = argparse.ArgumentParser(
77
+ prog="plot_oml_consum", description="Plot iot-lab consumption OML files"
78
+ )
79
+ PARSER.add_argument(
80
+ "-i",
81
+ "--input",
82
+ dest="data",
83
+ type=oml_load,
84
+ required=True,
85
+ help="Node consumption values",
86
+ )
87
+ PARSER.add_argument("-l", "--label", dest="title", default=_TITLE, help="Graph title")
88
+ PARSER.add_argument("-b", "--begin", default=0, type=int, help="Sample start")
89
+ PARSER.add_argument("-e", "--end", default=-1, type=int, help="Sample end")
90
+
91
+ _PLOT = PARSER.add_argument_group("plot", "Plot selection")
92
+ _PLOT.add_argument(
93
+ "-a",
94
+ "--all",
95
+ dest="plot",
96
+ const=_ALL,
97
+ action="append_const",
98
+ help="Plot power/voltage/current on one figure (default)",
99
+ )
100
+ _PLOT.add_argument(
101
+ "-p", "--power", dest="plot", const=_POWER, action="append_const", help="Plot power"
102
+ )
103
+ _PLOT.add_argument(
104
+ "-v",
105
+ "--voltage",
106
+ dest="plot",
107
+ const=_VOLTAGE,
108
+ action="append_const",
109
+ help="Plot voltage",
110
+ )
111
+ _PLOT.add_argument(
112
+ "-c",
113
+ "--current",
114
+ dest="plot",
115
+ const=_CURRENT,
116
+ action="append_const",
117
+ help="Plot current",
118
+ )
119
+ _PLOT.add_argument(
120
+ "-t",
121
+ "--time",
122
+ dest="plot",
123
+ const=_TIME,
124
+ action="append_const",
125
+ help="Plot time verification",
126
+ )
127
+
128
+
129
+ def consumption_plot(data, title, selection):
130
+ """Plot consumption values according to selection
131
+
132
+ :param data: numpy array returned by oml_read
133
+ :param title: Subplots title base
134
+ :param selection: with values in
135
+ 'power', 'voltage', 'current': plot on different windows
136
+ 'all': plot all three on the same window
137
+ 'time': plot time verification
138
+ """
139
+
140
+ # Single selection of 'p/v/c'
141
+ for value in (_POWER, _VOLTAGE, _CURRENT):
142
+ if value in selection:
143
+ oml_plot(data, title, [MEASURES_D[value]])
144
+
145
+ # Plot all on the same window
146
+ if _ALL in selection:
147
+ oml_plot(data, title, MEASURES_D.values())
148
+
149
+ # Clock verification
150
+ if "time" in selection:
151
+ common.oml_plot_clock(data)
152
+
153
+ common.plot_show()
154
+
155
+
156
+ def oml_plot(data, title, meas_tuples):
157
+ """Plot consumption value for 'meas_tuples'
158
+
159
+ :param data: numpy array returned by oml_read
160
+ :param title: Subplots title base
161
+ :param meas_tuples: numpy.dtypesplots separated on different windows
162
+ """
163
+
164
+ nbplots = len(meas_tuples)
165
+ plt.figure()
166
+
167
+ for num, meas in enumerate(meas_tuples, start=1):
168
+ plt.subplot(nbplots, 1, num)
169
+
170
+ _title = f"{title} {meas.name}"
171
+ common.plot(data, _title, meas.name, meas.label)
172
+
173
+
174
+ def main(args=None):
175
+ """iotlab-plot consum command"""
176
+ args = args or sys.argv[1:]
177
+
178
+ opts = PARSER.parse_args(args)
179
+ # default to plot all
180
+ selection = opts.plot or (_ALL)
181
+ # select samples
182
+ data = opts.data[opts.begin : opts.end]
183
+ consumption_plot(data, opts.title, selection)
184
+
185
+
186
+ if __name__ == "__main__":
187
+ main()
oml_plot_tools/main.py ADDED
@@ -0,0 +1,49 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ # This file is a part of IoT-LAB oml-plot-tools
4
+ # Copyright (C) 2015 INRIA (Contact: admin@iot-lab.info)
5
+ # Contributor(s) : see AUTHORS file
6
+ #
7
+ # This software is governed by the CeCILL license under French law
8
+ # and abiding by the rules of distribution of free software. You can use,
9
+ # modify and/ or redistribute the software under the terms of the CeCILL
10
+ # license as circulated by CEA, CNRS and INRIA at the following URL
11
+ # http://www.cecill.info.
12
+ #
13
+ # As a counterpart to the access to the source code and rights to copy,
14
+ # modify and redistribute granted by the license, users are provided only
15
+ # with a limited warranty and the software's author, the holder of the
16
+ # economic rights, and the successive licensors have only limited
17
+ # liability.
18
+ #
19
+ # The fact that you are presently reading this means that you have had
20
+ # knowledge of the CeCILL license and that you accept its terms.
21
+
22
+ """Main parser."""
23
+
24
+ import sys
25
+ from argparse import ArgumentParser
26
+
27
+ import oml_plot_tools.consum
28
+ import oml_plot_tools.radio
29
+ import oml_plot_tools.traj
30
+
31
+
32
+ def main(args=None):
33
+ """'iotlab' main function."""
34
+ args = args or sys.argv[1:]
35
+
36
+ commands = {
37
+ "consum": oml_plot_tools.consum.main,
38
+ "radio": oml_plot_tools.radio.main,
39
+ "traj": oml_plot_tools.traj.main,
40
+ "help": None,
41
+ }
42
+
43
+ parser = ArgumentParser()
44
+ parser.add_argument("command", nargs="?", choices=commands.keys(), default="help")
45
+ commands["help"] = lambda args: parser.print_help()
46
+
47
+ opts, args = parser.parse_known_args(args)
48
+
49
+ return commands[opts.command](args)
@@ -0,0 +1,184 @@
1
+ #!/usr/bin/python
2
+ # -*- coding: utf-8 -*-
3
+
4
+ # This file is a part of IoT-LAB oml-plot-tools
5
+ # Copyright (C) 2015 INRIA (Contact: admin@iot-lab.info)
6
+ # Contributor(s) : see AUTHORS file
7
+ #
8
+ # This software is governed by the CeCILL license under French law
9
+ # and abiding by the rules of distribution of free software. You can use,
10
+ # modify and/ or redistribute the software under the terms of the CeCILL
11
+ # license as circulated by CEA, CNRS and INRIA at the following URL
12
+ # http://www.cecill.info.
13
+ #
14
+ # As a counterpart to the access to the source code and rights to copy,
15
+ # modify and redistribute granted by the license, users are provided only
16
+ # with a limited warranty and the software's author, the holder of the
17
+ # economic rights, and the successive licensors have only limited
18
+ # liability.
19
+ #
20
+ # The fact that you are presently reading this means that you have had
21
+ # knowledge of the CeCILL license and that you accept its terms.
22
+
23
+
24
+ """
25
+ usage: plot_oml_radio [-h] -i DATA [-l TITLE] [-b BEGIN] [-e END] [-a] [-p]
26
+ [-t]
27
+
28
+ Plot iot-lab radio OML files
29
+
30
+ options:
31
+ -h, --help show this help message and exit
32
+ -i, --input DATA Node radio values
33
+ -l, --label TITLE Graph title
34
+ -b, --begin BEGIN Sample start
35
+ -e, --end END Sample end
36
+
37
+ plot:
38
+ Plot selection
39
+
40
+ -a, --all Plot all channels in one window (default)
41
+ -p, --plot Plot channels in different windows
42
+ -t, --time Plot time verification
43
+ """
44
+
45
+ import argparse
46
+ import sys
47
+
48
+ import matplotlib.pyplot as plt
49
+
50
+ from . import common
51
+
52
+ MEASURES_D = common.measures_dict(
53
+ ("channel", int, "Channel"),
54
+ ("rssi", int, "RSSI (dBm)"),
55
+ )
56
+
57
+
58
+ def oml_load(filename):
59
+ """Load radio oml file"""
60
+ data = common.oml_load(filename, "radio", MEASURES_D.values())
61
+ return data
62
+
63
+
64
+ # Selection variables
65
+ _JOINED = "joined"
66
+ _SEPARATED = "separated"
67
+ _TIME = "time"
68
+
69
+
70
+ PARSER = argparse.ArgumentParser(
71
+ prog="plot_oml_radio", description="Plot iot-lab radio OML files"
72
+ )
73
+ PARSER.add_argument(
74
+ "-i", "--input", dest="data", type=oml_load, required=True, help="Node radio values"
75
+ )
76
+ PARSER.add_argument("-l", "--label", dest="title", default="Node", help="Graph title")
77
+ PARSER.add_argument("-b", "--begin", default=0, type=int, help="Sample start")
78
+ PARSER.add_argument("-e", "--end", default=-1, type=int, help="Sample end")
79
+
80
+ _PLOT = PARSER.add_argument_group("plot", "Plot selection")
81
+ _PLOT.add_argument(
82
+ "-a",
83
+ "--all",
84
+ dest="plot",
85
+ const=_JOINED,
86
+ action="append_const",
87
+ help="Plot all channels in one window (default)",
88
+ )
89
+ _PLOT.add_argument(
90
+ "-p",
91
+ "--plot",
92
+ dest="plot",
93
+ const=_SEPARATED,
94
+ action="append_const",
95
+ help="Plot channels in different windows",
96
+ )
97
+ _PLOT.add_argument(
98
+ "-t",
99
+ "--time",
100
+ dest="plot",
101
+ const=_TIME,
102
+ action="append_const",
103
+ help="Plot time verification",
104
+ )
105
+
106
+
107
+ def radio_plot(data, title, selection):
108
+ """Plot radio values according to selection
109
+
110
+ :param data: numpy array returnel by oml_read
111
+ :param title: Subplots title base
112
+ :param selection: with values in
113
+ 'joined': plot on the same window
114
+ 'separated': plot on different windows
115
+ 'time': plot time verification
116
+ """
117
+
118
+ if _JOINED in selection:
119
+ oml_plot_rssi(data, title)
120
+ if _SEPARATED in selection:
121
+ oml_plot_rssi(data, title, separated=True)
122
+
123
+ # Clock verification
124
+ if _TIME in selection:
125
+ common.oml_plot_clock(data)
126
+
127
+ common.plot_show()
128
+
129
+
130
+ def list_channels(data):
131
+ """List radio channels used in data"""
132
+ channels = list(set(data["channel"]))
133
+ return sorted(channels)
134
+
135
+
136
+ def with_channel(data, channel):
137
+ """Extract data where measured channel == `channel`"""
138
+ select = data["channel"] == channel
139
+ return data[select]
140
+
141
+
142
+ def oml_plot_rssi(data, title, separated=False):
143
+ """Plot rssi for all channels.
144
+
145
+ :param data: numpy array returned by oml_read
146
+ :param title: Subplots title base
147
+ :param separated: plots separated on different windows
148
+ """
149
+
150
+ channels = list_channels(data)
151
+ nbplots = len(channels)
152
+ meas = MEASURES_D["rssi"]
153
+
154
+ # Only window for all
155
+ if not separated:
156
+ plt.figure()
157
+
158
+ for num, channel in enumerate(channels, start=1):
159
+ # Select data for channel
160
+ cdata = with_channel(data, channel)
161
+ _title = f"{title} Channel {channel}"
162
+
163
+ # One window per plot
164
+ if separated:
165
+ plt.figure()
166
+
167
+ plt.subplot(nbplots, 1, num)
168
+ common.plot(cdata, _title, meas.name, meas.label)
169
+
170
+
171
+ def main(args=None):
172
+ """iotlab-plot radio command"""
173
+ args = args or sys.argv[1:]
174
+
175
+ opts = PARSER.parse_args(args)
176
+ # default to plot all
177
+ selection = opts.plot or (_JOINED)
178
+ # select samples
179
+ data = opts.data[opts.begin : opts.end]
180
+ radio_plot(data, opts.title, selection)
181
+
182
+
183
+ if __name__ == "__main__":
184
+ main()
@@ -0,0 +1,22 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ # This file is a part of IoT-LAB oml-plot-tools
4
+ # Copyright (C) 2015 INRIA (Contact: admin@iot-lab.info)
5
+ # Contributor(s) : see AUTHORS file
6
+ #
7
+ # This software is governed by the CeCILL license under French law
8
+ # and abiding by the rules of distribution of free software. You can use,
9
+ # modify and/ or redistribute the software under the terms of the CeCILL
10
+ # license as circulated by CEA, CNRS and INRIA at the following URL
11
+ # http://www.cecill.info.
12
+ #
13
+ # As a counterpart to the access to the source code and rights to copy,
14
+ # modify and redistribute granted by the license, users are provided only
15
+ # with a limited warranty and the software's author, the holder of the
16
+ # economic rights, and the successive licensors have only limited
17
+ # liability.
18
+ #
19
+ # The fact that you are presently reading this means that you have had
20
+ # knowledge of the CeCILL license and that you accept its terms.
21
+
22
+ """oml_plot_tools tests"""