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