Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/tools/detector/plotFlows.py
169673 views
1
#!/usr/bin/env python
2
# Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
# Copyright (C) 2007-2025 German Aerospace Center (DLR) and others.
4
# This program and the accompanying materials are made available under the
5
# terms of the Eclipse Public License 2.0 which is available at
6
# https://www.eclipse.org/legal/epl-2.0/
7
# This Source Code may also be made available under the following Secondary
8
# Licenses when the conditions for such availability set forth in the Eclipse
9
# Public License 2.0 are satisfied: GNU General Public License, version 2
10
# or later which is available at
11
# https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12
# SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13
14
# @file plotFlows.py
15
# @author Jakob Erdmann
16
# @author Mirko Barthauer
17
# @date 2017-12-01
18
19
from __future__ import absolute_import
20
from __future__ import print_function
21
import math
22
import sys
23
import os
24
25
import matplotlib.pyplot as plt
26
27
import detector
28
29
SUMO_HOME = os.environ.get('SUMO_HOME',
30
os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', '..'))
31
sys.path.append(os.path.join(SUMO_HOME, 'tools'))
32
import sumolib # noqa
33
34
35
def get_options(args=None):
36
parser = sumolib.options.ArgumentParser()
37
parser.add_argument("-d", "--detector-file", dest="detfile", category="input", type=parser.additional_file,
38
help="read detectors from FILE (mandatory)", metavar="FILE")
39
parser.add_argument("--flow-column", dest="flowcol", default="qPKW", type=str,
40
help="which column contains flows", metavar="STRING")
41
parser.add_argument("-z", "--respect-zero", action="store_true", dest="respectzero",
42
default=False, help="respect detectors without data (or with permanent zero) with zero flow")
43
parser.add_argument("-i", "--interval", type=parser.time,
44
default=60, help="aggregation interval in minutes")
45
parser.add_argument("--long-names", action="store_true", dest="longnames",
46
default=False, help="do not use abbreviated names for detector groups")
47
parser.add_argument("--edge-names", action="store_true", dest="edgenames",
48
default=False, help="include detector group edge name in output")
49
parser.add_argument("-b", "--begin", type=parser.time, default=0, help="begin time in minutes")
50
parser.add_argument("-e", "--end", type=parser.time, default=None, help="end time in minutes")
51
parser.add_argument("-o", "--csv-output", dest="csv_output", type=str,
52
help="write plot data with prefix", category="output", metavar="FILE")
53
parser.add_argument("--extension", help="extension for saving plots", default="png", type=str, category="output")
54
parser.add_argument("-s", "--show", action="store_true", default=False, help="show plot directly")
55
parser.add_argument("-g", "--group-by", dest="groupby",
56
help="group detectors (all, none, type) ", default="all", type=str)
57
parser.add_argument("-t", "--type-filter", dest="typefilter", type=str, help="only show selected types")
58
parser.add_argument("-r", "--reference-flow", dest="reference", type=parser.file,
59
help="reference flow file that should not be grouped", metavar="FILE")
60
parser.add_argument("--id-filter", dest="idfilter", type=str, help="filter detector ids")
61
parser.add_argument("--single-plot", action="store_true", dest="singleplot",
62
default=False, help="put averything in a single plot")
63
# parser.add_argument("--boxplot", action="store_true", dest="boxplot", default=False, help="boxplot")
64
parser.add_argument("-m", "--max-files", type=int, dest="maxfiles",
65
category="input", help="limit number of input files")
66
parser.add_argument("-n", "--no-legend", dest="nolegend", action="store_true",
67
default=False, help="dont draw legend")
68
parser.add_argument("-v", "--verbose", action="store_true", default=False, help="tell me what you are doing")
69
parser.add_argument("flowfiles", help="read flows from FILE(s) (mandatory)", nargs="+",
70
category="input", type=parser.file, metavar="FILE+")
71
options = parser.parse_args()
72
if options.maxfiles is not None:
73
options.flowfiles = options.flowfiles[:options.maxfiles]
74
print(options.flowfiles)
75
if not options.detfile or not options.flowfiles:
76
parser.print_help()
77
sys.exit()
78
return options
79
80
81
def write_csv(keys, data, fname):
82
with open(fname, 'w') as f:
83
f.write("#key;value\n")
84
for key, v in zip(keys, data):
85
f.write("%s;%s\n" % (key, v))
86
87
88
def initDataList(begin, end, interval):
89
return [None] * int(math.ceil((end - begin) / interval))
90
91
92
def addToDataList(data, i, val):
93
if val is not None:
94
if data[i] is None:
95
data[i] = val
96
else:
97
data[i] += val
98
99
100
def plot(options, allData, prefix="", linestyle="-"):
101
if not options.singleplot:
102
plt.figure()
103
104
labelsuffix = ""
105
if prefix != "":
106
labelsuffix = "_%s" % prefix
107
plt.ylabel("Avg. Simulation Flow %s" % prefix)
108
109
plt.xlabel("Minutes")
110
x = range(int(options.begin), int(options.end), int(options.interval))
111
# if options.boxplot:
112
# for f, data in zip(options.flowfiles, allData):
113
# label = f[-12:-4] + labelsuffix
114
# #plt.plot(x, data, label=label, linestyle=linestyle)
115
# label = label.replace(";","_")
116
# if options.csv_output is not None:
117
# write_csv(x, data, options.csv_output + label + ".csv")
118
# for f, data in zip(options.flowfiles, allData[:1]):
119
# label = f[-12:-4] + labelsuffix
120
# plt.plot(x, data, label=label, linestyle=linestyle)
121
# label = label.replace(";","_")
122
# plt.boxplot(x, allData[1:])
123
# else:
124
for f, data in zip(options.flowfiles, allData):
125
label = f[:-4] + labelsuffix
126
plt.plot(x, data, label=label, linestyle=linestyle)
127
label = label.replace(";", "_")
128
if options.csv_output is not None:
129
fname = options.csv_output
130
if len(options.flowfiles) > 1:
131
lastdir = os.path.basename(os.path.dirname(f))
132
fname = "%s_%s.%s.csv" % (options.csv_output, label, lastdir)
133
write_csv(x, data, fname)
134
if not options.nolegend:
135
plt.legend(loc='best')
136
if not options.singleplot:
137
plt.savefig(label + "." + options.extension)
138
139
140
def main(options):
141
detReaders = [detector.DetectorReader(options.detfile, detector.LaneMap()) for f in options.flowfiles]
142
for f in options.flowfiles:
143
options.begin, options.end = detReaders[0].findTimes(f, options.begin, options.end)
144
if options.verbose:
145
print("begin=%s, end=%s" % (options.begin, options.end))
146
for detReader, f in zip(detReaders, options.flowfiles):
147
if options.verbose:
148
print("reading %s" % f)
149
detReader.clearFlows(options.begin, options.interval) # initialize
150
detReader.readFlowsTimeline(f, options.interval, begin=options.begin, end=options.end, flowCol=options.flowcol)
151
# aggregated detectors
152
if options.singleplot:
153
plt.figure(figsize=(14, 9), dpi=100)
154
if options.groupby == "all":
155
allData = [] # one list for each file
156
for detReader, f in zip(detReaders, options.flowfiles):
157
data = initDataList(options.begin, options.end, options.interval)
158
for edge, group in detReader.getGroups():
159
if options.idfilter is not None and options.idfilter not in group.ids[0]:
160
continue
161
assert len(group.timeline) <= len(data)
162
for i, (flow, speed) in enumerate(group.timeline):
163
addToDataList(data, i, flow)
164
allData.append(data)
165
plot(options, allData)
166
167
elif options.groupby == "type":
168
for detType, linestyle in [("source", "-"), ("sink", ":"), ("between", "--")]:
169
allData = [] # one list for each file
170
for detReader, f in zip(detReaders, options.flowfiles):
171
data = initDataList(options.begin, options.end, options.interval)
172
for edge, group in detReader.getGroups():
173
if options.idfilter is not None and options.idfilter not in group.ids[0]:
174
continue
175
assert len(group.timeline) <= len(data)
176
if group.type == detType:
177
for i, (flow, speed) in enumerate(group.timeline):
178
addToDataList(data, i, flow)
179
allData.append(data)
180
plot(options, allData, detType, linestyle)
181
182
elif options.groupby == "none":
183
for det, groupName in [(g.ids[0], g.getName(options.longnames, None)) for e, g in detReaders[0].getGroups()]:
184
allData = [] # one list for each file
185
for detReader, f in zip(detReaders, options.flowfiles):
186
data = initDataList(options.begin, options.end, options.interval)
187
group = detReader.getGroup(det)
188
if options.typefilter is not None and group.type != options.typefilter:
189
continue
190
if options.idfilter is not None and options.idfilter not in group.ids[0]:
191
continue
192
assert len(group.timeline) <= len(data)
193
for i, (flow, speed) in enumerate(group.timeline):
194
addToDataList(data, i, flow)
195
allData.append(data)
196
plot(options, allData, "%s_%s" % (groupName, group.type))
197
198
else:
199
raise RuntimeError("group-by '%s' not supported" % options.groupby)
200
201
if options.singleplot:
202
plt.savefig("singlePlot." + options.extension)
203
if options.show:
204
plt.show()
205
206
207
if __name__ == "__main__":
208
main(get_options())
209
210