Skip to content

Mode of transport

ModeOfTransport

Source code in june/groups/travel/mode_of_transport.py
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
class ModeOfTransport:
    """ """
    __all = {}
    __slots__ = "description", "is_public"

    def __new__(cls, description, is_public=False):
        if description not in ModeOfTransport.__all:
            ModeOfTransport.__all[description] = super().__new__(cls)
        return ModeOfTransport.__all[description]

    def __init__(self, description: str, is_public: bool = False):
        """
        Create a ModeOfTransport from its description.

        Only one instance of each mode of transport exists with instances being
        retrieved from the __all dictionary.

        Parameters
        ----------
        description
            e.g. "Bus, minibus or coach"
        is_public
            True if this is public transport, for example a bus.
        """
        self.description = description
        self.is_public = is_public

    @property
    def is_private(self) -> bool:
        """True if this is private transport, for example a car.

        """
        return not self.is_public

    @classmethod
    def with_description(cls, description: str) -> "ModeOfTransport":
        """Retrieve a mode of transport by its description.

        Args:
            description (str): A description, e.g. 'Bus, minibus or coach'

        Returns:
            The corresponding ModeOfTransport instance: 

        """
        return ModeOfTransport.__all[description]

    def index(self, headers: List[str]) -> int:
        """Determine the column index of this mode of transport.

        The first header that contains this mode of transport's description
        is counted.

        Args:
            headers (List[str]): A list of headers from a CSV file.

        Returns:
            The column index corresponding to this mode of transport.: 

        Raises:
            An assertion error if no such header is found.: 


        """
        for i, header in enumerate(headers):
            if self.description in header:
                return i
        raise AssertionError(f"{self} not found in headers {headers}")

    def __eq__(self, other):
        if isinstance(other, str):
            return self.description == other
        if isinstance(other, ModeOfTransport):
            return self.description == other.description
        return super().__eq__(other)

    def __hash__(self):
        return hash(self.description)

    def __str__(self):
        return self.description

    def __repr__(self):
        return f"<{self.__class__.__name__} {self}>"

    def __getnewargs__(self):
        return self.description, self.is_public

    @classmethod
    def load_from_file(
        cls, config_filename=default_config_filename
    ) -> List["ModeOfTransport"]:
        """Load all of the modes of transport from commute.yaml.

        Modes of transport are globally unique. That is, even if the function
        is called twice identical mode of transport objects are returned.

        Args:
            config_filename: The path to the mode of transport yaml configuration (Default value = default_config_filename)

        Returns:
            A list of modes of transport: 

        """
        with open(config_filename) as f:
            configs = yaml.load(f, Loader=yaml.FullLoader)
        return [ModeOfTransport(**config) for config in configs]

is_private property

True if this is private transport, for example a car.

__init__(description, is_public=False)

Create a ModeOfTransport from its description.

Only one instance of each mode of transport exists with instances being retrieved from the __all dictionary.

Parameters

description e.g. "Bus, minibus or coach" is_public True if this is public transport, for example a bus.

Source code in june/groups/travel/mode_of_transport.py
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
def __init__(self, description: str, is_public: bool = False):
    """
    Create a ModeOfTransport from its description.

    Only one instance of each mode of transport exists with instances being
    retrieved from the __all dictionary.

    Parameters
    ----------
    description
        e.g. "Bus, minibus or coach"
    is_public
        True if this is public transport, for example a bus.
    """
    self.description = description
    self.is_public = is_public

index(headers)

Determine the column index of this mode of transport.

The first header that contains this mode of transport's description is counted.

Parameters:

Name Type Description Default
headers List[str]

A list of headers from a CSV file.

required

Returns:

Type Description
int

The column index corresponding to this mode of transport.:

Raises:

Type Description
An assertion error if no such header is found.
Source code in june/groups/travel/mode_of_transport.py
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
def index(self, headers: List[str]) -> int:
    """Determine the column index of this mode of transport.

    The first header that contains this mode of transport's description
    is counted.

    Args:
        headers (List[str]): A list of headers from a CSV file.

    Returns:
        The column index corresponding to this mode of transport.: 

    Raises:
        An assertion error if no such header is found.: 


    """
    for i, header in enumerate(headers):
        if self.description in header:
            return i
    raise AssertionError(f"{self} not found in headers {headers}")

load_from_file(config_filename=default_config_filename) classmethod

Load all of the modes of transport from commute.yaml.

Modes of transport are globally unique. That is, even if the function is called twice identical mode of transport objects are returned.

Parameters:

Name Type Description Default
config_filename

The path to the mode of transport yaml configuration (Default value = default_config_filename)

default_config_filename

Returns:

Type Description
List[ModeOfTransport]

A list of modes of transport:

Source code in june/groups/travel/mode_of_transport.py
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
@classmethod
def load_from_file(
    cls, config_filename=default_config_filename
) -> List["ModeOfTransport"]:
    """Load all of the modes of transport from commute.yaml.

    Modes of transport are globally unique. That is, even if the function
    is called twice identical mode of transport objects are returned.

    Args:
        config_filename: The path to the mode of transport yaml configuration (Default value = default_config_filename)

    Returns:
        A list of modes of transport: 

    """
    with open(config_filename) as f:
        configs = yaml.load(f, Loader=yaml.FullLoader)
    return [ModeOfTransport(**config) for config in configs]

with_description(description) classmethod

Retrieve a mode of transport by its description.

Parameters:

Name Type Description Default
description str

A description, e.g. 'Bus, minibus or coach'

required

Returns:

Type Description
ModeOfTransport

The corresponding ModeOfTransport instance:

Source code in june/groups/travel/mode_of_transport.py
51
52
53
54
55
56
57
58
59
60
61
62
@classmethod
def with_description(cls, description: str) -> "ModeOfTransport":
    """Retrieve a mode of transport by its description.

    Args:
        description (str): A description, e.g. 'Bus, minibus or coach'

    Returns:
        The corresponding ModeOfTransport instance: 

    """
    return ModeOfTransport.__all[description]

ModeOfTransportGenerator

Source code in june/groups/travel/mode_of_transport.py
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
class ModeOfTransportGenerator:
    """ """
    def __init__(self, regional_generators: Dict[str, RegionalGenerator]):
        """
        Generate a mode of transport that a person uses in their commute.

        Modes of transport are chosen randomly, weighted by the numbers taken
        from census data for each given Output area.

        Parameters
        ----------
        regional_generators
            A dictionary mapping Geography areas to objects that randomly
            generate modes of transport
        """
        self.regional_generators = regional_generators

    def regional_gen_from_area(self, area: str) -> RegionalGenerator:
        """Get a regional generator for an Area identified
        by its output output area, e.g. E00062207

        Args:
            area (str): 

        Returns:
            An object that weighted-randomly selects modes of transport for the region.: 

        """
        if area in self.regional_generators:
            return self.regional_generators[area]
        else:
            # If area not found, create a default generator with equal weights for all modes
            # Load default modes from config
            modes_of_transport = ModeOfTransport.load_from_file()
            # Create equal weights (1 for each mode)
            weighted_modes = [(1, mode) for mode in modes_of_transport]
            return RegionalGenerator(area=area, weighted_modes=weighted_modes)

    @classmethod
    def from_file(
        cls,
        filename: str = default_commute_file,
        config_filename: str = default_config_filename,
    ) -> "ModeOfTransportGenerator":
        """Parse configuration describing each included mode of transport
        along with census data describing the weightings for modes of
        transport in each output area.

        Args:
            filename (str, optional): The path to the commute.csv file.
        This contains data on the number of people using each mode
        of transport. (Default value = default_commute_file)
            config_filename (str, optional): The path to the commute.yaml file (Default value = default_config_filename)

        Returns:
            An object used to generate commutes: 

        """
        regional_generators = {}
        with open(filename) as f:
            reader = csv.reader(f)
            headers = next(reader)
            area_column = headers.index("geography code")
            modes_of_transport = ModeOfTransport.load_from_file(config_filename)
            for row in reader:
                weighted_modes = []
                for mode in modes_of_transport:
                    weighted_modes.append((int(row[mode.index(headers)]), mode))
                area = row[area_column]
                regional_generators[area] = RegionalGenerator(
                    area=area, weighted_modes=weighted_modes
                )

        return ModeOfTransportGenerator(regional_generators)

__init__(regional_generators)

Generate a mode of transport that a person uses in their commute.

Modes of transport are chosen randomly, weighted by the numbers taken from census data for each given Output area.

Parameters

regional_generators A dictionary mapping Geography areas to objects that randomly generate modes of transport

Source code in june/groups/travel/mode_of_transport.py
186
187
188
189
190
191
192
193
194
195
196
197
198
199
def __init__(self, regional_generators: Dict[str, RegionalGenerator]):
    """
    Generate a mode of transport that a person uses in their commute.

    Modes of transport are chosen randomly, weighted by the numbers taken
    from census data for each given Output area.

    Parameters
    ----------
    regional_generators
        A dictionary mapping Geography areas to objects that randomly
        generate modes of transport
    """
    self.regional_generators = regional_generators

from_file(filename=default_commute_file, config_filename=default_config_filename) classmethod

Parse configuration describing each included mode of transport along with census data describing the weightings for modes of transport in each output area.

Parameters:

Name Type Description Default
filename str

The path to the commute.csv file.

default_commute_file

This contains data on the number of people using each mode of transport. (Default value = default_commute_file) config_filename (str, optional): The path to the commute.yaml file (Default value = default_config_filename)

Returns:

Type Description
ModeOfTransportGenerator

An object used to generate commutes:

Source code in june/groups/travel/mode_of_transport.py
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
@classmethod
def from_file(
    cls,
    filename: str = default_commute_file,
    config_filename: str = default_config_filename,
) -> "ModeOfTransportGenerator":
    """Parse configuration describing each included mode of transport
    along with census data describing the weightings for modes of
    transport in each output area.

    Args:
        filename (str, optional): The path to the commute.csv file.
    This contains data on the number of people using each mode
    of transport. (Default value = default_commute_file)
        config_filename (str, optional): The path to the commute.yaml file (Default value = default_config_filename)

    Returns:
        An object used to generate commutes: 

    """
    regional_generators = {}
    with open(filename) as f:
        reader = csv.reader(f)
        headers = next(reader)
        area_column = headers.index("geography code")
        modes_of_transport = ModeOfTransport.load_from_file(config_filename)
        for row in reader:
            weighted_modes = []
            for mode in modes_of_transport:
                weighted_modes.append((int(row[mode.index(headers)]), mode))
            area = row[area_column]
            regional_generators[area] = RegionalGenerator(
                area=area, weighted_modes=weighted_modes
            )

    return ModeOfTransportGenerator(regional_generators)

regional_gen_from_area(area)

Get a regional generator for an Area identified by its output output area, e.g. E00062207

Parameters:

Name Type Description Default
area str
required

Returns:

Type Description
RegionalGenerator

An object that weighted-randomly selects modes of transport for the region.:

Source code in june/groups/travel/mode_of_transport.py
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
def regional_gen_from_area(self, area: str) -> RegionalGenerator:
    """Get a regional generator for an Area identified
    by its output output area, e.g. E00062207

    Args:
        area (str): 

    Returns:
        An object that weighted-randomly selects modes of transport for the region.: 

    """
    if area in self.regional_generators:
        return self.regional_generators[area]
    else:
        # If area not found, create a default generator with equal weights for all modes
        # Load default modes from config
        modes_of_transport = ModeOfTransport.load_from_file()
        # Create equal weights (1 for each mode)
        weighted_modes = [(1, mode) for mode in modes_of_transport]
        return RegionalGenerator(area=area, weighted_modes=weighted_modes)

RegionalGenerator

Source code in june/groups/travel/mode_of_transport.py
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
class RegionalGenerator:
    """ """
    def __init__(self, area: str, weighted_modes: List[Tuple[int, "ModeOfTransport"]]):
        """
        Randomly generate modes of transport, weighted by usage, for
        one particular region.

        Parameters
        ----------
        area
            A unique identifier for a Output region
        weighted_modes
            A list of tuples comprising the number of people using a mode
            of a transport and a representation of that mode of transport
        """
        self.area = area
        self.weighted_modes = weighted_modes
        self.total = self._get_total()
        self.modes = self._get_modes()
        self.weights = self._get_weights()
        self.modes_idx = np.arange(0, len(self.modes))

    def _get_total(self) -> int:
        """The sum of the numbers of people using each mode of transport

        """
        return sum(mode[0] for mode in self.weighted_modes)

    def _get_modes(self) -> List["ModeOfTransport"]:
        """A list of modes of transport

        """
        return [mode[1] for mode in self.weighted_modes]

    def _get_weights(self) -> List[float]:
        """The normalised weights for each mode of transport.

        """
        if self.total == 0:
            # If no transport data is available, return equal weights for all modes
            n_modes = len(self.weighted_modes)
            return np.array([1.0 / n_modes if n_modes > 0 else 0.0] * n_modes)
        return np.array([mode[0] / self.total for mode in self.weighted_modes])

    def weighted_random_choice(self) -> "ModeOfTransport":
        """Randomly choose a mode of transport, weighted by usage in this region.

        """
        idx = random_choice_numba(self.modes_idx, self.weights)
        return self.modes[idx]

    def __repr__(self):
        return f"<{self.__class__.__name__} {self}>"

    def __str__(self):
        return self.area

__init__(area, weighted_modes)

Randomly generate modes of transport, weighted by usage, for one particular region.

Parameters

area A unique identifier for a Output region weighted_modes A list of tuples comprising the number of people using a mode of a transport and a representation of that mode of transport

Source code in june/groups/travel/mode_of_transport.py
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
def __init__(self, area: str, weighted_modes: List[Tuple[int, "ModeOfTransport"]]):
    """
    Randomly generate modes of transport, weighted by usage, for
    one particular region.

    Parameters
    ----------
    area
        A unique identifier for a Output region
    weighted_modes
        A list of tuples comprising the number of people using a mode
        of a transport and a representation of that mode of transport
    """
    self.area = area
    self.weighted_modes = weighted_modes
    self.total = self._get_total()
    self.modes = self._get_modes()
    self.weights = self._get_weights()
    self.modes_idx = np.arange(0, len(self.modes))

weighted_random_choice()

Randomly choose a mode of transport, weighted by usage in this region.

Source code in june/groups/travel/mode_of_transport.py
170
171
172
173
174
175
def weighted_random_choice(self) -> "ModeOfTransport":
    """Randomly choose a mode of transport, weighted by usage in this region.

    """
    idx = random_choice_numba(self.modes_idx, self.weights)
    return self.modes[idx]