コード例 #1
0
class GraphBuilder(object):
    """
    Build a graph of the tube network to export to GEXF format.
    """

    def __init__(self, station_list):
        """
        Intilise object.
        """
        self.journey_time_matrix = []
        self.my_station_list = station_list

    def build_full_graph(self):
        """
        For each pair of stations in the supplied list, create a
        Journey object and save the journey times in a list.
        Arguments:
        - `station_list`: the list of stations created by load_stations().
        """
        from Journey import Journey
        for i in range(len(self.my_station_list.get_list())):
            self.journey_time_matrix.append([])
            for j in range(len(self.my_station_list.get_list())):
                if i != j:
                    print "Journey:",\
                        self.my_station_list.get_list()[i][1].get_name(), \
                        "to",\
                        self.my_station_list.get_list()[j][1].get_name()

                    self.this_journey = Journey(self.my_station_list.get_list()[i][1],\
                                                    self.my_station_list.get_list()[j][1],\
                                                    "20130801",\
                                                    "0800")
                    self.this_journey.read_api()
                    self.journey_time_matrix[i].append(\
                        self.this_journey.get_journey_time())
                    self.this_journey.cleanup_files()
                else:
                    self.journey_time_matrix[i].append(0)

    def build_full_no_change_graph(self):
        """
        For each pair of stations in the supplied list, create a
        Journey object and save the journey times in a list.
        Arguments:
        - `station_list`: the list of stations created by load_stations().
        """
        from Journey import Journey
        for i in range(len(self.my_station_list.get_list())):
            self.journey_time_matrix.append([])
            for j in range(len(self.my_station_list.get_list())):
                if i != j:
                    print "Journey:",\
                        self.my_station_list.get_list()[i][1].get_name(), \
                        "to",\
                        self.my_station_list.get_list()[j][1].get_name()

                    self.this_journey = Journey(self.my_station_list.get_list()[i][1],\
                                                    self.my_station_list.get_list()[j][1],\
                                                    "20130801",\
                                                    "0800")
                    self.this_journey.read_api()
                    self.journey_time_matrix[i].append(\
                        self.this_journey.get_no_change_journey_time())
                    self.this_journey.cleanup_files()
                else:
                    self.journey_time_matrix[i].append(0)

    def build_part_graph(self):
        """
        Start from what has already been put into xml file and
        continue, writing to the xml file after each journey.
        This allows getting the full graph (eventually) despite SSH
        timeout and broken pipes etc.
        """
        from Journey import Journey
        import xml.etree.ElementTree as ET

        self.my_tree = ET.parse('TubeJourneyTimesGraph.gexf')
        self.my_gexf = self.my_tree.getroot()
        self.my_meta = self.my_gexf.find('{https://www.gexf.net/1.2draft}meta')
        self.my_graph = self.my_gexf.find('{https://www.gexf.net/1.2draft}graph')
        self.my_nodes = self.my_graph.find('{https://www.gexf.net/1.2draft}nodes')
        self.my_edges = self.my_graph.find('{https://www.gexf.net/1.2draft}edges')

        self.id_list = []
        for edge in self.my_edges:
            self.id_list.append(int(edge.get('id')))

        if len(self.id_list) != 0:
            self.max_id = self.id_list.pop()
        else:
            self.max_id = 0
            self.journey_time_matrix.append([])
            self.add_xml_node(0)

        self.i_start = self.max_id / len(self.my_station_list.get_list())
        self.j_start = self.max_id % len(self.my_station_list.get_list())

        for cols in range(self.i_start+1):
            self.journey_time_matrix.append([])
            for rows in range(self.j_start+1):
                self.journey_time_matrix[cols].append([])

        # finish current origin:
        for j in range(self.j_start+1, len(self.my_station_list.get_list())):
            if (self.i_start != j)\
                    and not(self.i_start==94 and j==95) and not(self.i_start==95 and j==94)\
                    and not(self.i_start==102 and j==103) and not(self.i_start==103 and j==102)\
                    and not(self.i_start==102 and j==104) and not(self.i_start==104 and j==102)\
                    and not(self.i_start==103 and j==104) and not(self.i_start==104 and j==103)\
                    and not(self.i_start==171 and j==172) and not(self.i_start==172 and j==171)\
                    and not(self.i_start==198 and j==199) and not(self.i_start==199 and j==198):
                print "Journey:",\
                    self.my_station_list.get_list()[self.i_start][1].get_name(), \
                    "to",\
                    self.my_station_list.get_list()[j][1].get_name()

                self.this_journey = Journey(self.my_station_list\
                                                .get_list()[self.i_start][1],\
                                                self.my_station_list\
                                                .get_list()[j][1],\
                                                "20130801",\
                                                "0800")
                self.this_journey.read_api()
                self.journey_time_matrix[self.i_start].append(\
                    self.this_journey.get_no_change_journey_time())
                self.this_journey.cleanup_files()

            else:
                self.journey_time_matrix[self.i_start].append(0)

            if self.journey_time_matrix[self.i_start][j] != 0:
                self.add_xml_edge(self.i_start,j)

        # then do the rest:
        for i in range(self.i_start + 1, len(self.my_station_list.get_list())):
            self.journey_time_matrix.append([])
            self.add_xml_node(i)
            for j in range(len(self.my_station_list.get_list())):
                if (i != j)\
                        and not(i==94 and j==95) and not(i==95 and j==94)\
                        and not(i==102 and j==103) and not(i==103 and j==102)\
                        and not(i==102 and j==104) and not(i==104 and j==103)\
                        and not(i==103 and j==104) and not(i==104 and j==103)\
                        and not(i==171 and j==172) and not(i==172 and j==171)\
                        and not(i==198 and j==199) and not(i==199 and j==198):
                    print "Journey:",\
                        self.my_station_list.get_list()[i][1].get_name(), \
                        "to",\
                        self.my_station_list.get_list()[j][1].get_name()

                    self.this_journey = Journey(self.my_station_list\
                                                    .get_list()[i][1],\
                                                    self.my_station_list\
                                                    .get_list()[j][1],\
                                                    "20130801",\
                                                    "0800")
                    self.this_journey.read_api()
                    self.journey_time_matrix[i].append(\
                        self.this_journey.get_no_change_journey_time())
                    self.this_journey.cleanup_files()

                else:
                    self.journey_time_matrix[i].append(0)

                if self.journey_time_matrix[i][j] != 0:
                    self.add_xml_edge(i,j)


    def export_to_gexf(self):
        """
        Export the generated graph to GEXF format used by gephi.
        """
        import time
        import subprocess
        import xml.etree.ElementTree as ET

        self.begin_xml_file()

        for i in range(len(self.journey_time_matrix)):
            self.new_node = ET.Element('node', {'id': str(i),\
                                                    'label':\
                                                    self.my_station_list\
                                                    .get_station(i)})
            self.my_atts = ET.Element('attvalues')
            self.my_stn_lat = ET.Element('attvalue', {'for': 'latitude',\
                                                      'value':\
                                                      str(self.my_station_list\
                                                              .fetch_station_id(i)\
                                                              .get_lat_long()[0])})
            self.my_stn_long = ET.Element('attvalue', {'for': 'longitude',\
                                                           'value':\
                                                           str(self.my_station_list\
                                                                   .fetch_station_id(i)\
                                                                   .get_lat_long()[1])})
            self.my_atts.append(self.my_stn_lat)
            self.my_atts.append(self.my_stn_long)
            self.new_node.append(self.my_atts)
            self.my_nodes.append(self.new_node)
            for j in range(len(self.journey_time_matrix)):
                if self.journey_time_matrix[i][j] != 0:
                    self.edge_id = str((i * len(self.journey_time_matrix)) + j)
                    self.new_edge = ET.Element('edge', {'id': self.edge_id,\
                                                            'source': str(i),\
                                                            'target': str(j),\
                                                            'weight':\
                                                            str(round(self.journey_time_matrix[i][j],1))})
                    self.my_edges.append(self.new_edge)

        self.my_tree.write('TubeJourneyTimesGraph.gexf')


    def begin_xml_file(self):
        """
        Create a new xml file and the appropriate meta data.
        Does not need to be called every time the program is
        run - only if there is no starting tree.
        """
        import time
        import subprocess
        import xml.etree.ElementTree as ET

        subprocess.call(['touch', 'TubeJourneyTimesGraph.gexf'])

        self.my_gexf = ET.Element('gexf',\
                                      {'xmlns': 'https://www.gexf.net/1.2draft',\
                                           'xmlns:xsi':\
                                           'http://www.w3.org/2001/XMLSchema-instance',\
                                           'xsi:schemaLocation': \
                                           'http://www.gexf.net/1.2draft \n \http://www.gexf.net/1.2draft/gexf.xsd',\
                                           'version': '1.2'})
        self.my_tree = ET.ElementTree(self.my_gexf)

        self.my_meta = ET.Element('meta', {'lastmodifieddate': time.strftime('%Y-%m-%d')})
        self.my_creator = ET.Element('creator')
        self.my_creator.text = "Andy Holt"
        self.my_description = ET.Element('description')
        self.my_description.text = "Graph of tube network"
        self.my_meta.append(self.my_creator)
        self.my_meta.append(self.my_description)
        self.my_gexf.append(self.my_meta)

        self.my_graph = ET.Element('graph', {'defaultedgetype': 'directed'})
        self.my_gexf.append(self.my_graph)

        self.my_attributes = ET.Element('attributes', {'class': 'node'})
        self.my_lat = ET.Element('attribute',\
                                     {'id': 'latitutde', 'title': 'latitude', 'type':'double'})
        self.my_long = ET.Element('attribute',\
                                      {'id': 'longitude', 'title': 'longitude', 'type':'double'})
        self.my_attributes.append(self.my_lat)
        self.my_attributes.append(self.my_long)
        self.my_graph.append(self.my_attributes)

        self.my_nodes = ET.Element('nodes')
        self.my_graph.append(self.my_nodes)

        self.my_edges = ET.Element('edges')
        self.my_graph.append(self.my_edges)

        self.my_tree.write('TubeJourneyTimesGraph.gexf')


    def add_xml_node(self, i):
        """
        Add a new station to the xml file and store.
        """
        import xml.etree.ElementTree as ET
        self.new_node = ET.Element('node', {'id': str(i),\
                                                'label':\
                                                self.my_station_list.get_station(i)})
        self.my_atts = ET.Element('attvalues')
        self.my_stn_lat = ET.Element('attvalue', {'for': 'latitude',\
                                                      'value':\
                                                      str(self.my_station_list.fetch_station_id(i)\
                                                              .get_lat_long()[0])})
        self.my_stn_long = ET.Element('attvalue', {'for': 'longitude',\
                                                       'value':\
                                                       str(self.my_station_list.fetch_station_id(i)\
                                                               .get_lat_long()[1])})
        self.my_atts.append(self.my_stn_lat)
        self.my_atts.append(self.my_stn_long)
        self.new_node.append(self.my_atts)
        self.my_nodes.append(self.new_node)

        self.my_tree.write('TubeJourneyTimesGraph.gexf')

    def add_xml_edge(self, i, j):
        """
        Add a new journey to the xml file and store.
        """
        import xml.etree.ElementTree as ET

        self.edge_id = str((i * len(self.my_station_list.get_list())) + j)
        self.new_edge = ET.Element('edge', {'id': self.edge_id,\
                                                'source': str(i),\
                                                'target': str(j),\
                                                'weight': str(round(self.journey_time_matrix[i][j],1))})
        self.my_edges.append(self.new_edge)

        self.my_tree.write('TubeJourneyTimesGraph.gexf')