Welcome to CityFlow’s documentation!¶
Introduction¶
CityFlow is a multi-agent reinforcement learning environment for large scale city traffic scenario.
Checkout these features!
- a microscopic traffic simulator which simulates the behavior of each vehicle, providing highest level detail of traffic evolution.
- support flexible definitions for road network and traffic flow
- provides friendly python interface for reinforcement learning
- Fast! Elaborately designed data structure and simulation algorithm with multithreading. Capable of simulating city-wide traffic. See the performance comparison with SUMO [2].

Performance comparison between CityFlow with different number of threads (1, 2, 4, 8) and SUMO. From small 1x1 grid roadnet to city-level 30x30 roadnet. Even faster when you need to interact with the simulator through python API.
See Quick Start to get started.
[1] | WWW 2019 Demo Paper |
[2] | SUMO home page |
Installation Guide¶
Docker¶
The easiest way to use CityFlow is via docker.
docker pull cityflowproject/cityflow:latest
This will create docker image cityflow:latest
.
docker run -it cityflowproject/cityflow:latest
Create and start a container, CityFlow is out-of-the-box along with miniconda with python3.6.
import cityflow
eng = cityflow.Engine
Build From Source¶
If you want to get nightly version of CityFlow or running on native system, you can build CityFlow from source. Currently, we only support building on Unix systems. This guide is based on Ubuntu 16.04.
CityFlow has little dependencies, so building from source is not scary.
- Check that you have python 3 installed. Other version of python might work, however, we only tested on python with version >= 3.5.
- Install cpp dependencies
sudo apt update && sudo apt install -y build-essential cmake
- Clone CityFlow project from github.
git clone https://github.com/cityflow-project/CityFlow.git
- Go to CityFlow project’s root directory and run
pip install .
- Wait for installation to complete and CityFlow should be successfully installed.
import cityflow
eng = cityflow.Engine
For Windows Users¶
For Windows users, it is recommended to run CityFlow under Windows Subsystem for Linux (WSL) or use docker.
Quick Start¶
Installation¶
If you have not installed CityFlow yet, Installation Guide is a simple guide for installation.
Create Engine¶
import cityflow
eng = cityflow.Engine(config_path, thread_num=1)
config_path
: path for config file.thread_num
: number of threads.
Arguments In Config File¶
interval
: time of each simulation step (in seconds). Aninterval
of 0.5 means for each simulation step, the system will move 0.5 seconds forward. For example, if a car is at location 0 with speed 10m/s, after one simulation step, it will move to location 10*0.5=5.seed
: random seed.dir
: root directory, all file path will be relative to this directory.roadnetFile
: path for roadnet file.flowFile
: path for flow file.rlTrafficLight
: whether to enable traffic light control through python API. If set tofalse
, default traffic light plan defined inroadnetFile
will be used.saveReplay
: whether to save simulation for replay. If set totrue
,roadnetLogFile
andreplayLogFile
are required.roadnetLogFile
: path for roadnet replay file. This is a special roadnet file for replay, not the same asroadnetFile
.replayLogFile
: path for replay. This file contains vehicle positions and traffic light situation of each simulation step.laneChange
: whether to enable lane changing. The default value is ‘false’.
For format of roadnetFile
and flowFile
, please see Roadnet File Format, Flow File Format
Note
Runnable sample roadnet and flow files can be found in examples
folder.
You can generate grid roadnet and flow files using tools/generate_grid_scenario.py
For example, you can generate a 2x3 roadnet with predefined traffic light plan and a corresponding flow file with
python generate_grid_scenario.py 2 3 --roadnetFile roadnet.json --flowFile flow.json --dir . --tlPlan
Sample Config File¶
Note
Runnable sample config files can be found in examples
folder.
{
"interval": 1.0,
"seed": 0,
"dir": "data/",
"roadnetFile": "roadnet/testcase_roadnet_3x3.json",
"flowFile": "flow/testcase_flow_3x3.json",
"rlTrafficLight": false,
"saveReplay": true,
"roadnetLogFile": "frontend/web/testcase_roadnet_3x3.json",
"replayLogFile": "frontend/web/testcase_replay_3x3.txt"
}
Data Access API¶
get_vehicle_count()
:
- Get number of total running vehicles.
- Return an
int
get_vehicles(include_waiting=False)
:
- Get all vehicle ids
- Include vehicles in lane’s waiting buffer if
include_waiting=True
- Return an
list
of vehicle ids
get_lane_vehicle_count()
:
- Get number of running vehicles on each lane.
- Return a
dict
with lane id as key and corresponding number as value.
get_lane_waiting_vehicle_count()
:
- Get number of waiting vehicles on each lane. Currently, vehicles with speed less than 0.1m/s is considered as waiting.
- Return a
dict
with lane id as key and corresponding number as value.
get_lane_vehicles()
:
- Get vehicle ids on each lane.
- Return a
dict
with lane id as key and list of vehicle id as value.
get_vehicle_info(vehicle_id)
:
Return a
dict
which contains information of the given vehicle.The items include:
running
: whether the vehicle is running.If the vehicle is running:
speed
: The speed of the vehicle.distance
: The distance the vehicle has travelled on the current lane or lanelink.drivable
: The id of the current drivable(lane or lanelink)road
: The id of the current road if the vehicle is running on a lane.intersection
: The next intersection if the vehicle is running on a lane.route
: A string contains ids of following roads in the vehicle’s route which are separated by' '
.
Note that all items are stored as
str
.
get_vehicle_speed()
:
- Get speed of each vehicle
- Return a
dict
with vehicle id as key and corresponding speed as value.
get_vehicle_distance()
:
- Get distance travelled on current lane of each vehicle.
- Return a
dict
with vehicle id as key and corresponding distance as value.
get_leader(vehicle_id)
- Return the id of the vehicle in front of
vehicle_id
. - Return an empty string
""
whenvehicle_id
does not have a leader
get_current_time()
:
- Get simulation time (in seconds)
- Return a
double
get_average_travel_time()
:
- Get average travel time (in seconds)
- Return a
double
Control API¶
set_tl_phase(intersection_id, phase_id)
:
- Set the phase of traffic light of
intersection_id
tophase_id
. Only works whenrlTrafficLight
is set totrue
. - The
intersection_id
should be defined inroadnetFile
phase_id
is the index of phase in array"lightphases"
, defined inroadnetFile
.
set_vehicle_speed(vehicle_id, speed)
:
- Set the speed of
vehicle_id
tospeed
. - The vehicles have to obey fundamental rules to avoid collisions so the real speed might be different from
speed
.
reset(seed=False)
:
- Reset the simulation (clear all vehicles and set simulation time back to zero)
- Reset random seed if
seed
is set toTrue
- This does not clear old replays, instead, it appends new replays to
replayLogFile
.
snapshot()
:
- Take a snapshot of current simulation state
- This will generate an
Archive
object which can be loaded later - You can save an
Archive
object to a file using itsdump
method.
load(archive)
:
- Load an
Archive
object and restore simulation state
load_from_file(path)
Load a snapshot file created by
dump
method and restore simulation state.The whole process of saving and loading file is like:
archive = eng.snapshot() # create an archive object archive.dump("save.json") # if you want to save the snapshot to a file # do something eng.load(archive) # load 'archive' and the simulation will start from the status when 'archive'is created # or if you want to load from 'save.json' eng.load_from_file("save.json")
set_random_seed(seed)
:
- Set seed of random generator to
seed
set_vehicle_route(vehicle_id, route)
:
- To change the route of a vehicle during its travelling.
- route is a list of road ids (doesn’t include the current road)
- Return true if the route is available and can be connected.
Other API¶
set_replay_file(replay_file)
:
replay_file
should be a path related todir
in config file- Set
replayLogFile
toreplay_file
, newly generated replays will be output intoreplay_file
- This is useful when you want to look at a specific episode for debugging purposes
- This API works only when
saveReplay
istrue
in config json
set_save_replay(open)
:
- Open or close replay saving
- Set
open
to False to stop replay saving - Set
open
to True to start replay saving - This API works only when
saveReplay
istrue
in config json
Roadnet File Format¶
Roadnet file defines the roadnet structure. CityFlow’s roadnet mainly consists of intersections and roads (see them as nodes and edges of a graph).
- Road represents a directional road from one intersection to another intersection with road-specific properties. A road may contain multiple lanes.
- Intersection is where roads intersects. An intersection contains several roadlinks. Each roadlink connects two roads of the intersection and can be controlled by traffic signals.
- A roadlink may contain several lanelinks. Each lanelink represents a specific path from one lane of incoming road to one lane of outgoing road.
Now let’s see a sample roadnet file and we’ll explain the meaning of each components. Relax, the definition of field is quite straight forward, if you are familiar with modern road networks. For the following json file, []
means this field is an array, but we will only show one object for demonstration.
Note
Runnable sample roadnet files can be found in examples
folder.
Sample roadnet.json
with explanation.
{
"intersections": [
{
// id of the intersection
"id": "intersection_1_0",
// coordinate of center of intersection
"point": {
"x": 0,
"y": 0
},
// width of the intersection
"width": 10,
// roads connected to the intersection
"roads": [
"road_1",
"road_2"
],
// roadLinks of the intersection
"roadLinks": [
{
// 'turn_left', 'turn_right', 'go_straight'
"type": "go_straight",
// id of starting road
"startRoad": "road_1",
// id of ending road
"endRoad": "road_2",
// lanelinks of roadlink
"laneLinks": [
{
// from startRoad's startLaneIndex lane to endRoad's endLaneIndex lane
"startLaneIndex": 0,
"endLaneIndex": 1,
// points along the laneLink which describe the shape of laneLink
"points": [
{
"x": -10,
"y": 2
},
{
"x": 10,
"y": -2
}
]
}
]
}
],
// traffic light plan of the intersection
"trafficLight": {
"lightphases": [
{
// default duration of the phase
"time": 30,
// available roadLinks of current phase, index is the no. of roadlinks defined above.
"availableRoadLinks": [
0,
2
]
}
]
},
// true if it's a peripheral intersection (if it only connects to one road)
"virtual": false
}
],
"roads": [
{
// id of road
"id": "road_1",
// id of start intersection
"startIntersection": "intersection_1",
// id of end intersection
"endIntersection": "intersection_2",
// points along the road which describe the shape of the road
"points": [
{
"x": -200,
"y": 0
},
{
"x": 0,
"y": 0
}
],
// property of each lane
"lanes": [
{
"width": 4,
"maxSpeed": 16.67
}
]
}
]
}

Illustration of a 1x2 grid roadnet.
You can convert SUMO roadnet files into CityFlow format using tools/Converter/converter.py
For example, the following code converts a sumo roadnet file, atlanta.net.xml, to CityFlow format.
python converter.py --sumonet atlanta_sumo.net.xml --cityflownet atlanta_cityflow.json
Flow File Format¶
Flow file defines the traffic flow. Each flow contains following field:
vehicle
: defines the parameter of vehicle.- length: length of the vehicle
- width: width of the vehicle
- maxPosAcc: maximum acceleration (in m/s)
- maxNegAcc: maximum deceleration (in m/s)
- usualPosAcc: usual acceleration (in m/s)
- usualNegAcc: usual deceleration (in m/s)
- minGap: minimum acceptable gap with leading vehicle (in meter)
- maxSpeed: maximum cruising speed (in m/s)
- headwayTime: desired headway time (in seconds) with leading vehicle, keep current speed * headwayTime gap.
route
: defines the route, all vehicles of this flow will follow the route. Specify the source and the destination, optionally some anchor points and the router will connect them with shortest paths automatically.interval
: defines the interval of consecutive vehicles (in seconds). If the interval is too small, vehicles may not be able to enter the road due to blockage, it will be held and let go once there are enough space.startTime
,endTime
: Flow will generate vehicles between time [startTime, endTime] (in seconds), includingstartTime
andendTime
.
Note
Runnable sample flow files can be found in examples
folder.
Replay¶
Start¶
- enter the
frontend
folder and openindex.html
in your browser. - choose the roadnet log file (as defined by
roadnetLogFile
field in the config file, not ‘roadnetFile’) and wait for it to be loaded. When it has finished loading, there will be a message shown in the info box. - choose the replay file (as defined by
replayLogFile
field in the config file) . - choose the chart data file (optional, see section Chart below).
- press
Start
button to start the replay.
Control¶
- Use the mouse to navigate. Dragging and mouse wheel zooming are supported.
- Move the slider in Control Box to adjust the replay speed. You can also press
1
on keyboard to slow down or2
to speed up. - Press
Pause
button in Control Box to pause/resume. You can also double-click on the map to pause and resume. - Press
[
or]
on keyboard to take a step backward or forward. - To restart the replay, just press
Start
button again. - The
debug
option enables displaying the ID of vehicles, roads and intersections during a mouse hover. This will cause a slower replaying, so we suggest using it only for debugging purposes.
Chart¶
The player supports showing the change of different metrics in a chart simultaneously with the replay process.
To provide required data, a log file in a format as shown below is needed:
The first line is the title of the chart.
Each row stands for a time step and each column stands for a specific metric. For example, to track vehicle numbers of three crossroads respectively, we need three columns and each column stands for the vehicle number of a certain crossroads.
In one row, numbers are separated by one or more spaces or tabs.
The numbers in one column will be shown as points connected by one line in the chart.
Note
Make sure that each row is corresponding with the right time step.
Notes¶
- To get the example replay files, run
download_replay.py
underfrontend
folder. - If you create a new Engine object with same
replayLogFile
, it will clear the old replay file first - Using
eng.reset()
won’t clear old replays, it will append newly generated replay to the end ofreplayLogFile
- You can change
replayLogFile
during runtime usingset_replay_file
, see set-replay-file