def __add__(self, other): # combine two changesets self.new_links = {**self.new_links, **other.new_links} self.new_nodes = {**self.new_nodes, **other.new_nodes} self.df_route_data = self.df_route_data.append(other.df_route_data) self.additional_links_modes = dict_support.merge_complex_dictionaries( self.additional_links_modes, other.additional_links_modes) self.new_stops = dict_support.merge_complex_dictionaries( self.new_stops, other.new_stops) self.new_pt_edges = dict_support.combine_edge_data_lists( self.new_pt_edges, other.new_pt_edges) return self
def test_merging_dictionaries_with_nested_lists(): return_d = dict_support.merge_complex_dictionaries( { 'a': 1, 'b': { 'a': [3, 6] }, 'c': { 'b': [1] } }, { 'b': { 'a': [5] }, 'c': { 'b': [8, 90] } }) assert_semantically_equal(return_d, { 'a': 1, 'b': { 'a': [3, 6, 5] }, 'c': { 'b': [8, 90, 1] } })
def test_merging_nested_dictionaries(): return_d = dict_support.merge_complex_dictionaries( { 'a': 1, 'b': { 3: 5 }, 'c': { 1: 4 } }, { 'b': { 5: 3 }, 'c': { 8: 90 } }) assert_semantically_equal(return_d, { 'a': 1, 'b': { 3: 5, 5: 3 }, 'c': { 1: 4, 8: 90 } })
def test_merging_dictionaries_with_nested_sets(): return_d = dict_support.merge_complex_dictionaries( { 'a': 1, 'b': { 'a': {3, 6} }, 'c': { 'b': {1} } }, { 'b': { 'a': {5} }, 'c': { 'b': {8, 90} } }) assert_semantically_equal(return_d, { 'a': 1, 'b': { 'a': {3, 6, 5} }, 'c': { 'b': {8, 90, 1} } })
def test_merging_simple_dictionaries(): return_d = dict_support.merge_complex_dictionaries({ 'a': 1, 'b': 3 }, { 'b': 5, 'c': 8 }) assert return_d == {'a': 1, 'b': 5, 'c': 8}
def test_merging_dicts_with_lists(): d = dict_support.merge_complex_dictionaries({ '1': [''], '2': [] }, { '3': ['1'], '1': ['2'] }) assert_semantically_equal(d, {'1': ['', '2'], '2': [], '3': ['1']})
def test_merging_dicts_with_lists_with_overlapping_values_returns_list_with_unique_values( ): d = dict_support.merge_complex_dictionaries({ '1': ['2'], '2': [] }, { '3': ['1'], '1': ['2'] }) assert_semantically_equal(d, {'1': ['2'], '2': [], '3': ['1']})
def _build_graph(self, stops=None): nodes = {} edges = {} for route in self._routes.values(): g = route.graph() nodes = dict_support.merge_complex_dictionaries( dict(g.nodes(data=True)), nodes) edges = dict_support.combine_edge_data_lists( list(g.edges(data=True)), edges) service_graph = nx.DiGraph(name='Service graph') service_graph.add_nodes_from(nodes, services=[self.id]) service_graph.add_edges_from(edges, services=[self.id]) nx.set_node_attributes(service_graph, nodes) # update route graphs by the larger graph self._update_graph(service_graph) return service_graph
def _build_graph(self, stops=None): nodes = {} edges = {} for service_id, service in self.services.items(): g = service.graph() nodes = dict_support.merge_complex_dictionaries( dict(g.nodes(data=True)), nodes) edges = dict_support.combine_edge_data_lists( list(g.edges(data=True)), edges) # TODO check for clashing stop ids overwriting data schedule_graph = nx.DiGraph(name='Schedule graph') schedule_graph.add_nodes_from(nodes) schedule_graph.add_edges_from(edges) nx.set_node_attributes(schedule_graph, nodes) # update service and route graphs by the larger graph self._update_graph(schedule_graph) return schedule_graph
def read_schedule(schedule_path, epsg): """ Read MATSim schedule :param schedule_path: path to the schedule.xml file :param epsg: 'epsg:12345' :return: list of Service objects """ services = [] transformer = Transformer.from_proj(Proj(epsg), Proj('epsg:4326'), always_xy=True) def write_transitLinesTransitRoute(transitLine, transitRoutes, transportMode): mode = transportMode['transportMode'] service_id = transitLine['transitLine']['id'] service_routes = [] for transitRoute, transitRoute_val in transitRoutes.items(): stops = [ Stop(s['stop']['refId'], x=transit_stop_id_mapping[s['stop']['refId']]['x'], y=transit_stop_id_mapping[s['stop']['refId']]['y'], epsg=epsg, transformer=transformer) for s in transitRoute_val['stops'] ] for s in stops: s.add_additional_attributes(transit_stop_id_mapping[s.id]) arrival_offsets = [] departure_offsets = [] await_departure = [] for stop in transitRoute_val['stops']: if 'departureOffset' not in stop[ 'stop'] and 'arrivalOffset' not in stop['stop']: pass elif 'departureOffset' not in stop['stop']: arrival_offsets.append(stop['stop']['arrivalOffset']) departure_offsets.append(stop['stop']['arrivalOffset']) elif 'arrivalOffset' not in stop['stop']: arrival_offsets.append(stop['stop']['departureOffset']) departure_offsets.append(stop['stop']['departureOffset']) else: arrival_offsets.append(stop['stop']['arrivalOffset']) departure_offsets.append(stop['stop']['departureOffset']) if 'awaitDeparture' in stop['stop']: await_departure.append( str(stop['stop']['awaitDeparture']).lower() in ['true', '1']) route = [ r_val['link']['refId'] for r_val in transitRoute_val['links'] ] trips = { 'trip_id': [], 'trip_departure_time': [], 'vehicle_id': [] } for dep in transitRoute_val['departure_list']: trips['trip_id'].append(dep['departure']['id']) trips['trip_departure_time'].append( dep['departure']['departureTime']) trips['vehicle_id'].append(dep['departure']['vehicleRefId']) r = Route(route_short_name=transitLine['transitLine']['name'], mode=mode, stops=stops, route=route, trips=trips, arrival_offsets=arrival_offsets, departure_offsets=departure_offsets, id=transitRoute, await_departure=await_departure) service_routes.append(r) services.append(Service(id=service_id, routes=service_routes)) transitLine = {} transitRoutes = {} transportMode = {} transit_stop_id_mapping = {} is_minimalTransferTimes = False minimalTransferTimes = { } # {'stop_id_1': {'stop_id_2': 0.0}} seconds_to_transfer between stop_id_1 and stop_id_2 # transitLines for event, elem in ET.iterparse(schedule_path, events=('start', 'end')): if event == 'start': if elem.tag == 'stopFacility': attribs = elem.attrib attribs['epsg'] = epsg attribs['x'] = float(attribs['x']) attribs['y'] = float(attribs['y']) if attribs['id'] not in transit_stop_id_mapping: transit_stop_id_mapping[attribs['id']] = attribs if elem.tag == 'minimalTransferTimes': is_minimalTransferTimes = not is_minimalTransferTimes if elem.tag == 'relation': if is_minimalTransferTimes: attribs = elem.attrib minimalTransferTimes = dict_support.merge_complex_dictionaries( minimalTransferTimes, { attribs['fromStop']: { attribs['toStop']: float( attribs['transferTime']) } }) if elem.tag == 'transitLine': if transitLine: write_transitLinesTransitRoute(transitLine, transitRoutes, transportMode) transitLine = {"transitLine": elem.attrib} transitRoutes = {} if elem.tag == 'transitRoute': transitRoutes[elem.attrib['id']] = { 'stops': [], 'links': [], 'departure_list': [], 'attribs': elem.attrib } transitRoute = elem.attrib['id'] # doesn't have any attribs # if elem.tag == 'routeProfile': # routeProfile = {'routeProfile': elem.attrib} if elem.tag == 'stop': transitRoutes[transitRoute]['stops'].append( {'stop': elem.attrib}) # doesn't have any attribs # if elem.tag == 'route': # route = {'route': elem.attrib} if elem.tag == 'link': transitRoutes[transitRoute]['links'].append( {'link': elem.attrib}) # doesn't have any attribs # if elem.tag == 'departures': # departures = {'departures': elem.attrib} if elem.tag == 'departure': transitRoutes[transitRoute]['departure_list'].append( {'departure': elem.attrib}) elif (event == 'end') and (elem.tag == "transportMode"): transportMode = {'transportMode': elem.text} # add the last one write_transitLinesTransitRoute(transitLine, transitRoutes, transportMode) return services, minimalTransferTimes, transit_stop_id_mapping
def test_merging_dicts_with_lists_when_one_dict_is_empty(): d = dict_support.merge_complex_dictionaries({'1': [''], '2': []}, {}) assert_semantically_equal(d, {'1': [''], '2': []})