jsp-vis 1.0.0__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.
- jsp_vis-1.0.0/LICENSE +21 -0
- jsp_vis-1.0.0/MANIFEST.in +1 -0
- jsp_vis-1.0.0/PKG-INFO +169 -0
- jsp_vis-1.0.0/README.md +117 -0
- jsp_vis-1.0.0/pyproject.toml +45 -0
- jsp_vis-1.0.0/setup.cfg +23 -0
- jsp_vis-1.0.0/setup.py +4 -0
- jsp_vis-1.0.0/src/jsp_vis/__init__.py +0 -0
- jsp_vis-1.0.0/src/jsp_vis/console.py +209 -0
- jsp_vis-1.0.0/src/jsp_vis/cv2_window.py +69 -0
- jsp_vis-1.0.0/src/jsp_vis/rgb_array.py +49 -0
- jsp_vis-1.0.0/src/jsp_vis.egg-info/PKG-INFO +169 -0
- jsp_vis-1.0.0/src/jsp_vis.egg-info/SOURCES.txt +19 -0
- jsp_vis-1.0.0/src/jsp_vis.egg-info/dependency_links.txt +1 -0
- jsp_vis-1.0.0/src/jsp_vis.egg-info/not-zip-safe +1 -0
- jsp_vis-1.0.0/src/jsp_vis.egg-info/requires.txt +13 -0
- jsp_vis-1.0.0/src/jsp_vis.egg-info/top_level.txt +1 -0
- jsp_vis-1.0.0/tests/test_render_console.py +25 -0
- jsp_vis-1.0.0/tests/test_render_cv2_window.py +30 -0
- jsp_vis-1.0.0/tests/test_render_rgb_array.py +17 -0
jsp_vis-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Alexander Nasuta
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# MANIFEST.in
|
jsp_vis-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: jsp-vis
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: A flexible enviorment for job shop scheduling using the disjunctive graph apporach.
|
|
5
|
+
Author: Alexander Nasuta
|
|
6
|
+
Author-email: Alexander Nasuta <alexander.nasuta@ima.rwth-aachen.de>
|
|
7
|
+
License: MIT License
|
|
8
|
+
|
|
9
|
+
Copyright (c) 2024 Alexander Nasuta
|
|
10
|
+
|
|
11
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
12
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
13
|
+
in the Software without restriction, including without limitation the rights
|
|
14
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
15
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
16
|
+
furnished to do so, subject to the following conditions:
|
|
17
|
+
|
|
18
|
+
The above copyright notice and this permission notice shall be included in all
|
|
19
|
+
copies or substantial portions of the Software.
|
|
20
|
+
|
|
21
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
22
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
23
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
24
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
25
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
26
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
27
|
+
SOFTWARE.
|
|
28
|
+
Project-URL: Homepage, https://github.com/Alexander-Nasuta/pypitemplate
|
|
29
|
+
Platform: unix
|
|
30
|
+
Platform: linux
|
|
31
|
+
Platform: osx
|
|
32
|
+
Platform: cygwin
|
|
33
|
+
Platform: win32
|
|
34
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
35
|
+
Classifier: Programming Language :: Python
|
|
36
|
+
Classifier: Programming Language :: Python :: 3
|
|
37
|
+
Requires-Python: >=3.9
|
|
38
|
+
Description-Content-Type: text/markdown
|
|
39
|
+
License-File: LICENSE
|
|
40
|
+
Requires-Dist: opencv-python
|
|
41
|
+
Requires-Dist: plotly
|
|
42
|
+
Requires-Dist: matplotlib
|
|
43
|
+
Requires-Dist: numpy
|
|
44
|
+
Requires-Dist: pandas
|
|
45
|
+
Requires-Dist: kaleido
|
|
46
|
+
Provides-Extra: dev
|
|
47
|
+
Requires-Dist: pip-tools; extra == "dev"
|
|
48
|
+
Requires-Dist: pytest; extra == "dev"
|
|
49
|
+
Requires-Dist: pytest-cov; extra == "dev"
|
|
50
|
+
Requires-Dist: tox; extra == "dev"
|
|
51
|
+
Requires-Dist: twine; extra == "dev"
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
<div id="top"></div>
|
|
56
|
+
|
|
57
|
+
<!-- PROJECT LOGO -->
|
|
58
|
+
<br />
|
|
59
|
+
<div align="center">
|
|
60
|
+
<!--
|
|
61
|
+
<a href="https://cybernetics-lab.de/">
|
|
62
|
+
<img src="https://github.com/Alexander-Nasuta/graph-jsp-env/raw/master/resources/readme_images/logo.png" alt="Logo" height="80">
|
|
63
|
+
</a>
|
|
64
|
+
-->
|
|
65
|
+
|
|
66
|
+
<h1 align="center">
|
|
67
|
+
Job Shop Scheduling Problem Visualisations
|
|
68
|
+
</h1>
|
|
69
|
+
|
|
70
|
+
<!--
|
|
71
|
+
<a>
|
|
72
|
+
<img src="https://github.com/Alexander-Nasuta/graph-jsp-env/raw/master/resources/readme_images/graph_jsp_tikz.png" alt="Logo" height="180">
|
|
73
|
+
</a>
|
|
74
|
+
-->
|
|
75
|
+
|
|
76
|
+
</div>
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
- **Github**: https://github.com/Alexander-Nasuta/jsp-vis
|
|
80
|
+
|
|
81
|
+
- **PyPi**:
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
# About The Project
|
|
85
|
+
Ths project provides visualisation for the Job Shop Scheduling Problem (JSP).
|
|
86
|
+
This is focused on Gantt charts. The input date for the visualisation is inspired by [plotly's Gantt chart api](https://plotly.com/python/gantt/).
|
|
87
|
+
`jsp-vis` is a standalone package and in designed to be used in combination with a JSP-reinforcement learning environments that follow the [Gymnasium Environment](https://gymnasium.farama.org/) standard.
|
|
88
|
+
The render function of the environment can be used to render the Gantt chart.
|
|
89
|
+
Typically the render function can implement different modes like `human`, `rgb_array` or `ansi` rendering.
|
|
90
|
+
The `jsp-vis` package offers three different visualisations: console visualisation, rgb_array visualisation and window visualisation.
|
|
91
|
+
The window visualisation is essentially only rendering the rgb_array visualisation in a window using OpenCV.
|
|
92
|
+
The console visualisation might be used for the `asni` mode of a render function, the rgb_array visualisation for the `rgb_array` mode and the window visualisation for the `human` mode.
|
|
93
|
+
|
|
94
|
+
# Installation
|
|
95
|
+
|
|
96
|
+
Install the package with pip:
|
|
97
|
+
```
|
|
98
|
+
pip install todo
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
# Minimal Working Example: console visualisation
|
|
102
|
+
|
|
103
|
+
```python
|
|
104
|
+
import pandas
|
|
105
|
+
from jsp_vis.console import gantt_chart_console
|
|
106
|
+
import pandas as pd
|
|
107
|
+
|
|
108
|
+
df = pd.DataFrame([
|
|
109
|
+
{'Task': 'Job 0', 'Start': 5, 'Finish': 16, 'Resource': 'Machine 0'},
|
|
110
|
+
{'Task': 'Job 0', 'Start': 28, 'Finish': 31, 'Resource': 'Machine 1'},
|
|
111
|
+
{'Task': 'Job 0', 'Start': 31, 'Finish': 34, 'Resource': 'Machine 2'},
|
|
112
|
+
{'Task': 'Job 0', 'Start': 34, 'Finish': 46, 'Resource': 'Machine 3'},
|
|
113
|
+
{'Task': 'Job 1', 'Start': 0, 'Finish': 5, 'Resource': 'Machine 0'},
|
|
114
|
+
{'Task': 'Job 1', 'Start': 5, 'Finish': 21, 'Resource': 'Machine 2'},
|
|
115
|
+
{'Task': 'Job 1', 'Start': 21, 'Finish': 28, 'Resource': 'Machine 1'},
|
|
116
|
+
{'Task': 'Job 1', 'Start': 28, 'Finish': 32, 'Resource': 'Machine 3'}
|
|
117
|
+
])
|
|
118
|
+
num_of_machines = 4
|
|
119
|
+
|
|
120
|
+
gantt_chart_console(df, num_of_machines)
|
|
121
|
+
```
|
|
122
|
+
The code above will render the following Gantt chart in the console:
|
|
123
|
+
|
|
124
|
+

|
|
125
|
+
|
|
126
|
+
# Minimal Working Example: console visualisation
|
|
127
|
+
|
|
128
|
+
```python
|
|
129
|
+
from jsp_vis.cv2_window import render_gantt_in_window
|
|
130
|
+
import pandas as pd
|
|
131
|
+
|
|
132
|
+
df = pd.DataFrame([
|
|
133
|
+
{'Task': 'Job 0', 'Start': 5, 'Finish': 16, 'Resource': 'Machine 0'},
|
|
134
|
+
{'Task': 'Job 0', 'Start': 28, 'Finish': 31, 'Resource': 'Machine 1'},
|
|
135
|
+
{'Task': 'Job 0', 'Start': 31, 'Finish': 34, 'Resource': 'Machine 2'},
|
|
136
|
+
{'Task': 'Job 0', 'Start': 34, 'Finish': 46, 'Resource': 'Machine 3'},
|
|
137
|
+
{'Task': 'Job 1', 'Start': 0, 'Finish': 5, 'Resource': 'Machine 0'},
|
|
138
|
+
{'Task': 'Job 1', 'Start': 5, 'Finish': 21, 'Resource': 'Machine 2'},
|
|
139
|
+
{'Task': 'Job 1', 'Start': 21, 'Finish': 28, 'Resource': 'Machine 1'},
|
|
140
|
+
{'Task': 'Job 1', 'Start': 28, 'Finish': 32, 'Resource': 'Machine 3'}
|
|
141
|
+
])
|
|
142
|
+
num_of_machines = 4
|
|
143
|
+
|
|
144
|
+
render_gantt_in_window(
|
|
145
|
+
df=df,
|
|
146
|
+
n_machines=num_of_machines,
|
|
147
|
+
wait=2000 # time in ms that the `cv2`-window is open.
|
|
148
|
+
# wait=None # ''None'' will keep the window open till a keyboard occurs.
|
|
149
|
+
)
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
The code above will render the following Gantt chart in the console:
|
|
153
|
+
|
|
154
|
+

|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
# More Examples
|
|
158
|
+
For more examples you can have a look at the test files in the `tests` directory.
|
|
159
|
+
Every visualisation has its own test file and is tested on two different jsp instances defined in the `conftest.py`.
|
|
160
|
+
|
|
161
|
+
# License
|
|
162
|
+
|
|
163
|
+
Distributed under the MIT License. See `LICENSE.txt` for more information.
|
|
164
|
+
|
|
165
|
+
<!-- MARKDOWN LINKS & IMAGES todo: add Github, Linked in etc.-->
|
|
166
|
+
<!-- https://www.markdownguide.org/basic-syntax/#reference-style-links -->
|
|
167
|
+
[screenshot]: resources/readme_images/screenshot.png
|
|
168
|
+
|
|
169
|
+
|
jsp_vis-1.0.0/README.md
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
<div id="top"></div>
|
|
4
|
+
|
|
5
|
+
<!-- PROJECT LOGO -->
|
|
6
|
+
<br />
|
|
7
|
+
<div align="center">
|
|
8
|
+
<!--
|
|
9
|
+
<a href="https://cybernetics-lab.de/">
|
|
10
|
+
<img src="https://github.com/Alexander-Nasuta/graph-jsp-env/raw/master/resources/readme_images/logo.png" alt="Logo" height="80">
|
|
11
|
+
</a>
|
|
12
|
+
-->
|
|
13
|
+
|
|
14
|
+
<h1 align="center">
|
|
15
|
+
Job Shop Scheduling Problem Visualisations
|
|
16
|
+
</h1>
|
|
17
|
+
|
|
18
|
+
<!--
|
|
19
|
+
<a>
|
|
20
|
+
<img src="https://github.com/Alexander-Nasuta/graph-jsp-env/raw/master/resources/readme_images/graph_jsp_tikz.png" alt="Logo" height="180">
|
|
21
|
+
</a>
|
|
22
|
+
-->
|
|
23
|
+
|
|
24
|
+
</div>
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
- **Github**: https://github.com/Alexander-Nasuta/jsp-vis
|
|
28
|
+
|
|
29
|
+
- **PyPi**:
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
# About The Project
|
|
33
|
+
Ths project provides visualisation for the Job Shop Scheduling Problem (JSP).
|
|
34
|
+
This is focused on Gantt charts. The input date for the visualisation is inspired by [plotly's Gantt chart api](https://plotly.com/python/gantt/).
|
|
35
|
+
`jsp-vis` is a standalone package and in designed to be used in combination with a JSP-reinforcement learning environments that follow the [Gymnasium Environment](https://gymnasium.farama.org/) standard.
|
|
36
|
+
The render function of the environment can be used to render the Gantt chart.
|
|
37
|
+
Typically the render function can implement different modes like `human`, `rgb_array` or `ansi` rendering.
|
|
38
|
+
The `jsp-vis` package offers three different visualisations: console visualisation, rgb_array visualisation and window visualisation.
|
|
39
|
+
The window visualisation is essentially only rendering the rgb_array visualisation in a window using OpenCV.
|
|
40
|
+
The console visualisation might be used for the `asni` mode of a render function, the rgb_array visualisation for the `rgb_array` mode and the window visualisation for the `human` mode.
|
|
41
|
+
|
|
42
|
+
# Installation
|
|
43
|
+
|
|
44
|
+
Install the package with pip:
|
|
45
|
+
```
|
|
46
|
+
pip install todo
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
# Minimal Working Example: console visualisation
|
|
50
|
+
|
|
51
|
+
```python
|
|
52
|
+
import pandas
|
|
53
|
+
from jsp_vis.console import gantt_chart_console
|
|
54
|
+
import pandas as pd
|
|
55
|
+
|
|
56
|
+
df = pd.DataFrame([
|
|
57
|
+
{'Task': 'Job 0', 'Start': 5, 'Finish': 16, 'Resource': 'Machine 0'},
|
|
58
|
+
{'Task': 'Job 0', 'Start': 28, 'Finish': 31, 'Resource': 'Machine 1'},
|
|
59
|
+
{'Task': 'Job 0', 'Start': 31, 'Finish': 34, 'Resource': 'Machine 2'},
|
|
60
|
+
{'Task': 'Job 0', 'Start': 34, 'Finish': 46, 'Resource': 'Machine 3'},
|
|
61
|
+
{'Task': 'Job 1', 'Start': 0, 'Finish': 5, 'Resource': 'Machine 0'},
|
|
62
|
+
{'Task': 'Job 1', 'Start': 5, 'Finish': 21, 'Resource': 'Machine 2'},
|
|
63
|
+
{'Task': 'Job 1', 'Start': 21, 'Finish': 28, 'Resource': 'Machine 1'},
|
|
64
|
+
{'Task': 'Job 1', 'Start': 28, 'Finish': 32, 'Resource': 'Machine 3'}
|
|
65
|
+
])
|
|
66
|
+
num_of_machines = 4
|
|
67
|
+
|
|
68
|
+
gantt_chart_console(df, num_of_machines)
|
|
69
|
+
```
|
|
70
|
+
The code above will render the following Gantt chart in the console:
|
|
71
|
+
|
|
72
|
+

|
|
73
|
+
|
|
74
|
+
# Minimal Working Example: console visualisation
|
|
75
|
+
|
|
76
|
+
```python
|
|
77
|
+
from jsp_vis.cv2_window import render_gantt_in_window
|
|
78
|
+
import pandas as pd
|
|
79
|
+
|
|
80
|
+
df = pd.DataFrame([
|
|
81
|
+
{'Task': 'Job 0', 'Start': 5, 'Finish': 16, 'Resource': 'Machine 0'},
|
|
82
|
+
{'Task': 'Job 0', 'Start': 28, 'Finish': 31, 'Resource': 'Machine 1'},
|
|
83
|
+
{'Task': 'Job 0', 'Start': 31, 'Finish': 34, 'Resource': 'Machine 2'},
|
|
84
|
+
{'Task': 'Job 0', 'Start': 34, 'Finish': 46, 'Resource': 'Machine 3'},
|
|
85
|
+
{'Task': 'Job 1', 'Start': 0, 'Finish': 5, 'Resource': 'Machine 0'},
|
|
86
|
+
{'Task': 'Job 1', 'Start': 5, 'Finish': 21, 'Resource': 'Machine 2'},
|
|
87
|
+
{'Task': 'Job 1', 'Start': 21, 'Finish': 28, 'Resource': 'Machine 1'},
|
|
88
|
+
{'Task': 'Job 1', 'Start': 28, 'Finish': 32, 'Resource': 'Machine 3'}
|
|
89
|
+
])
|
|
90
|
+
num_of_machines = 4
|
|
91
|
+
|
|
92
|
+
render_gantt_in_window(
|
|
93
|
+
df=df,
|
|
94
|
+
n_machines=num_of_machines,
|
|
95
|
+
wait=2000 # time in ms that the `cv2`-window is open.
|
|
96
|
+
# wait=None # ''None'' will keep the window open till a keyboard occurs.
|
|
97
|
+
)
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
The code above will render the following Gantt chart in the console:
|
|
101
|
+
|
|
102
|
+

|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
# More Examples
|
|
106
|
+
For more examples you can have a look at the test files in the `tests` directory.
|
|
107
|
+
Every visualisation has its own test file and is tested on two different jsp instances defined in the `conftest.py`.
|
|
108
|
+
|
|
109
|
+
# License
|
|
110
|
+
|
|
111
|
+
Distributed under the MIT License. See `LICENSE.txt` for more information.
|
|
112
|
+
|
|
113
|
+
<!-- MARKDOWN LINKS & IMAGES todo: add Github, Linked in etc.-->
|
|
114
|
+
<!-- https://www.markdownguide.org/basic-syntax/#reference-style-links -->
|
|
115
|
+
[screenshot]: resources/readme_images/screenshot.png
|
|
116
|
+
|
|
117
|
+
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=65.5.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "jsp-vis"
|
|
7
|
+
version = "1.0.0"
|
|
8
|
+
description = "A flexible enviorment for job shop scheduling using the disjunctive graph apporach."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
authors = [{ name = "Alexander Nasuta", email = "alexander.nasuta@ima.rwth-aachen.de" }]
|
|
11
|
+
license = { file = "LICENSE" }
|
|
12
|
+
classifiers = [
|
|
13
|
+
"License :: OSI Approved :: MIT License",
|
|
14
|
+
"Programming Language :: Python",
|
|
15
|
+
"Programming Language :: Python :: 3",
|
|
16
|
+
]
|
|
17
|
+
keywords = []
|
|
18
|
+
dependencies = [
|
|
19
|
+
"opencv-python",
|
|
20
|
+
"plotly",
|
|
21
|
+
# "networkx>=3",
|
|
22
|
+
"matplotlib",
|
|
23
|
+
"numpy",
|
|
24
|
+
"pandas",
|
|
25
|
+
"kaleido",
|
|
26
|
+
]
|
|
27
|
+
requires-python = ">=3.9"
|
|
28
|
+
|
|
29
|
+
[project.optional-dependencies]
|
|
30
|
+
dev = [
|
|
31
|
+
"pip-tools",
|
|
32
|
+
"pytest",
|
|
33
|
+
"pytest-cov",
|
|
34
|
+
"tox",
|
|
35
|
+
"twine"
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
[project.urls]
|
|
39
|
+
Homepage = "https://github.com/Alexander-Nasuta/pypitemplate"
|
|
40
|
+
|
|
41
|
+
[tool.pytest.ini_options]
|
|
42
|
+
addopts = "--cov=jsp_vis -p no:warnings"
|
|
43
|
+
testpaths = [
|
|
44
|
+
"tests",
|
|
45
|
+
]
|
jsp_vis-1.0.0/setup.cfg
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
[metadata]
|
|
2
|
+
name = jsp-vis
|
|
3
|
+
author = Alexander Nasuta
|
|
4
|
+
license = MIT
|
|
5
|
+
license_files = LICENSE
|
|
6
|
+
platforms = unix, linux, osx, cygwin, win32
|
|
7
|
+
classifiers =
|
|
8
|
+
Programming Language :: Python :: 3
|
|
9
|
+
Programming Language :: Python :: 3 :: Only
|
|
10
|
+
Programming Language :: Python :: 3.11
|
|
11
|
+
|
|
12
|
+
[options]
|
|
13
|
+
packages =
|
|
14
|
+
jsp_vis
|
|
15
|
+
python_requires = >=3.11
|
|
16
|
+
package_dir =
|
|
17
|
+
=src
|
|
18
|
+
zip_safe = no
|
|
19
|
+
|
|
20
|
+
[egg_info]
|
|
21
|
+
tag_build =
|
|
22
|
+
tag_date = 0
|
|
23
|
+
|
jsp_vis-1.0.0/setup.py
ADDED
|
File without changes
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import itertools
|
|
2
|
+
import shutil
|
|
3
|
+
|
|
4
|
+
import matplotlib
|
|
5
|
+
import numpy as np
|
|
6
|
+
import pandas as pd
|
|
7
|
+
|
|
8
|
+
import logging
|
|
9
|
+
|
|
10
|
+
log = logging.getLogger(__name__)
|
|
11
|
+
|
|
12
|
+
CEND = "\33[0m"
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def rgb_color_sequence(r: int | float, g: int | float, b: int | float,
|
|
16
|
+
*, format_type: str = 'foreground') -> str:
|
|
17
|
+
"""
|
|
18
|
+
generates a color-codes, that change the color of text in console outputs.
|
|
19
|
+
|
|
20
|
+
rgb values must be numbers between 0 and 255 or 0.0 and 1.0.
|
|
21
|
+
|
|
22
|
+
:param r: red value.
|
|
23
|
+
:param g: green value
|
|
24
|
+
:param b: blue value
|
|
25
|
+
|
|
26
|
+
:param format_type: specifies weather the foreground-color or the background-color shall be adjusted.
|
|
27
|
+
valid options: 'foreground','background'
|
|
28
|
+
:return: a string that contains the color-codes.
|
|
29
|
+
"""
|
|
30
|
+
# type: ignore # noqa: F401
|
|
31
|
+
if format_type == 'foreground':
|
|
32
|
+
f = '\033[38;2;{};{};{}m'.format # font rgb format
|
|
33
|
+
elif format_type == 'background':
|
|
34
|
+
f = '\033[48;2;{};{};{}m'.format # font background rgb format
|
|
35
|
+
else:
|
|
36
|
+
raise ValueError(f"format {format_type} is not defined. Use 'foreground' or 'background'.")
|
|
37
|
+
rgb = [r, g, b]
|
|
38
|
+
|
|
39
|
+
if isinstance(r, int) and isinstance(g, int) and isinstance(b, int):
|
|
40
|
+
if min(rgb) < 0 and max(rgb) > 255:
|
|
41
|
+
raise ValueError("rgb values must be numbers between 0 and 255 or 0.0 and 1.0")
|
|
42
|
+
return f(r, g, b)
|
|
43
|
+
if isinstance(r, float) and isinstance(g, float) and isinstance(b, float):
|
|
44
|
+
if min(rgb) < 0 and max(rgb) > 1:
|
|
45
|
+
raise ValueError("rgb values must be numbers between 0 and 255 or 0.0 and 1.0")
|
|
46
|
+
return f(*[int(n * 255) for n in [r, g, b]])
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def wrap_with_color_codes(s: object, /, r: int | float, g: int | float, b: int | float, **kwargs) \
|
|
50
|
+
-> str:
|
|
51
|
+
"""
|
|
52
|
+
stringify an object and wrap it with console color codes. It adds the color control sequence in front and one
|
|
53
|
+
at the end that resolves the color again.
|
|
54
|
+
|
|
55
|
+
rgb values must be numbers between 0 and 255 or 0.0 and 1.0.
|
|
56
|
+
|
|
57
|
+
:param s: the object to stringify and wrap
|
|
58
|
+
:param r: red value.
|
|
59
|
+
:param g: green value.
|
|
60
|
+
:param b: blue value.
|
|
61
|
+
:param kwargs: additional argument for the 'DisjunctiveGraphJspVisualizer.rgb_color_sequence'-method.
|
|
62
|
+
:return:
|
|
63
|
+
"""
|
|
64
|
+
return f"{rgb_color_sequence(r, g, b, **kwargs)}" \
|
|
65
|
+
f"{s}" \
|
|
66
|
+
f"{CEND}"
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def gantt_chart_console(df: pd.DataFrame, n_machines: int, c_map="rainbow") -> None:
|
|
70
|
+
"""
|
|
71
|
+
console version of the `gantt_chart_rgb_array`-method. prints a gant chart to the console.
|
|
72
|
+
the parameters need to follow the plotly specification.
|
|
73
|
+
see: https://plotly.com/python/gantt/ or `gantt_chart_rgb_array`
|
|
74
|
+
|
|
75
|
+
:param df: dataframe according to `plotly` specification (https://plotly.com/python/gantt/).
|
|
76
|
+
|
|
77
|
+
:return: a `plotly` gantt chart as rgb array.
|
|
78
|
+
|
|
79
|
+
color example
|
|
80
|
+
|
|
81
|
+
import numpy as np
|
|
82
|
+
|
|
83
|
+
c_map = plt.cm.get_cmap("jet") # select the desired cmap
|
|
84
|
+
arr = np.linspace(0, 1, 10) # create a list with numbers from 0 to 1 with n items
|
|
85
|
+
colors = {resource: c_map(val) for resource, val in enumerate(arr)}
|
|
86
|
+
"""
|
|
87
|
+
w, h = shutil.get_terminal_size((80, 20)) # enable emulate output in terminal ...
|
|
88
|
+
|
|
89
|
+
c_map = matplotlib.colormaps.get_cmap(c_map) # select the desired cmap
|
|
90
|
+
arr = np.linspace(0, 1, n_machines) # create a list with numbers from 0 to 1 with n items
|
|
91
|
+
machine_colors = {m_id: c_map(val) for m_id, val in enumerate(arr)}
|
|
92
|
+
colors = {f"Machine {m_id}": (r, g, b) for m_id, (r, g, b, a) in machine_colors.items()}
|
|
93
|
+
|
|
94
|
+
if len(df) > 0:
|
|
95
|
+
machines = sorted(df['Resource'].unique())
|
|
96
|
+
jobs = df['Task'].unique()
|
|
97
|
+
jobs.sort()
|
|
98
|
+
else:
|
|
99
|
+
jobs, machines = None, None
|
|
100
|
+
|
|
101
|
+
len_prefix = 10
|
|
102
|
+
len_suffix = 15
|
|
103
|
+
|
|
104
|
+
x_pixels = w - len_prefix - len_suffix
|
|
105
|
+
x_max = df['Finish'].max() + 1 if len(df) > 0 else x_pixels
|
|
106
|
+
if x_pixels < 0:
|
|
107
|
+
log.warn("terminal window to small")
|
|
108
|
+
return
|
|
109
|
+
|
|
110
|
+
x_axis_tick_small = "╤════"
|
|
111
|
+
x_axis_tick_big = "╦════"
|
|
112
|
+
len_tick = len(x_axis_tick_big)
|
|
113
|
+
num_hole_ticks = x_pixels // len_tick
|
|
114
|
+
len_last_tick = x_pixels % len_tick
|
|
115
|
+
x_axis = "".join([
|
|
116
|
+
f"{'':<{len_prefix - 1}}╚",
|
|
117
|
+
*[x_axis_tick_big if i % 5 == 0 else x_axis_tick_small for i in range(num_hole_ticks)],
|
|
118
|
+
"═" * len_last_tick + "╝"
|
|
119
|
+
])
|
|
120
|
+
x_chart_frame_top = "".join([
|
|
121
|
+
f"{'':<{len_prefix - 1}}╔",
|
|
122
|
+
"═" * x_pixels,
|
|
123
|
+
"╗"
|
|
124
|
+
])
|
|
125
|
+
|
|
126
|
+
x_interval_increment5 = x_max / num_hole_ticks
|
|
127
|
+
x_interval_increment1 = x_max / x_pixels
|
|
128
|
+
|
|
129
|
+
x_axis_label = "".join([
|
|
130
|
+
f"{'':<{len_prefix}}",
|
|
131
|
+
*[
|
|
132
|
+
f"{f'{i * x_interval_increment5:.1f}':<5}" if i % 5 == 0 else f"{'':<5}"
|
|
133
|
+
for i in range(num_hole_ticks)
|
|
134
|
+
]
|
|
135
|
+
])
|
|
136
|
+
|
|
137
|
+
rows = []
|
|
138
|
+
if len(df) > 0:
|
|
139
|
+
for j, m in itertools.zip_longest(jobs, machines):
|
|
140
|
+
matching_tasks = df.loc[df['Task'] == j].iterrows()
|
|
141
|
+
chart_str = [i * x_interval_increment1 for i in range(x_pixels)]
|
|
142
|
+
for _, (_, start, finish, resource) in matching_tasks:
|
|
143
|
+
chart_str = [
|
|
144
|
+
f"{rgb_color_sequence(*colors[resource])}█"
|
|
145
|
+
if not isinstance(v, str) and start <= v <= finish else v for v in chart_str
|
|
146
|
+
]
|
|
147
|
+
prefix = f"{f'{j}':<{len_prefix - 1}}║" if j else f"{'':<{len_prefix - 1}}║"
|
|
148
|
+
colored_block = wrap_with_color_codes("█", *colors[m]) if m else None
|
|
149
|
+
suffix = f"{f'║ {m}':<{len_suffix - 1}}" + f"{colored_block}" if m else f"{f'║':<{len_suffix}}"
|
|
150
|
+
|
|
151
|
+
chart_str = [" " if not isinstance(v, str) else v for v in chart_str]
|
|
152
|
+
chart_str = "".join(chart_str)
|
|
153
|
+
rows.append(f"{prefix}{chart_str}{CEND}{suffix}")
|
|
154
|
+
else:
|
|
155
|
+
rows = ["".join([f"{f'':<{len_prefix - 1}}║", " " * x_pixels, "║"])]
|
|
156
|
+
|
|
157
|
+
gant_str = "\n".join([
|
|
158
|
+
x_chart_frame_top,
|
|
159
|
+
*rows,
|
|
160
|
+
x_axis,
|
|
161
|
+
x_axis_label
|
|
162
|
+
])
|
|
163
|
+
print(gant_str)
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def graph_console(df: pd.DataFrame, jsp_instance: np.ndarray, c_map="rainbow"):
|
|
167
|
+
w, _ = shutil.get_terminal_size((80, 20))
|
|
168
|
+
_, n_jobs, n_machines = jsp_instance.shape
|
|
169
|
+
|
|
170
|
+
len_prefix = 10
|
|
171
|
+
len_suffix = 15
|
|
172
|
+
|
|
173
|
+
machine_order = jsp_instance[0]
|
|
174
|
+
|
|
175
|
+
if w < 2 * n_jobs + len_prefix + len_suffix:
|
|
176
|
+
log.warning("terminal window to small")
|
|
177
|
+
return
|
|
178
|
+
|
|
179
|
+
c_map = matplotlib.colormaps.get_cmap(c_map) # select the desired cmap
|
|
180
|
+
arr = np.linspace(0, 1, n_machines) # create a list with numbers from 0 to 1 with n items
|
|
181
|
+
machine_colors = {m_id: c_map(val) for m_id, val in enumerate(arr)}
|
|
182
|
+
colors = {f"Machine {m_id}": (r, g, b) for m_id, (r, g, b, a) in machine_colors.items()}
|
|
183
|
+
|
|
184
|
+
machine_strings = [
|
|
185
|
+
f"{m :>{len_suffix - 5}} {wrap_with_color_codes('█', r, g, b)}"
|
|
186
|
+
for m, (r, g, b) in colors.items()
|
|
187
|
+
]
|
|
188
|
+
|
|
189
|
+
def task_is_in_df(job: int, machine: int):
|
|
190
|
+
return any((df['Task'] == f"Job {job}") & (df['Resource'] == f"Machine {machine}"))
|
|
191
|
+
pass
|
|
192
|
+
|
|
193
|
+
for j, m_str in itertools.zip_longest(range(n_jobs), machine_strings):
|
|
194
|
+
row = f"Job {j}" if j is not None else ""
|
|
195
|
+
row = f"{row:<{len_prefix}}"
|
|
196
|
+
for task_in_job in range(n_machines):
|
|
197
|
+
|
|
198
|
+
if j is not None:
|
|
199
|
+
machine_of_task = machine_order[j][task_in_job]
|
|
200
|
+
node_str = "●" if task_is_in_df(job=j, machine=machine_of_task) else "◯"
|
|
201
|
+
node_str = wrap_with_color_codes(node_str, *colors[f"Machine {machine_of_task}"])
|
|
202
|
+
if task_in_job < n_machines - 1:
|
|
203
|
+
node_str += "-"
|
|
204
|
+
else:
|
|
205
|
+
node_str = " "
|
|
206
|
+
if task_in_job < n_machines - 1:
|
|
207
|
+
node_str += " "
|
|
208
|
+
row += node_str
|
|
209
|
+
print("".join([row, " " * 4, m_str if m_str is not None else ""]))
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import cv2
|
|
2
|
+
import signal
|
|
3
|
+
|
|
4
|
+
import pandas as pd
|
|
5
|
+
import numpy.typing as npt
|
|
6
|
+
|
|
7
|
+
from jsp_vis.rgb_array import gantt_chart_rgb_array
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def handler_stop_signals(*_) -> None:
|
|
11
|
+
"""
|
|
12
|
+
closes all `cv2`-windows when the process is killed
|
|
13
|
+
"""
|
|
14
|
+
cv2.destroyAllWindows()
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
signal.signal(signal.SIGINT, handler_stop_signals)
|
|
18
|
+
signal.signal(signal.SIGTERM, handler_stop_signals)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def render_rgb_array(vis: npt.NDArray, *, window_title: str = "Job Shop Scheduling", wait: int = 1) -> None:
|
|
22
|
+
"""
|
|
23
|
+
renders a rgb-array in an `cv2` window.
|
|
24
|
+
the window will remain open for `:param wait:` ms or till the user presses any key.
|
|
25
|
+
|
|
26
|
+
:param vis: the rgb-array to render.
|
|
27
|
+
:param window_title: the title of the `cv2`-window
|
|
28
|
+
:param wait: time in ms that the `cv2`-window is open.
|
|
29
|
+
if `None`, then the window will remain open till a keyboard occurs.
|
|
30
|
+
|
|
31
|
+
:return:
|
|
32
|
+
"""
|
|
33
|
+
vis = cv2.cvtColor(vis, cv2.COLOR_RGB2BGR)
|
|
34
|
+
cv2.imshow(window_title, vis)
|
|
35
|
+
# https://stackoverflow.com/questions/64061721/opencv-to-close-the-window-on-a-specific-key
|
|
36
|
+
k = cv2.waitKey(wait) & 0xFF
|
|
37
|
+
if k == 27: # wait for ESC key to exit
|
|
38
|
+
cv2.destroyAllWindows()
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def render_gantt_in_window(df: pd.DataFrame, *, n_machines: int, gantt_chart_rgb_array_kwargs: dict | None =None,
|
|
42
|
+
**render_kwargs: dict) -> None:
|
|
43
|
+
"""
|
|
44
|
+
wrapper for the `gantt_chart_rgb_array`- and `render_rgb_array`-methods
|
|
45
|
+
|
|
46
|
+
:param df: parameter for `gantt_chart_rgb_array`
|
|
47
|
+
:param n_machines: parameter for `gantt_chart_rgb_array`
|
|
48
|
+
:param render_kwargs: additional parameters for `render_rgb_array`
|
|
49
|
+
|
|
50
|
+
:return: None
|
|
51
|
+
"""
|
|
52
|
+
if gantt_chart_rgb_array_kwargs is None:
|
|
53
|
+
gantt_chart_rgb_array_kwargs = {}
|
|
54
|
+
vis = gantt_chart_rgb_array(df=df, n_machines=n_machines, **gantt_chart_rgb_array_kwargs)
|
|
55
|
+
render_rgb_array(vis, **render_kwargs)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
if __name__ == '__main__':
|
|
59
|
+
df = [
|
|
60
|
+
{'Task': 'Job 0', 'Start': 5, 'Finish': 16, 'Resource': 'Machine 0'},
|
|
61
|
+
{'Task': 'Job 0', 'Start': 28, 'Finish': 31, 'Resource': 'Machine 1'},
|
|
62
|
+
{'Task': 'Job 0', 'Start': 31, 'Finish': 34, 'Resource': 'Machine 2'},
|
|
63
|
+
{'Task': 'Job 0', 'Start': 34, 'Finish': 46, 'Resource': 'Machine 3'},
|
|
64
|
+
{'Task': 'Job 1', 'Start': 0, 'Finish': 5, 'Resource': 'Machine 0'},
|
|
65
|
+
{'Task': 'Job 1', 'Start': 5, 'Finish': 21, 'Resource': 'Machine 2'},
|
|
66
|
+
{'Task': 'Job 1', 'Start': 21, 'Finish': 28, 'Resource': 'Machine 1'},
|
|
67
|
+
{'Task': 'Job 1', 'Start': 28, 'Finish': 32, 'Resource': 'Machine 3'}
|
|
68
|
+
]
|
|
69
|
+
render_gantt_in_window(pd.DataFrame(df), n_machines=4, wait=None)
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import cv2
|
|
2
|
+
|
|
3
|
+
import pandas as pd
|
|
4
|
+
import numpy as np
|
|
5
|
+
|
|
6
|
+
import matplotlib.pyplot as plt
|
|
7
|
+
import matplotlib as mpl
|
|
8
|
+
import plotly.figure_factory as ff
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def gantt_chart_rgb_array(df: pd.DataFrame, n_machines: int, *,
|
|
12
|
+
c_map="rainbow",
|
|
13
|
+
dpi=80,
|
|
14
|
+
width=7.5,
|
|
15
|
+
height=5,
|
|
16
|
+
show_colorbar=True,
|
|
17
|
+
index_col='Resource',
|
|
18
|
+
group_tasks=True,
|
|
19
|
+
xaxis_type='linear') -> np.ndarray:
|
|
20
|
+
c_map = mpl.colormaps.get_cmap(c_map) # select the desired cmap
|
|
21
|
+
arr = np.linspace(0, 1, n_machines) # create a list with numbers from 0 to 1 with n items
|
|
22
|
+
machine_colors = {m_id: c_map(val) for m_id, val in enumerate(arr)}
|
|
23
|
+
colors = {f"Machine {m_id}": (r, g, b) for m_id, (r, g, b, a) in machine_colors.items()}
|
|
24
|
+
|
|
25
|
+
plt.figure(dpi=dpi)
|
|
26
|
+
plt.axis("off")
|
|
27
|
+
plt.tight_layout()
|
|
28
|
+
|
|
29
|
+
fig = mpl.pyplot.gcf()
|
|
30
|
+
fig.set_size_inches(width, height)
|
|
31
|
+
|
|
32
|
+
# Gantt chart
|
|
33
|
+
width, height = fig.canvas.get_width_height()
|
|
34
|
+
if not len(df):
|
|
35
|
+
df = pd.DataFrame([{"Task": "Job 0", "Start": 0, "Finish": 0, "Resource": "Machine 0"}])
|
|
36
|
+
fig = ff.create_gantt(df=df, show_colorbar=show_colorbar, index_col=index_col, group_tasks=group_tasks,
|
|
37
|
+
colors=colors)
|
|
38
|
+
fig.update_layout(xaxis_type=xaxis_type)
|
|
39
|
+
|
|
40
|
+
img_str = fig.to_image(format="jpg", width=width, height=height)
|
|
41
|
+
|
|
42
|
+
nparr = np.frombuffer(img_str, np.uint8)
|
|
43
|
+
img = cv2.imdecode(nparr, cv2.IMREAD_COLOR) # cv2.IMREAD_COLOR in OpenCV 3.1
|
|
44
|
+
img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
|
|
45
|
+
|
|
46
|
+
# clear current frame
|
|
47
|
+
plt.clf()
|
|
48
|
+
plt.close('all')
|
|
49
|
+
return img
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: jsp-vis
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: A flexible enviorment for job shop scheduling using the disjunctive graph apporach.
|
|
5
|
+
Author: Alexander Nasuta
|
|
6
|
+
Author-email: Alexander Nasuta <alexander.nasuta@ima.rwth-aachen.de>
|
|
7
|
+
License: MIT License
|
|
8
|
+
|
|
9
|
+
Copyright (c) 2024 Alexander Nasuta
|
|
10
|
+
|
|
11
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
12
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
13
|
+
in the Software without restriction, including without limitation the rights
|
|
14
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
15
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
16
|
+
furnished to do so, subject to the following conditions:
|
|
17
|
+
|
|
18
|
+
The above copyright notice and this permission notice shall be included in all
|
|
19
|
+
copies or substantial portions of the Software.
|
|
20
|
+
|
|
21
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
22
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
23
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
24
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
25
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
26
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
27
|
+
SOFTWARE.
|
|
28
|
+
Project-URL: Homepage, https://github.com/Alexander-Nasuta/pypitemplate
|
|
29
|
+
Platform: unix
|
|
30
|
+
Platform: linux
|
|
31
|
+
Platform: osx
|
|
32
|
+
Platform: cygwin
|
|
33
|
+
Platform: win32
|
|
34
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
35
|
+
Classifier: Programming Language :: Python
|
|
36
|
+
Classifier: Programming Language :: Python :: 3
|
|
37
|
+
Requires-Python: >=3.9
|
|
38
|
+
Description-Content-Type: text/markdown
|
|
39
|
+
License-File: LICENSE
|
|
40
|
+
Requires-Dist: opencv-python
|
|
41
|
+
Requires-Dist: plotly
|
|
42
|
+
Requires-Dist: matplotlib
|
|
43
|
+
Requires-Dist: numpy
|
|
44
|
+
Requires-Dist: pandas
|
|
45
|
+
Requires-Dist: kaleido
|
|
46
|
+
Provides-Extra: dev
|
|
47
|
+
Requires-Dist: pip-tools; extra == "dev"
|
|
48
|
+
Requires-Dist: pytest; extra == "dev"
|
|
49
|
+
Requires-Dist: pytest-cov; extra == "dev"
|
|
50
|
+
Requires-Dist: tox; extra == "dev"
|
|
51
|
+
Requires-Dist: twine; extra == "dev"
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
<div id="top"></div>
|
|
56
|
+
|
|
57
|
+
<!-- PROJECT LOGO -->
|
|
58
|
+
<br />
|
|
59
|
+
<div align="center">
|
|
60
|
+
<!--
|
|
61
|
+
<a href="https://cybernetics-lab.de/">
|
|
62
|
+
<img src="https://github.com/Alexander-Nasuta/graph-jsp-env/raw/master/resources/readme_images/logo.png" alt="Logo" height="80">
|
|
63
|
+
</a>
|
|
64
|
+
-->
|
|
65
|
+
|
|
66
|
+
<h1 align="center">
|
|
67
|
+
Job Shop Scheduling Problem Visualisations
|
|
68
|
+
</h1>
|
|
69
|
+
|
|
70
|
+
<!--
|
|
71
|
+
<a>
|
|
72
|
+
<img src="https://github.com/Alexander-Nasuta/graph-jsp-env/raw/master/resources/readme_images/graph_jsp_tikz.png" alt="Logo" height="180">
|
|
73
|
+
</a>
|
|
74
|
+
-->
|
|
75
|
+
|
|
76
|
+
</div>
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
- **Github**: https://github.com/Alexander-Nasuta/jsp-vis
|
|
80
|
+
|
|
81
|
+
- **PyPi**:
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
# About The Project
|
|
85
|
+
Ths project provides visualisation for the Job Shop Scheduling Problem (JSP).
|
|
86
|
+
This is focused on Gantt charts. The input date for the visualisation is inspired by [plotly's Gantt chart api](https://plotly.com/python/gantt/).
|
|
87
|
+
`jsp-vis` is a standalone package and in designed to be used in combination with a JSP-reinforcement learning environments that follow the [Gymnasium Environment](https://gymnasium.farama.org/) standard.
|
|
88
|
+
The render function of the environment can be used to render the Gantt chart.
|
|
89
|
+
Typically the render function can implement different modes like `human`, `rgb_array` or `ansi` rendering.
|
|
90
|
+
The `jsp-vis` package offers three different visualisations: console visualisation, rgb_array visualisation and window visualisation.
|
|
91
|
+
The window visualisation is essentially only rendering the rgb_array visualisation in a window using OpenCV.
|
|
92
|
+
The console visualisation might be used for the `asni` mode of a render function, the rgb_array visualisation for the `rgb_array` mode and the window visualisation for the `human` mode.
|
|
93
|
+
|
|
94
|
+
# Installation
|
|
95
|
+
|
|
96
|
+
Install the package with pip:
|
|
97
|
+
```
|
|
98
|
+
pip install todo
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
# Minimal Working Example: console visualisation
|
|
102
|
+
|
|
103
|
+
```python
|
|
104
|
+
import pandas
|
|
105
|
+
from jsp_vis.console import gantt_chart_console
|
|
106
|
+
import pandas as pd
|
|
107
|
+
|
|
108
|
+
df = pd.DataFrame([
|
|
109
|
+
{'Task': 'Job 0', 'Start': 5, 'Finish': 16, 'Resource': 'Machine 0'},
|
|
110
|
+
{'Task': 'Job 0', 'Start': 28, 'Finish': 31, 'Resource': 'Machine 1'},
|
|
111
|
+
{'Task': 'Job 0', 'Start': 31, 'Finish': 34, 'Resource': 'Machine 2'},
|
|
112
|
+
{'Task': 'Job 0', 'Start': 34, 'Finish': 46, 'Resource': 'Machine 3'},
|
|
113
|
+
{'Task': 'Job 1', 'Start': 0, 'Finish': 5, 'Resource': 'Machine 0'},
|
|
114
|
+
{'Task': 'Job 1', 'Start': 5, 'Finish': 21, 'Resource': 'Machine 2'},
|
|
115
|
+
{'Task': 'Job 1', 'Start': 21, 'Finish': 28, 'Resource': 'Machine 1'},
|
|
116
|
+
{'Task': 'Job 1', 'Start': 28, 'Finish': 32, 'Resource': 'Machine 3'}
|
|
117
|
+
])
|
|
118
|
+
num_of_machines = 4
|
|
119
|
+
|
|
120
|
+
gantt_chart_console(df, num_of_machines)
|
|
121
|
+
```
|
|
122
|
+
The code above will render the following Gantt chart in the console:
|
|
123
|
+
|
|
124
|
+

|
|
125
|
+
|
|
126
|
+
# Minimal Working Example: console visualisation
|
|
127
|
+
|
|
128
|
+
```python
|
|
129
|
+
from jsp_vis.cv2_window import render_gantt_in_window
|
|
130
|
+
import pandas as pd
|
|
131
|
+
|
|
132
|
+
df = pd.DataFrame([
|
|
133
|
+
{'Task': 'Job 0', 'Start': 5, 'Finish': 16, 'Resource': 'Machine 0'},
|
|
134
|
+
{'Task': 'Job 0', 'Start': 28, 'Finish': 31, 'Resource': 'Machine 1'},
|
|
135
|
+
{'Task': 'Job 0', 'Start': 31, 'Finish': 34, 'Resource': 'Machine 2'},
|
|
136
|
+
{'Task': 'Job 0', 'Start': 34, 'Finish': 46, 'Resource': 'Machine 3'},
|
|
137
|
+
{'Task': 'Job 1', 'Start': 0, 'Finish': 5, 'Resource': 'Machine 0'},
|
|
138
|
+
{'Task': 'Job 1', 'Start': 5, 'Finish': 21, 'Resource': 'Machine 2'},
|
|
139
|
+
{'Task': 'Job 1', 'Start': 21, 'Finish': 28, 'Resource': 'Machine 1'},
|
|
140
|
+
{'Task': 'Job 1', 'Start': 28, 'Finish': 32, 'Resource': 'Machine 3'}
|
|
141
|
+
])
|
|
142
|
+
num_of_machines = 4
|
|
143
|
+
|
|
144
|
+
render_gantt_in_window(
|
|
145
|
+
df=df,
|
|
146
|
+
n_machines=num_of_machines,
|
|
147
|
+
wait=2000 # time in ms that the `cv2`-window is open.
|
|
148
|
+
# wait=None # ''None'' will keep the window open till a keyboard occurs.
|
|
149
|
+
)
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
The code above will render the following Gantt chart in the console:
|
|
153
|
+
|
|
154
|
+

|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
# More Examples
|
|
158
|
+
For more examples you can have a look at the test files in the `tests` directory.
|
|
159
|
+
Every visualisation has its own test file and is tested on two different jsp instances defined in the `conftest.py`.
|
|
160
|
+
|
|
161
|
+
# License
|
|
162
|
+
|
|
163
|
+
Distributed under the MIT License. See `LICENSE.txt` for more information.
|
|
164
|
+
|
|
165
|
+
<!-- MARKDOWN LINKS & IMAGES todo: add Github, Linked in etc.-->
|
|
166
|
+
<!-- https://www.markdownguide.org/basic-syntax/#reference-style-links -->
|
|
167
|
+
[screenshot]: resources/readme_images/screenshot.png
|
|
168
|
+
|
|
169
|
+
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
MANIFEST.in
|
|
3
|
+
README.md
|
|
4
|
+
pyproject.toml
|
|
5
|
+
setup.cfg
|
|
6
|
+
setup.py
|
|
7
|
+
src/jsp_vis/__init__.py
|
|
8
|
+
src/jsp_vis/console.py
|
|
9
|
+
src/jsp_vis/cv2_window.py
|
|
10
|
+
src/jsp_vis/rgb_array.py
|
|
11
|
+
src/jsp_vis.egg-info/PKG-INFO
|
|
12
|
+
src/jsp_vis.egg-info/SOURCES.txt
|
|
13
|
+
src/jsp_vis.egg-info/dependency_links.txt
|
|
14
|
+
src/jsp_vis.egg-info/not-zip-safe
|
|
15
|
+
src/jsp_vis.egg-info/requires.txt
|
|
16
|
+
src/jsp_vis.egg-info/top_level.txt
|
|
17
|
+
tests/test_render_console.py
|
|
18
|
+
tests/test_render_cv2_window.py
|
|
19
|
+
tests/test_render_rgb_array.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
jsp_vis
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import pandas as pd
|
|
2
|
+
|
|
3
|
+
from jsp_vis.console import gantt_chart_console, graph_console
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def test_gantt_console(custom_jsp_instance_df, custom_jsp_n_machines):
|
|
7
|
+
gantt_chart_console(pd.DataFrame(custom_jsp_instance_df), custom_jsp_n_machines)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def test_gantt_console_ft06(ft06_df, ft06_n_machines):
|
|
11
|
+
gantt_chart_console(pd.DataFrame(ft06_df), ft06_n_machines)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def test_graph_console(custom_jsp_instance, custom_jsp_instance_df):
|
|
15
|
+
graph_console(
|
|
16
|
+
df=pd.DataFrame(custom_jsp_instance_df),
|
|
17
|
+
jsp_instance=custom_jsp_instance,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def test_graph_console_ft06(ft06, ft06_df):
|
|
22
|
+
graph_console(
|
|
23
|
+
df=pd.DataFrame(ft06_df),
|
|
24
|
+
jsp_instance=ft06,
|
|
25
|
+
)
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@pytest.mark.skipif(sys.platform == 'linux',
|
|
7
|
+
reason="the Github Actions runner is configured to run on Linux. "
|
|
8
|
+
"The runner does not have a UI, so the test will fail. ")
|
|
9
|
+
def test_render_cv2_window(custom_jsp_instance_df, custom_jsp_n_machines):
|
|
10
|
+
from jsp_vis.cv2_window import render_gantt_in_window
|
|
11
|
+
|
|
12
|
+
render_gantt_in_window(
|
|
13
|
+
df=custom_jsp_instance_df,
|
|
14
|
+
n_machines=custom_jsp_n_machines,
|
|
15
|
+
wait=1 # time in ms that the `cv2`-window is open.
|
|
16
|
+
# wait=None # ''None'' will keep the window open till a keyboard occurs.
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
@pytest.mark.skipif(sys.platform == 'linux',
|
|
20
|
+
reason="the Github Actions runner is configured to run on Linux. "
|
|
21
|
+
"The runner does not have a UI, so the test will fail. ")
|
|
22
|
+
def test_render_cv2_window(ft06_df, ft06_n_machines):
|
|
23
|
+
from jsp_vis.cv2_window import render_gantt_in_window
|
|
24
|
+
|
|
25
|
+
render_gantt_in_window(
|
|
26
|
+
df=ft06_df,
|
|
27
|
+
n_machines=ft06_n_machines,
|
|
28
|
+
wait=1 # time in ms that the `cv2`-window is open.
|
|
29
|
+
# wait=None # ''None'' will keep the window open till a keyboard occurs.
|
|
30
|
+
)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def test_rgb_array_custom_jsp_instance(custom_jsp_instance_df, custom_jsp_n_machines):
|
|
5
|
+
from jsp_vis.rgb_array import gantt_chart_rgb_array
|
|
6
|
+
|
|
7
|
+
vis = gantt_chart_rgb_array(custom_jsp_instance_df, custom_jsp_n_machines)
|
|
8
|
+
assert type(vis) == type(np.array([]))
|
|
9
|
+
assert vis.shape == (400, 600, 3)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def test_rgb_array_ft06(ft06_df, ft06_n_machines):
|
|
13
|
+
from jsp_vis.rgb_array import gantt_chart_rgb_array
|
|
14
|
+
|
|
15
|
+
vis = gantt_chart_rgb_array(ft06_df, ft06_n_machines)
|
|
16
|
+
assert type(vis) == type(np.array([]))
|
|
17
|
+
assert vis.shape == (400, 600, 3)
|