사업/python 으로 모든걸 할수있다

google ortools routing 결과 시각화

밍이의 꿈 2020. 3. 24. 18:34

Google ortools 는 굉장히 파워풀하면서도 간단한 최적화 툴입니다.

그 중 경로를 찾는 routing 문제에 대한 예제도 굉장히 간단하게 제공되어있습니다.

 

그럼 오늘은 google ortools로 찾은 최적 경로를 시각화하는 방법에 대해 알아보겠습니다. 

 

https://github.com/google/or-tools/blob/master/ortools/constraint_solver/doc/routing_svg.py

 

google/or-tools

Google's Operations Research tools:. Contribute to google/or-tools development by creating an account on GitHub.

github.com

이 경로로 들어가면 svg파일이 생성을 위한 코드를 다운받을 수 있습니다. 

jupyter notebook을 이용하면 오류가 나서 pycharm을 써보겠습니다.

실행을 시켜보면 다음과 같이 svg코드가 콘솔창에 print이 되고요. 

<svg xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" version="1.1"
width="1022.6666666666666" height="750.6666666666666" viewBox="-55.333333333333336 -55.333333333333336 1022.6666666666666 750.6666666666666">
<!-- Need this definition to make an arrow marker, from https://www.w3.org/TR/svg-markers/ -->
<defs>
  <marker id="arrow_blue" viewBox="0 0 16 16" refX="8" refY="8" markerUnits="strokeWidth" markerWidth="5" markerHeight="5" orient="auto">
    <path d="M 0 0 L 16 8 L 0 16 z" stroke="none" fill="#4285F4"/>
  </marker>
  <marker id="arrow_red" viewBox="0 0 16 16" refX="8" refY="8" markerUnits="strokeWidth" markerWidth="5" markerHeight="5" orient="auto">
    <path d="M 0 0 L 16 8 L 0 16 z" stroke="none" fill="#EA4335"/>
  </marker>
  <marker id="arrow_yellow" viewBox="0 0 16 16" refX="8" refY="8" markerUnits="strokeWidth" markerWidth="5" markerHeight="5" orient="auto">
    <path d="M 0 0 L 16 8 L 0 16 z" stroke="none" fill="#FBBC05"/>
  </marker>
  <marker id="arrow_green" viewBox="0 0 16 16" refX="8" refY="8" markerUnits="strokeWidth" markerWidth="5" markerHeight="5" orient="auto">
    <path d="M 0 0 L 16 8 L 0 16 z" stroke="none" fill="#34A853"/>
  </marker>
  <marker id="arrow_black" viewBox="0 0 16 16" refX="8" refY="8" markerUnits="strokeWidth" markerWidth="5" markerHeight="5" orient="auto">
    <path d="M 0 0 L 16 8 L 0 16 z" stroke="none" fill="#101010"/>
  </marker>
  <marker id="arrow_white" viewBox="0 0 16 16" refX="8" refY="8" markerUnits="strokeWidth" markerWidth="5" markerHeight="5" orient="auto">
    <path d="M 0 0 L 16 8 L 0 16 z" stroke="none" fill="#FFFFFF"/>
  </marker>
</defs>
<!-- Print city streets -->
<line x1="0" y1="0" x2="912" y2="0" style="stroke-width:2;stroke:#969696;fill:none"/>
<line x1="0" y1="80" x2="912" y2="80" style="stroke-width:2;stroke:#969696;fill:none"/>
<line x1="0" y1="160" x2="912" y2="160" style="stroke-width:2;stroke:#969696;fill:none"/>
<line x1="0" y1="240" x2="912" y2="240" style="stroke-width:2;stroke:#969696;fill:none"/>
<line x1="0" y1="320" x2="912" y2="320" style="stroke-width:2;stroke:#969696;fill:none"/>
<line x1="0" y1="400" x2="912" y2="400" style="stroke-width:2;stroke:#969696;fill:none"/>
<line x1="0" y1="480" x2="912" y2="480" style="stroke-width:2;stroke:#969696;fill:none"/>
<line x1="0" y1="560" x2="912" y2="560" style="stroke-width:2;stroke:#969696;fill:none"/>
<line x1="0" y1="640" x2="912" y2="640" style="stroke-width:2;stroke:#969696;fill:none"/>
<line x1="0" y1="0" x2="0" y2="640" style="stroke-width:2;stroke:#969696;fill:none"/>
<line x1="114" y1="0" x2="114" y2="640" style="stroke-width:2;stroke:#969696;fill:none"/>
<line x1="228" y1="0" x2="228" y2="640" style="stroke-width:2;stroke:#969696;fill:none"/>
<line x1="342" y1="0" x2="342" y2="640" style="stroke-width:2;stroke:#969696;fill:none"/>
<line x1="456" y1="0" x2="456" y2="640" style="stroke-width:2;stroke:#969696;fill:none"/>
<line x1="570" y1="0" x2="570" y2="640" style="stroke-width:2;stroke:#969696;fill:none"/>
<line x1="684" y1="0" x2="684" y2="640" style="stroke-width:2;stroke:#969696;fill:none"/>
<line x1="798" y1="0" x2="798" y2="640" style="stroke-width:2;stroke:#969696;fill:none"/>
<line x1="912" y1="0" x2="912" y2="640" style="stroke-width:2;stroke:#969696;fill:none"/>
<!-- Print locations -->
<circle cx="228" cy="0" r="26.666666666666668" style="stroke-width:6.666666666666667;stroke:#4285F4;fill:white"/>
<text x="228" y="0" dy="8.88888888888889" style="text-anchor:middle;font-weight:bold;font-size:26.666666666666668;stroke:none;fill:#4285F4">1</text>
<circle cx="912" cy="0" r="26.666666666666668" style="stroke-width:6.666666666666667;stroke:#4285F4;fill:white"/>
<text x="912" y="0" dy="8.88888888888889" style="text-anchor:middle;font-weight:bold;font-size:26.666666666666668;stroke:none;fill:#4285F4">2</text>
<circle cx="0" cy="80" r="26.666666666666668" style="stroke-width:6.666666666666667;stroke:#4285F4;fill:white"/>
<text x="0" y="80" dy="8.88888888888889" style="text-anchor:middle;font-weight:bold;font-size:26.666666666666668;stroke:none;fill:#4285F4">3</text>
<circle cx="114" cy="80" r="26.666666666666668" style="stroke-width:6.666666666666667;stroke:#4285F4;fill:white"/>
<text x="114" y="80" dy="8.88888888888889" style="text-anchor:middle;font-weight:bold;font-size:26.666666666666668;stroke:none;fill:#4285F4">4</text>
<circle cx="570" cy="160" r="26.666666666666668" style="stroke-width:6.666666666666667;stroke:#4285F4;fill:white"/>
<text x="570" y="160" dy="8.88888888888889" style="text-anchor:middle;font-weight:bold;font-size:26.666666666666668;stroke:none;fill:#4285F4">5</text>
<circle cx="798" cy="160" r="26.666666666666668" style="stroke-width:6.666666666666667;stroke:#4285F4;fill:white"/>
<text x="798" y="160" dy="8.88888888888889" style="text-anchor:middle;font-weight:bold;font-size:26.666666666666668;stroke:none;fill:#4285F4">6</text>
<circle cx="342" cy="240" r="26.666666666666668" style="stroke-width:6.666666666666667;stroke:#4285F4;fill:white"/>
<text x="342" y="240" dy="8.88888888888889" style="text-anchor:middle;font-weight:bold;font-size:26.666666666666668;stroke:none;fill:#4285F4">7</text>
<circle cx="684" cy="240" r="26.666666666666668" style="stroke-width:6.666666666666667;stroke:#4285F4;fill:white"/>
<text x="684" y="240" dy="8.88888888888889" style="text-anchor:middle;font-weight:bold;font-size:26.666666666666668;stroke:none;fill:#4285F4">8</text>
<circle cx="570" cy="400" r="26.666666666666668" style="stroke-width:6.666666666666667;stroke:#4285F4;fill:white"/>
<text x="570" y="400" dy="8.88888888888889" style="text-anchor:middle;font-weight:bold;font-size:26.666666666666668;stroke:none;fill:#4285F4">9</text>
<circle cx="912" cy="400" r="26.666666666666668" style="stroke-width:6.666666666666667;stroke:#4285F4;fill:white"/>
<text x="912" y="400" dy="8.88888888888889" style="text-anchor:middle;font-weight:bold;font-size:26.666666666666668;stroke:none;fill:#4285F4">10</text>
<circle cx="114" cy="480" r="26.666666666666668" style="stroke-width:6.666666666666667;stroke:#4285F4;fill:white"/>
<text x="114" y="480" dy="8.88888888888889" style="text-anchor:middle;font-weight:bold;font-size:26.666666666666668;stroke:none;fill:#4285F4">11</text>
<circle cx="228" cy="480" r="26.666666666666668" style="stroke-width:6.666666666666667;stroke:#4285F4;fill:white"/>
<text x="228" y="480" dy="8.88888888888889" style="text-anchor:middle;font-weight:bold;font-size:26.666666666666668;stroke:none;fill:#4285F4">12</text>
<circle cx="342" cy="560" r="26.666666666666668" style="stroke-width:6.666666666666667;stroke:#4285F4;fill:white"/>
<text x="342" y="560" dy="8.88888888888889" style="text-anchor:middle;font-weight:bold;font-size:26.666666666666668;stroke:none;fill:#4285F4">13</text>
<circle cx="684" cy="560" r="26.666666666666668" style="stroke-width:6.666666666666667;stroke:#4285F4;fill:white"/>
<text x="684" y="560" dy="8.88888888888889" style="text-anchor:middle;font-weight:bold;font-size:26.666666666666668;stroke:none;fill:#4285F4">14</text>
<circle cx="0" cy="640" r="26.666666666666668" style="stroke-width:6.666666666666667;stroke:#4285F4;fill:white"/>
<text x="0" y="640" dy="8.88888888888889" style="text-anchor:middle;font-weight:bold;font-size:26.666666666666668;stroke:none;fill:#4285F4">15</text>
<circle cx="798" cy="640" r="26.666666666666668" style="stroke-width:6.666666666666667;stroke:#4285F4;fill:white"/>
<text x="798" y="640" dy="8.88888888888889" style="text-anchor:middle;font-weight:bold;font-size:26.666666666666668;stroke:none;fill:#4285F4">16</text>
<!-- Print depot -->
<circle cx="456" cy="320" r="26.666666666666668" style="stroke-width:6.666666666666667;stroke:#101010;fill:white"/>
<text x="456" y="320" dy="8.88888888888889" style="text-anchor:middle;font-weight:bold;font-size:26.666666666666668;stroke:none;fill:#101010">0</text>
</svg>

 

new file을 열어 작성된 svg코드를 붙여넣기하고 저장하면 아래와 같이 그림이 생성됩니다. 

 

다음으로 svg파일을 저장하는 법.

 

sudo python3 경로/svg_generator.py -h

를해보면 

 

sudo python3 경로/svg_generator.py -pd -s > 경로/output.svg

 

[그냥 메모]

완성된 경로로 애니메이션까지 만들고싶다면 아래 경로를 참고하면 됩니다. 

https://activimetrics.com/blog/animating_ortools_routes/