nrel-shift 0.1.0a0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. NREL-shift-0.1.0a0/LICENSE.txt +29 -0
  2. NREL-shift-0.1.0a0/NREL_shift.egg-info/PKG-INFO +45 -0
  3. NREL-shift-0.1.0a0/NREL_shift.egg-info/SOURCES.txt +35 -0
  4. NREL-shift-0.1.0a0/NREL_shift.egg-info/dependency_links.txt +1 -0
  5. NREL-shift-0.1.0a0/NREL_shift.egg-info/entry_points.txt +2 -0
  6. NREL-shift-0.1.0a0/NREL_shift.egg-info/requires.txt +18 -0
  7. NREL-shift-0.1.0a0/NREL_shift.egg-info/top_level.txt +1 -0
  8. NREL-shift-0.1.0a0/PKG-INFO +45 -0
  9. NREL-shift-0.1.0a0/README.md +30 -0
  10. NREL-shift-0.1.0a0/setup.cfg +4 -0
  11. NREL-shift-0.1.0a0/setup.py +30 -0
  12. NREL-shift-0.1.0a0/shift/__init__.py +0 -0
  13. NREL-shift-0.1.0a0/shift/cli/__init__.py +0 -0
  14. NREL-shift-0.1.0a0/shift/cli/shift.py +69 -0
  15. NREL-shift-0.1.0a0/shift/clustering.py +229 -0
  16. NREL-shift-0.1.0a0/shift/config_template.py +300 -0
  17. NREL-shift-0.1.0a0/shift/constants.py +188 -0
  18. NREL-shift-0.1.0a0/shift/enums.py +100 -0
  19. NREL-shift-0.1.0a0/shift/examples/__init__.py +0 -0
  20. NREL-shift-0.1.0a0/shift/examples/example0.py +235 -0
  21. NREL-shift-0.1.0a0/shift/exceptions.py +588 -0
  22. NREL-shift-0.1.0a0/shift/exporter/__init__.py +0 -0
  23. NREL-shift-0.1.0a0/shift/exporter/base.py +44 -0
  24. NREL-shift-0.1.0a0/shift/exporter/opendss.py +584 -0
  25. NREL-shift-0.1.0a0/shift/facade.py +578 -0
  26. NREL-shift-0.1.0a0/shift/feeder_network.py +289 -0
  27. NREL-shift-0.1.0a0/shift/geometry.py +365 -0
  28. NREL-shift-0.1.0a0/shift/graph.py +227 -0
  29. NREL-shift-0.1.0a0/shift/line_section.py +745 -0
  30. NREL-shift-0.1.0a0/shift/load.py +218 -0
  31. NREL-shift-0.1.0a0/shift/load_builder.py +551 -0
  32. NREL-shift-0.1.0a0/shift/network_plots.py +295 -0
  33. NREL-shift-0.1.0a0/shift/primary_network_builder.py +892 -0
  34. NREL-shift-0.1.0a0/shift/secondary_network_builder.py +413 -0
  35. NREL-shift-0.1.0a0/shift/transformer.py +228 -0
  36. NREL-shift-0.1.0a0/shift/transformer_builder.py +536 -0
  37. NREL-shift-0.1.0a0/shift/utils.py +569 -0
@@ -0,0 +1,29 @@
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2022, Alliance for Sustainable Energy, LLC
4
+ All rights reserved.
5
+
6
+ Redistribution and use in source and binary forms, with or without
7
+ modification, are permitted provided that the following conditions are met:
8
+
9
+ 1. Redistributions of source code must retain the above copyright notice, this
10
+ list of conditions and the following disclaimer.
11
+
12
+ 2. Redistributions in binary form must reproduce the above copyright notice,
13
+ this list of conditions and the following disclaimer in the documentation
14
+ and/or other materials provided with the distribution.
15
+
16
+ 3. Neither the name of the copyright holder nor the names of its
17
+ contributors may be used to endorse or promote products derived from
18
+ this software without specific prior written permission.
19
+
20
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,45 @@
1
+ Metadata-Version: 2.1
2
+ Name: NREL-shift
3
+ Version: 0.1.0a0
4
+ Summary: Generate synthetic feeders using open street map data
5
+ Home-page: https://github.com/nrel/shift
6
+ Author: Kapil Duwadi
7
+ Author-email: kapil.duwadi@nrel.gov
8
+ Keywords: Synthetic feeder,Open steet data,OpenDSS
9
+ Classifier: License :: OSI Approved :: BSD License
10
+ Classifier: Programming Language :: Python :: 3.7
11
+ Classifier: Operating System :: OS Independent
12
+ Requires-Python: >=3.9
13
+ Description-Content-Type: text/markdown
14
+ License-File: LICENSE.txt
15
+
16
+
17
+ Simple Synthetic Distribution Feeder Generation Tool (SHIFT)
18
+
19
+ <img src="docs/images/shift.svg" width="400" style="display:block;margin:auto;">
20
+
21
+
22
+ ![GitHub all releases](https://img.shields.io/github/downloads/NREL/shift/total?logo=Github&logoColor=%2300ff00&style=flat-square)
23
+ ![GitHub repo size](https://img.shields.io/github/repo-size/nrel/shift?style=flat-square)
24
+ ![CodeFactor Grade](https://img.shields.io/codefactor/grade/github/nrel/shift?color=%23ff0000&logo=python&logoColor=%2300ff00&style=flat-square)
25
+ [![GitHub license](https://img.shields.io/github/license/NREL/shift?style=flat-square)](https://github.com/NREL/shift/blob/main/LICENSE.txt)
26
+ [![GitHub issues](https://img.shields.io/github/issues/NREL/shift?style=flat-square)](https://github.com/NREL/shift/issues)
27
+ ![GitHub top language](https://img.shields.io/github/languages/top/nrel/shift?style=flat-square)
28
+ ![Snyk Vulnerabilities for GitHub Repo](https://img.shields.io/snyk/vulnerabilities/github/nrel/shift?style=flat-square)
29
+
30
+ ### :wave: Welcome to SHIFT repository!
31
+
32
+ [Goto full documentation](https://nrel.github.io/shift/)
33
+
34
+ Getting free distribution feeder models for your reasearch has never been easier.
35
+ SHIFT helps you build synthetic distribution feeders models using just the OpenStreet data e.g. buildings and road network. You can configure lots of
36
+ parameters and design choices when building these models and even create multiple versions of them and choose the one that fits your needs. If you are utility no worries we
37
+ have you covered as well. As a utility you can also integrate your data when building these models.
38
+
39
+ Having distribution models in your hand can help you perform rich analysis in understanding impact of distributed energy resources
40
+ such as roof top PV, energy storage (Tesla Wall, lead acid, lithium name ....), electric vehicle and more. Performing network upgrade analysis, hosting capacity
41
+ analysis, interconnection studies all require detailed distribution models.
42
+
43
+ So what are you waiting for. We can't wait to see how you will use this tool for your as wells your organizations's benefit.
44
+
45
+ Feel free to reach out to us or send us a comment using Github issue. We don't mind if you smash that starred icon motivating our developers and contributors.
@@ -0,0 +1,35 @@
1
+ LICENSE.txt
2
+ README.md
3
+ setup.py
4
+ NREL_shift.egg-info/PKG-INFO
5
+ NREL_shift.egg-info/SOURCES.txt
6
+ NREL_shift.egg-info/dependency_links.txt
7
+ NREL_shift.egg-info/entry_points.txt
8
+ NREL_shift.egg-info/requires.txt
9
+ NREL_shift.egg-info/top_level.txt
10
+ shift/__init__.py
11
+ shift/clustering.py
12
+ shift/config_template.py
13
+ shift/constants.py
14
+ shift/enums.py
15
+ shift/exceptions.py
16
+ shift/facade.py
17
+ shift/feeder_network.py
18
+ shift/geometry.py
19
+ shift/graph.py
20
+ shift/line_section.py
21
+ shift/load.py
22
+ shift/load_builder.py
23
+ shift/network_plots.py
24
+ shift/primary_network_builder.py
25
+ shift/secondary_network_builder.py
26
+ shift/transformer.py
27
+ shift/transformer_builder.py
28
+ shift/utils.py
29
+ shift/cli/__init__.py
30
+ shift/cli/shift.py
31
+ shift/examples/__init__.py
32
+ shift/examples/example0.py
33
+ shift/exporter/__init__.py
34
+ shift/exporter/base.py
35
+ shift/exporter/opendss.py
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ shift-internal = shift.cli.shift:cli
@@ -0,0 +1,18 @@
1
+ osmnx
2
+ cerberus
3
+ geopy
4
+ pyshp
5
+ shapely
6
+ plotly
7
+ numpy
8
+ networkx
9
+ pandas
10
+ sklearn
11
+ pydantic
12
+ click
13
+ pytest
14
+ openpyxl
15
+ mkdocs
16
+ mkdocstrings[python]
17
+ mkdocs-material
18
+ mkdocs-jupyter
@@ -0,0 +1,45 @@
1
+ Metadata-Version: 2.1
2
+ Name: NREL-shift
3
+ Version: 0.1.0a0
4
+ Summary: Generate synthetic feeders using open street map data
5
+ Home-page: https://github.com/nrel/shift
6
+ Author: Kapil Duwadi
7
+ Author-email: kapil.duwadi@nrel.gov
8
+ Keywords: Synthetic feeder,Open steet data,OpenDSS
9
+ Classifier: License :: OSI Approved :: BSD License
10
+ Classifier: Programming Language :: Python :: 3.7
11
+ Classifier: Operating System :: OS Independent
12
+ Requires-Python: >=3.9
13
+ Description-Content-Type: text/markdown
14
+ License-File: LICENSE.txt
15
+
16
+
17
+ Simple Synthetic Distribution Feeder Generation Tool (SHIFT)
18
+
19
+ <img src="docs/images/shift.svg" width="400" style="display:block;margin:auto;">
20
+
21
+
22
+ ![GitHub all releases](https://img.shields.io/github/downloads/NREL/shift/total?logo=Github&logoColor=%2300ff00&style=flat-square)
23
+ ![GitHub repo size](https://img.shields.io/github/repo-size/nrel/shift?style=flat-square)
24
+ ![CodeFactor Grade](https://img.shields.io/codefactor/grade/github/nrel/shift?color=%23ff0000&logo=python&logoColor=%2300ff00&style=flat-square)
25
+ [![GitHub license](https://img.shields.io/github/license/NREL/shift?style=flat-square)](https://github.com/NREL/shift/blob/main/LICENSE.txt)
26
+ [![GitHub issues](https://img.shields.io/github/issues/NREL/shift?style=flat-square)](https://github.com/NREL/shift/issues)
27
+ ![GitHub top language](https://img.shields.io/github/languages/top/nrel/shift?style=flat-square)
28
+ ![Snyk Vulnerabilities for GitHub Repo](https://img.shields.io/snyk/vulnerabilities/github/nrel/shift?style=flat-square)
29
+
30
+ ### :wave: Welcome to SHIFT repository!
31
+
32
+ [Goto full documentation](https://nrel.github.io/shift/)
33
+
34
+ Getting free distribution feeder models for your reasearch has never been easier.
35
+ SHIFT helps you build synthetic distribution feeders models using just the OpenStreet data e.g. buildings and road network. You can configure lots of
36
+ parameters and design choices when building these models and even create multiple versions of them and choose the one that fits your needs. If you are utility no worries we
37
+ have you covered as well. As a utility you can also integrate your data when building these models.
38
+
39
+ Having distribution models in your hand can help you perform rich analysis in understanding impact of distributed energy resources
40
+ such as roof top PV, energy storage (Tesla Wall, lead acid, lithium name ....), electric vehicle and more. Performing network upgrade analysis, hosting capacity
41
+ analysis, interconnection studies all require detailed distribution models.
42
+
43
+ So what are you waiting for. We can't wait to see how you will use this tool for your as wells your organizations's benefit.
44
+
45
+ Feel free to reach out to us or send us a comment using Github issue. We don't mind if you smash that starred icon motivating our developers and contributors.
@@ -0,0 +1,30 @@
1
+
2
+ Simple Synthetic Distribution Feeder Generation Tool (SHIFT)
3
+
4
+ <img src="docs/images/shift.svg" width="400" style="display:block;margin:auto;">
5
+
6
+
7
+ ![GitHub all releases](https://img.shields.io/github/downloads/NREL/shift/total?logo=Github&logoColor=%2300ff00&style=flat-square)
8
+ ![GitHub repo size](https://img.shields.io/github/repo-size/nrel/shift?style=flat-square)
9
+ ![CodeFactor Grade](https://img.shields.io/codefactor/grade/github/nrel/shift?color=%23ff0000&logo=python&logoColor=%2300ff00&style=flat-square)
10
+ [![GitHub license](https://img.shields.io/github/license/NREL/shift?style=flat-square)](https://github.com/NREL/shift/blob/main/LICENSE.txt)
11
+ [![GitHub issues](https://img.shields.io/github/issues/NREL/shift?style=flat-square)](https://github.com/NREL/shift/issues)
12
+ ![GitHub top language](https://img.shields.io/github/languages/top/nrel/shift?style=flat-square)
13
+ ![Snyk Vulnerabilities for GitHub Repo](https://img.shields.io/snyk/vulnerabilities/github/nrel/shift?style=flat-square)
14
+
15
+ ### :wave: Welcome to SHIFT repository!
16
+
17
+ [Goto full documentation](https://nrel.github.io/shift/)
18
+
19
+ Getting free distribution feeder models for your reasearch has never been easier.
20
+ SHIFT helps you build synthetic distribution feeders models using just the OpenStreet data e.g. buildings and road network. You can configure lots of
21
+ parameters and design choices when building these models and even create multiple versions of them and choose the one that fits your needs. If you are utility no worries we
22
+ have you covered as well. As a utility you can also integrate your data when building these models.
23
+
24
+ Having distribution models in your hand can help you perform rich analysis in understanding impact of distributed energy resources
25
+ such as roof top PV, energy storage (Tesla Wall, lead acid, lithium name ....), electric vehicle and more. Performing network upgrade analysis, hosting capacity
26
+ analysis, interconnection studies all require detailed distribution models.
27
+
28
+ So what are you waiting for. We can't wait to see how you will use this tool for your as wells your organizations's benefit.
29
+
30
+ Feel free to reach out to us or send us a comment using Github issue. We don't mind if you smash that starred icon motivating our developers and contributors.
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,30 @@
1
+ import os
2
+ from setuptools import setup, find_packages
3
+
4
+ with open("README.md", "r") as fh:
5
+ long_description = fh.read()
6
+
7
+ with open(os.path.join(os.path.dirname(__file__), "requirements.txt")) as f:
8
+ requirements = f.read().splitlines()
9
+
10
+ setup(
11
+ name="NREL-shift",
12
+ long_description=long_description,
13
+ long_description_content_type="text/markdown",
14
+ version="v0.1.0-alpha",
15
+ description="Generate synthetic feeders using open street map data",
16
+ author="Kapil Duwadi",
17
+ author_email="kapil.duwadi@nrel.gov",
18
+ packages=find_packages(),
19
+ url="https://github.com/nrel/shift",
20
+ keywords="Synthetic feeder, Open steet data, OpenDSS",
21
+ install_requires=requirements,
22
+ python_requires=">=3.9",
23
+ package_dir={"shift": "shift"},
24
+ entry_points={"console_scripts": ["shift-internal=shift.cli.shift:cli"]},
25
+ classifiers=[
26
+ "License :: OSI Approved :: BSD License",
27
+ "Programming Language :: Python :: 3.7",
28
+ "Operating System :: OS Independent",
29
+ ],
30
+ )
File without changes
File without changes
@@ -0,0 +1,69 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright (c) 2022, Alliance for Sustainable Energy, LLC
3
+
4
+ # All rights reserved.
5
+
6
+ # Redistribution and use in source and binary forms, with or without
7
+ # modification, are permitted provided that the following conditions are met:
8
+
9
+ # 1. Redistributions of source code must retain the above copyright notice, this
10
+ # list of conditions and the following disclaimer.
11
+
12
+ # 2. Redistributions in binary form must reproduce the above copyright notice,
13
+ # this list of conditions and the following disclaimer in the documentation
14
+ # and/or other materials provided with the distribution.
15
+
16
+ # 3. Neither the name of the copyright holder nor the names of its
17
+ # contributors may be used to endorse or promote products derived from
18
+ # this software without specific prior written permission.
19
+
20
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24
+ # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27
+ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28
+ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
+
31
+ """This module handles command line interface for this package. """
32
+ import json
33
+
34
+ import click
35
+ import yaml
36
+
37
+ from shift.config_template import ConfigTemplate
38
+ from shift.facade import generate_feeder_from_yaml
39
+
40
+
41
+ @click.command()
42
+ @click.option("-c", "--config-yaml", help="Path to config yaml file.")
43
+ def create_config_file(config_yaml: str) -> None:
44
+ """Creates a default config yaml file. Update this yaml file and use it to
45
+ create the synthetic distribution feeder.
46
+ """
47
+ config = ConfigTemplate().dict()
48
+ print(json.loads(json.dumps(config)))
49
+ with open(config_yaml, "w", encoding="utf-8") as fpointer:
50
+ yaml.dump(json.loads(json.dumps(config)), fpointer)
51
+
52
+
53
+ @click.command()
54
+ @click.option("-c", "--config-yaml", help="Path to config yaml file.")
55
+ def create_feeder(config_yaml: str) -> None:
56
+ """Creates a synthetic distribution feeder
57
+ by taking the config yaml file as an input.
58
+ """
59
+ generate_feeder_from_yaml(config_yaml)
60
+
61
+
62
+ @click.group()
63
+ def cli():
64
+ """Entry point"""
65
+ pass
66
+
67
+
68
+ cli.add_command(create_config_file)
69
+ cli.add_command(create_feeder)
@@ -0,0 +1,229 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright (c) 2022, Alliance for Sustainable Energy, LLC
3
+
4
+ # All rights reserved.
5
+
6
+ # Redistribution and use in source and binary forms, with or without
7
+ # modification, are permitted provided that the following conditions are met:
8
+
9
+ # 1. Redistributions of source code must retain the above copyright notice, this
10
+ # list of conditions and the following disclaimer.
11
+
12
+ # 2. Redistributions in binary form must reproduce the above copyright notice,
13
+ # this list of conditions and the following disclaimer in the documentation
14
+ # and/or other materials provided with the distribution.
15
+
16
+ # 3. Neither the name of the copyright holder nor the names of its
17
+ # contributors may be used to endorse or promote products derived from
18
+ # this software without specific prior written permission.
19
+
20
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23
+ # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24
+ # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26
+ # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27
+ # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28
+ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
+ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
+
31
+ """ Contains abstract and concrete classes for implementing clustering.
32
+
33
+ This module contains classes for managing clustering of location pairs.
34
+ The cluster center is used as reference location to figure out
35
+ transformer siting. In the process mapping between
36
+ cluster center and locations is also created.
37
+
38
+ Examples:
39
+ Get the clusters from given list of location pairs and plot it.
40
+
41
+ >>> from shift.clustering import KmeansClustering
42
+ >>> import numpy as np
43
+ >>> x_array = np.array([[1,2], [3,4], [5,6]])
44
+ >>> cluster = KmeansClustering(2)
45
+ >>> cluster.get_clusters(x_array)
46
+ >>> cluster.plot_clusters()
47
+ """
48
+
49
+ from abc import ABC, abstractmethod
50
+ from typing import List, Union
51
+
52
+ from sklearn.cluster import KMeans
53
+ from sklearn.metrics import silhouette_score
54
+ import plotly.express as px
55
+ import pandas as pd
56
+
57
+ from shift.constants import MAX_KMEANS_LOOP, MIN_NUM_CLUSTER
58
+ from shift.exceptions import (
59
+ MaxLoopReachedForKmeans,
60
+ WrongInputUsed,
61
+ NumberOfClusterNotInRangeError,
62
+ EarlyMethodCallError,
63
+ )
64
+
65
+
66
+ class Clustering(ABC):
67
+ """Abstract interface for implementing clustering subclass"""
68
+
69
+ @abstractmethod
70
+ def get_clusters(self, x_array: List[list]) -> dict:
71
+ """Method for creating and returning clusters.
72
+
73
+ Subclass inhereting this class must implement this method and should
74
+ return the clusters in the following format.
75
+ ```json
76
+ {"labels": [0,1,1], "centre": [(0,0), (2,2)]}
77
+ ```
78
+
79
+ Returns:
80
+ dict: A dictionary containing cluster labels
81
+ and cluster centers
82
+ """
83
+ pass
84
+
85
+ @abstractmethod
86
+ def plot_clusters(self) -> None:
87
+ """Method to plot clusters
88
+
89
+ Raises:
90
+ EarlyMethodCallError: If this method is called before calling
91
+ `get_clusters` method.
92
+ """
93
+ pass
94
+
95
+
96
+ class KmeansClustering(Clustering):
97
+ """Class implementing Kmeans clustering.
98
+
99
+ Attributes:
100
+ num_of_clusters (Union[str, int]): Number of clusters to be used
101
+ cluster_centers (List[Sequece]): List of cluster center
102
+ labels (list): Integer label for each location indicating which
103
+ cluster they belong to
104
+ xarray (List[Sequece]): List of location pairs for which
105
+ clustering is performed
106
+ optimal_clusters (int): Optimal number of clusters created if
107
+ `num_of_clusters` passed is `optimal`
108
+ """
109
+
110
+ def __init__(self, num_of_clusters: Union[str, int] = "optimal") -> None:
111
+ """Constructor for `KmeansClustering` class.
112
+
113
+ Args:
114
+ num_of_clusters (Union[str, int]): Number of clusters to be used
115
+
116
+ Raises:
117
+ NumberOfClusterNotInRangeError: if `num_of_clusters` speecified is
118
+ less than MIN_NUM_CLUSTER constants module.
119
+ """
120
+ self.num_of_clusters = num_of_clusters
121
+
122
+ if isinstance(self.num_of_clusters, int):
123
+ if self.num_of_clusters < MIN_NUM_CLUSTER:
124
+ raise NumberOfClusterNotInRangeError(self.num_of_clusters)
125
+
126
+ def plot_clusters(self):
127
+ """Refer to the base class for details."""
128
+
129
+ if (
130
+ hasattr(self, "x_array")
131
+ and hasattr(self, "labels")
132
+ and hasattr(self, "cluster_centers")
133
+ ):
134
+ plot_data = {"x": [], "y": [], "label": []}
135
+ for d, label in zip(self.x_array, self.labels):
136
+ plot_data["x"].append(d[0])
137
+ plot_data["y"].append(d[1])
138
+ plot_data["label"].append(label)
139
+ fig = px.scatter(
140
+ pd.DataFrame(plot_data), x="x", y="y", color="label"
141
+ )
142
+ fig.show()
143
+
144
+ else:
145
+ raise EarlyMethodCallError(
146
+ "Call get_clusters() method first before "
147
+ + "calling plot clusters method!"
148
+ )
149
+
150
+ def plot_scores(self):
151
+ """Method for plotting scores
152
+
153
+ Note:
154
+ Only use this method if `num_of_clusters` passed is `optimal`.
155
+
156
+ Raises:
157
+ EarlyMethodCallError: If called before calling
158
+ `get_clusters` method.
159
+ """
160
+
161
+ if hasattr(self, "sil_scores"):
162
+ plot_data = {
163
+ "Number of clusters": [x[0] for x in self.sil_scores],
164
+ "Silhouette Value": [x[1] for x in self.sil_scores],
165
+ }
166
+ fig = px.line(
167
+ pd.DataFrame(plot_data),
168
+ x="Number of clusters",
169
+ y="Silhouette Value",
170
+ )
171
+ fig.show()
172
+
173
+ else:
174
+ raise EarlyMethodCallError(
175
+ "Call get_clusters() method first before calling "
176
+ + "plot scores method!"
177
+ )
178
+
179
+ def get_clusters(self, x_array: list) -> dict:
180
+ """Refer to the base class for details.
181
+
182
+ Raises:
183
+ WrongInputUsed: If the number of clusters passed is invalid.
184
+ """
185
+
186
+ self.x_array = x_array
187
+ if isinstance(self.num_of_clusters, int):
188
+ kmeans = KMeans(
189
+ n_clusters=self.num_of_clusters, random_state=0
190
+ ).fit(x_array)
191
+
192
+ else:
193
+ if self.num_of_clusters == "optimal":
194
+ # Let's try to find optimal number of clusters
195
+ self.sil_scores = []
196
+
197
+ for k in range(2, MAX_KMEANS_LOOP):
198
+ kmeans = KMeans(n_clusters=k).fit(x_array)
199
+ labels = kmeans.labels_
200
+ self.sil_scores.append(
201
+ (
202
+ k,
203
+ silhouette_score(
204
+ x_array, labels, metric="euclidean"
205
+ ),
206
+ )
207
+ )
208
+
209
+ # Break the loop if Silhouette score starts to decrease
210
+ if k > 2:
211
+ if (
212
+ self.sil_scores[k - 2][1]
213
+ < self.sil_scores[k - 3][1]
214
+ ):
215
+ break
216
+
217
+ if k == MAX_KMEANS_LOOP - 1:
218
+ raise MaxLoopReachedForKmeans()
219
+ kmeans = KMeans(n_clusters=k - 1, random_state=0).fit(x_array)
220
+ self.optimal_clusters = k - 1
221
+ else:
222
+ raise WrongInputUsed(
223
+ "For now number of clusters can be either integer "
224
+ + "number or 'optimal'!"
225
+ + f"You provided {self.num_of_clusters}"
226
+ )
227
+ self.labels = kmeans.labels_
228
+ self.cluster_centers = kmeans.cluster_centers_
229
+ return {"labels": self.labels, "centre": self.cluster_centers}