Spaces:
Sleeping
Sleeping
Upload folder using huggingface_hub
Browse files- .gitattributes +5 -0
- .gradio/certificate.pem +31 -0
- Data/inha_boundary.cpg +1 -0
- Data/inha_boundary.dbf +0 -0
- Data/inha_boundary.geojson +172 -0
- Data/inha_boundary.prj +1 -0
- Data/inha_boundary.shp +0 -0
- Data/inha_boundary.shx +0 -0
- Data/inha_boundary_map.png +3 -0
- Data/inha_boundary_polygon.png +3 -0
- Data/inha_boundary_satellite.png +3 -0
- Data/zones.geojson +7 -0
- Data/zones_์ต์ข .geojson +1 -0
- Data/์ธก์ ๊ฒฐ๊ณผ_์์ ์ค.csv +113 -0
- Data/์ธก์ ๊ฒฐ๊ณผ_์ต์ข .csv +113 -0
- README.md +3 -9
- app.py +539 -0
- draw_zones.html +220 -0
- geo.ipynb +0 -0
- pin.py +376 -0
- simul.py +539 -0
- tset.ipynb +1135 -0
- ๋ฐ์ดํฐ ์์ง/inha_boundary_with_points.png +3 -0
- ๋ฐ์ดํฐ ์์ง/๊น๋ค์.csv +92 -0
- ๋ฐ์ดํฐ ์์ง/๊น๋ค์.ipynb +159 -0
- ๋ฐ์ดํฐ ์์ง/์ธก์ ๊ฒฐ๊ณผ.csv +114 -0
- ๋ชจ์ํ์ ๋จ_์ ์์.pdf +3 -0
- ์์ด๋์ด/์ธ์ ์ต๋์.txt +316 -0
.gitattributes
CHANGED
|
@@ -33,3 +33,8 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
+
Data/inha_boundary_map.png filter=lfs diff=lfs merge=lfs -text
|
| 37 |
+
Data/inha_boundary_polygon.png filter=lfs diff=lfs merge=lfs -text
|
| 38 |
+
Data/inha_boundary_satellite.png filter=lfs diff=lfs merge=lfs -text
|
| 39 |
+
๋ฐ์ดํฐ[[:space:]]์์ง/inha_boundary_with_points.png filter=lfs diff=lfs merge=lfs -text
|
| 40 |
+
๋ชจ์ํ์ ๋จ_์ ์์.pdf filter=lfs diff=lfs merge=lfs -text
|
.gradio/certificate.pem
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
-----BEGIN CERTIFICATE-----
|
| 2 |
+
MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw
|
| 3 |
+
TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
|
| 4 |
+
cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4
|
| 5 |
+
WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu
|
| 6 |
+
ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY
|
| 7 |
+
MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc
|
| 8 |
+
h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+
|
| 9 |
+
0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U
|
| 10 |
+
A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW
|
| 11 |
+
T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH
|
| 12 |
+
B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC
|
| 13 |
+
B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv
|
| 14 |
+
KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn
|
| 15 |
+
OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn
|
| 16 |
+
jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw
|
| 17 |
+
qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI
|
| 18 |
+
rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV
|
| 19 |
+
HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq
|
| 20 |
+
hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL
|
| 21 |
+
ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ
|
| 22 |
+
3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK
|
| 23 |
+
NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5
|
| 24 |
+
ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur
|
| 25 |
+
TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC
|
| 26 |
+
jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc
|
| 27 |
+
oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq
|
| 28 |
+
4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA
|
| 29 |
+
mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d
|
| 30 |
+
emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=
|
| 31 |
+
-----END CERTIFICATE-----
|
Data/inha_boundary.cpg
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
UTF-8
|
Data/inha_boundary.dbf
ADDED
|
Binary file (819 Bytes). View file
|
|
|
Data/inha_boundary.geojson
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"type": "FeatureCollection",
|
| 3 |
+
"features": [
|
| 4 |
+
{
|
| 5 |
+
"type": "Feature",
|
| 6 |
+
"geometry": {
|
| 7 |
+
"type": "Polygon",
|
| 8 |
+
"coordinates": [
|
| 9 |
+
[
|
| 10 |
+
[
|
| 11 |
+
126.6504913,
|
| 12 |
+
37.4488536
|
| 13 |
+
],
|
| 14 |
+
[
|
| 15 |
+
126.6502018,
|
| 16 |
+
37.4490381
|
| 17 |
+
],
|
| 18 |
+
[
|
| 19 |
+
126.6501274,
|
| 20 |
+
37.4490101
|
| 21 |
+
],
|
| 22 |
+
[
|
| 23 |
+
126.650006,
|
| 24 |
+
37.449035
|
| 25 |
+
],
|
| 26 |
+
[
|
| 27 |
+
126.6499295,
|
| 28 |
+
37.4493095
|
| 29 |
+
],
|
| 30 |
+
[
|
| 31 |
+
126.6497967,
|
| 32 |
+
37.4495766
|
| 33 |
+
],
|
| 34 |
+
[
|
| 35 |
+
126.6496642,
|
| 36 |
+
37.4498464
|
| 37 |
+
],
|
| 38 |
+
[
|
| 39 |
+
126.6493324,
|
| 40 |
+
37.4504076
|
| 41 |
+
],
|
| 42 |
+
[
|
| 43 |
+
126.6490067,
|
| 44 |
+
37.4509487
|
| 45 |
+
],
|
| 46 |
+
[
|
| 47 |
+
126.649781,
|
| 48 |
+
37.4514003
|
| 49 |
+
],
|
| 50 |
+
[
|
| 51 |
+
126.6495914,
|
| 52 |
+
37.4517312
|
| 53 |
+
],
|
| 54 |
+
[
|
| 55 |
+
126.6501326,
|
| 56 |
+
37.45175
|
| 57 |
+
],
|
| 58 |
+
[
|
| 59 |
+
126.6505999,
|
| 60 |
+
37.4517726
|
| 61 |
+
],
|
| 62 |
+
[
|
| 63 |
+
126.6510982,
|
| 64 |
+
37.4518266
|
| 65 |
+
],
|
| 66 |
+
[
|
| 67 |
+
126.6512838,
|
| 68 |
+
37.4518467
|
| 69 |
+
],
|
| 70 |
+
[
|
| 71 |
+
126.6517828,
|
| 72 |
+
37.4519342
|
| 73 |
+
],
|
| 74 |
+
[
|
| 75 |
+
126.6520048,
|
| 76 |
+
37.4519731
|
| 77 |
+
],
|
| 78 |
+
[
|
| 79 |
+
126.6520885,
|
| 80 |
+
37.4519878
|
| 81 |
+
],
|
| 82 |
+
[
|
| 83 |
+
126.6524237,
|
| 84 |
+
37.4520465
|
| 85 |
+
],
|
| 86 |
+
[
|
| 87 |
+
126.6525693,
|
| 88 |
+
37.452072
|
| 89 |
+
],
|
| 90 |
+
[
|
| 91 |
+
126.6528855,
|
| 92 |
+
37.4521371
|
| 93 |
+
],
|
| 94 |
+
[
|
| 95 |
+
126.6530797,
|
| 96 |
+
37.4521045
|
| 97 |
+
],
|
| 98 |
+
[
|
| 99 |
+
126.6536373,
|
| 100 |
+
37.4518765
|
| 101 |
+
],
|
| 102 |
+
[
|
| 103 |
+
126.6544021,
|
| 104 |
+
37.4516675
|
| 105 |
+
],
|
| 106 |
+
[
|
| 107 |
+
126.6564271,
|
| 108 |
+
37.4511471
|
| 109 |
+
],
|
| 110 |
+
[
|
| 111 |
+
126.6578465,
|
| 112 |
+
37.4507776
|
| 113 |
+
],
|
| 114 |
+
[
|
| 115 |
+
126.6569217,
|
| 116 |
+
37.4492734
|
| 117 |
+
],
|
| 118 |
+
[
|
| 119 |
+
126.6553859,
|
| 120 |
+
37.4466845
|
| 121 |
+
],
|
| 122 |
+
[
|
| 123 |
+
126.6547144,
|
| 124 |
+
37.4468884
|
| 125 |
+
],
|
| 126 |
+
[
|
| 127 |
+
126.6545294,
|
| 128 |
+
37.4469713
|
| 129 |
+
],
|
| 130 |
+
[
|
| 131 |
+
126.6544155,
|
| 132 |
+
37.4470167
|
| 133 |
+
],
|
| 134 |
+
[
|
| 135 |
+
126.653386,
|
| 136 |
+
37.4474272
|
| 137 |
+
],
|
| 138 |
+
[
|
| 139 |
+
126.6527874,
|
| 140 |
+
37.4476634
|
| 141 |
+
],
|
| 142 |
+
[
|
| 143 |
+
126.6507639,
|
| 144 |
+
37.4484888
|
| 145 |
+
],
|
| 146 |
+
[
|
| 147 |
+
126.6505808,
|
| 148 |
+
37.4485626
|
| 149 |
+
],
|
| 150 |
+
[
|
| 151 |
+
126.6505271,
|
| 152 |
+
37.4487565
|
| 153 |
+
],
|
| 154 |
+
[
|
| 155 |
+
126.6504913,
|
| 156 |
+
37.4488536
|
| 157 |
+
]
|
| 158 |
+
]
|
| 159 |
+
]
|
| 160 |
+
},
|
| 161 |
+
"properties": {
|
| 162 |
+
"amenity": "university",
|
| 163 |
+
"education": "university",
|
| 164 |
+
"name": "์ธํ๋ํ๊ต",
|
| 165 |
+
"name:en": "Inha University",
|
| 166 |
+
"name:ja": "ไป่ทๅคงๅญฆๆ ก",
|
| 167 |
+
"name:zh": "ไป่ทๅคงๅญฆ",
|
| 168 |
+
"wikidata": "Q488851"
|
| 169 |
+
}
|
| 170 |
+
}
|
| 171 |
+
]
|
| 172 |
+
}
|
Data/inha_boundary.prj
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]]
|
Data/inha_boundary.shp
ADDED
|
Binary file (748 Bytes). View file
|
|
|
Data/inha_boundary.shx
ADDED
|
Binary file (108 Bytes). View file
|
|
|
Data/inha_boundary_map.png
ADDED
|
Git LFS Details
|
Data/inha_boundary_polygon.png
ADDED
|
Git LFS Details
|
Data/inha_boundary_satellite.png
ADDED
|
Git LFS Details
|
Data/zones.geojson
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{"type":"FeatureCollection","features":[{"type":"Feature","properties":{},
|
| 2 |
+
"geometry":{"type":"Polygon","coordinates":[[[126.653513,37.450119],[126.6545,37.451635],[126.652805,37.452087],[126.649843,37.451652],[126.653513,37.450119]]]}},{"type":"Feature","properties":{},
|
| 3 |
+
"geometry":{"type":"Polygon","coordinates":[[[126.653523,37.450059],[126.65009,37.451431],[126.649232,37.45092],[126.650208,37.449157],[126.650594,37.448807],[126.650659,37.44856],[126.652247,37.447921],[126.653523,37.450059]]]}},{"type":"Feature","properties":{},
|
| 4 |
+
"geometry":{"type":"Polygon","coordinates":[[[126.653588,37.450119],[126.654553,37.451618],[126.656442,37.451116],[126.655476,37.449369],[126.653588,37.450119]]]}},{"type":"Feature","properties":{},
|
| 5 |
+
"geometry":{"type":"Polygon","coordinates":[[[126.65554,37.449327],[126.656474,37.451073],[126.657826,37.450766],[126.656656,37.448875],[126.65554,37.449327]]]}},{"type":"Feature","properties":{},
|
| 6 |
+
"geometry":{"type":"Polygon","coordinates":[[[126.655465,37.449284],[126.653534,37.450021],[126.6523,37.447904],[126.65436,37.447053],[126.655465,37.449284]]]}},{"type":"Feature","properties":{},
|
| 7 |
+
"geometry":{"type":"Polygon","coordinates":[[[126.655519,37.449276],[126.654371,37.447019],[126.655374,37.446703],[126.656662,37.448863],[126.655519,37.449276]]]}}]}
|
Data/zones_์ต์ข
.geojson
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
{"type":"FeatureCollection","features":[{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[126.649822,37.451397],[126.65031,37.451388],[126.653615,37.450085],[126.65215,37.447926],[126.650605,37.44859],[126.650509,37.448871],[126.650208,37.449071],[126.650047,37.449059],[126.64905,37.450941],[126.649822,37.451397]]]}},{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[126.653631,37.450081],[126.65215,37.447926],[126.654484,37.447002],[126.655846,37.449184],[126.653631,37.450081]]]}},{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[126.654478,37.446985],[126.655852,37.449191],[126.656678,37.448875],[126.655374,37.446695],[126.654478,37.446985]]]}},{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[126.656688,37.448875],[126.655401,37.449382],[126.655433,37.449676],[126.656442,37.451145],[126.657842,37.450775],[126.656688,37.448875]]]}},{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[126.655406,37.449378],[126.653529,37.450145],[126.654623,37.45161],[126.656447,37.451145],[126.655417,37.449702],[126.655406,37.449378]]]}},{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[126.653513,37.45014],[126.650316,37.451409],[126.649806,37.451409],[126.649624,37.451707],[126.650686,37.451763],[126.65288,37.452104],[126.654607,37.451601],[126.653513,37.45014]]]}}]}
|
Data/์ธก์ ๊ฒฐ๊ณผ_์์ ์ค.csv
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
lat,lon,dB
|
| 2 |
+
37.4516638,126.6527864,2.0
|
| 3 |
+
37.4517164,126.6525593,30.0
|
| 4 |
+
37.4512905,126.653364,3.0
|
| 5 |
+
37.4514279,126.652793,4.0
|
| 6 |
+
37.4511085,126.6535225,5.0
|
| 7 |
+
37.4510701,126.6531148,6.0
|
| 8 |
+
37.4513171,126.652632,7.0
|
| 9 |
+
37.4513746,126.6517523,24.0
|
| 10 |
+
37.4512256,126.6514948,21.0
|
| 11 |
+
37.4510425,126.6515538,22.0
|
| 12 |
+
37.4510595,126.6526267,8.0
|
| 13 |
+
37.4505606,126.6533733,14.0
|
| 14 |
+
37.4506117,126.6531748,25.0
|
| 15 |
+
37.4514975,126.6537273,28.0
|
| 16 |
+
37.4509056,126.6523755,26.0
|
| 17 |
+
37.450863,126.6535503,11.0
|
| 18 |
+
37.4517914,126.6530514,27.0
|
| 19 |
+
37.4514336,126.6522414,31.0
|
| 20 |
+
37.451127,126.6513348,23.0
|
| 21 |
+
37.4505351,126.6524077,18.0
|
| 22 |
+
37.4507437,126.6524077,16.0
|
| 23 |
+
37.4503988,126.6532875,19.0
|
| 24 |
+
37.4510631,126.6536844,10.0
|
| 25 |
+
37.4515699,126.6534377,29.0
|
| 26 |
+
37.4506799,126.6527081,17.0
|
| 27 |
+
37.4512906,126.6521779,32.0
|
| 28 |
+
37.4509074,126.6521297,15.0
|
| 29 |
+
37.4510309,126.6528753,9.0
|
| 30 |
+
37.4512012,126.6539697,13.0
|
| 31 |
+
37.4507669,126.6537015,12.0
|
| 32 |
+
37.4509659,126.6549157,70.0
|
| 33 |
+
37.4508935,126.6552698,71.0
|
| 34 |
+
37.4508636,126.6558974,69.0
|
| 35 |
+
37.4511234,126.6544705,68.0
|
| 36 |
+
37.4513577,126.6545939,66.0
|
| 37 |
+
37.4505187,126.6540735,67.0
|
| 38 |
+
37.4505826,126.6550338,72.0
|
| 39 |
+
37.4506465,126.6546851,73.0
|
| 40 |
+
37.4498331,126.6546207,90.0
|
| 41 |
+
37.4505016,126.6553824,78.0
|
| 42 |
+
37.4503569,126.6549479,74.0
|
| 43 |
+
37.4500523,126.6554818,79.0
|
| 44 |
+
37.4498416,126.6553664,80.0
|
| 45 |
+
37.449931,126.6551249,84.0
|
| 46 |
+
37.4501013,126.6545617,86.0
|
| 47 |
+
37.4500119,126.6549318,83.0
|
| 48 |
+
37.450259,126.6542881,81.0
|
| 49 |
+
37.4502206,126.6544383,82.0
|
| 50 |
+
37.4501525,126.654213,87.0
|
| 51 |
+
37.4503654,126.655495,77.0
|
| 52 |
+
37.4497777,126.6547173,91.0
|
| 53 |
+
37.4505655,126.655243,76.0
|
| 54 |
+
37.4505698,126.6506188,41.0
|
| 55 |
+
37.4503398,126.6505276,40.0
|
| 56 |
+
37.4506251,126.6509514,42.0
|
| 57 |
+
37.4504676,126.6517346,34.0
|
| 58 |
+
37.4506252,126.6513859,33.0
|
| 59 |
+
37.4499438,126.6512143,38.0
|
| 60 |
+
37.4499054,126.6506027,39.0
|
| 61 |
+
37.4500971,126.651917,37.0
|
| 62 |
+
37.4504548,126.6550123,75.0
|
| 63 |
+
37.4501865,126.6517293,36.0
|
| 64 |
+
37.4502887,126.6514664,35.0
|
| 65 |
+
37.4499437,126.6552644,85.0
|
| 66 |
+
37.4495805,126.6526316,46.0
|
| 67 |
+
37.4492398,126.6524492,48.0
|
| 68 |
+
37.4497977,126.6530554,45.0
|
| 69 |
+
37.4500532,126.6527818,43.0
|
| 70 |
+
37.4499255,126.6529267,44.0
|
| 71 |
+
37.4489332,126.6520201,49.0
|
| 72 |
+
37.4489204,126.6522293,50.0
|
| 73 |
+
37.449474,126.6528355,47.0
|
| 74 |
+
37.4494917,126.6541855,57.0
|
| 75 |
+
37.4499771,126.65462,88.0
|
| 76 |
+
37.4497514,126.6551403,89.0
|
| 77 |
+
37.4486569,126.6536919,53.0
|
| 78 |
+
37.4489806,126.6539548,54.0
|
| 79 |
+
37.4496024,126.654502,58.0
|
| 80 |
+
37.4497003,126.6544966,60.0
|
| 81 |
+
37.4499814,126.6539816,59.0
|
| 82 |
+
37.4495939,126.654797,61.0
|
| 83 |
+
37.4495172,126.6545878,56.0
|
| 84 |
+
37.4493171,126.6552154,62.0
|
| 85 |
+
37.4491893,126.6552101,63.0
|
| 86 |
+
37.4490317,126.6551242,65.0
|
| 87 |
+
37.4491978,126.655076,64.0
|
| 88 |
+
37.4488827,126.6542498,55.0
|
| 89 |
+
37.4479436,126.6529785,51.0
|
| 90 |
+
37.4503967,126.6529463,20.0
|
| 91 |
+
37.4486122,126.6533164,52.0
|
| 92 |
+
37.448078,126.6556807,37.0
|
| 93 |
+
37.4483203,126.6558354,41.0
|
| 94 |
+
37.4483203,126.655504,47.0
|
| 95 |
+
37.44746,126.655224,52.0
|
| 96 |
+
37.4474539,126.6555703,45.0
|
| 97 |
+
37.4476721,126.6550472,55.0
|
| 98 |
+
37.4477023,126.655364,49.0
|
| 99 |
+
37.4477751,126.6551283,56.0
|
| 100 |
+
37.4488898,126.6557323,53.0
|
| 101 |
+
37.4490655,126.6560712,55.0
|
| 102 |
+
37.4489565,126.6559828,54.0
|
| 103 |
+
37.4492533,126.656108,59.0
|
| 104 |
+
37.4494472,126.6563216,63.0
|
| 105 |
+
37.4497198,126.6561375,58.0
|
| 106 |
+
37.4499379,126.656248,56.0
|
| 107 |
+
37.4485566,126.6557102,59.0
|
| 108 |
+
37.4483627,126.6551062,42.0
|
| 109 |
+
37.4506589,126.6570141,51.0
|
| 110 |
+
37.4503802,126.656469,58.0
|
| 111 |
+
37.4505559,126.6571835,48.0
|
| 112 |
+
37.4492957,126.656329,58.0
|
| 113 |
+
37.4495078,126.6564248,61.0
|
Data/์ธก์ ๊ฒฐ๊ณผ_์ต์ข
.csv
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
lat,lon,dB
|
| 2 |
+
37.4516638,126.6527864,50.0
|
| 3 |
+
37.4512905,126.653364,49.0
|
| 4 |
+
37.4514279,126.652793,48.0
|
| 5 |
+
37.4511085,126.6535225,49.0
|
| 6 |
+
37.4510701,126.6531148,48.0
|
| 7 |
+
37.4513171,126.652632,47.0
|
| 8 |
+
37.4510595,126.6526267,50.0
|
| 9 |
+
37.4510309,126.6528753,51.0
|
| 10 |
+
37.4510631,126.6536844,57.0
|
| 11 |
+
37.450863,126.6535503,52.0
|
| 12 |
+
37.4507669,126.6537015,51.0
|
| 13 |
+
37.4512012,126.6539697,47.0
|
| 14 |
+
37.4505606,126.6533733,47.0
|
| 15 |
+
37.4509074,126.6521297,58.0
|
| 16 |
+
37.4507437,126.6524077,49.0
|
| 17 |
+
37.4506799,126.6527081,48.0
|
| 18 |
+
37.4505351,126.6524077,53.0
|
| 19 |
+
37.4503988,126.6532875,47.0
|
| 20 |
+
37.4503967,126.6529463,46.0
|
| 21 |
+
37.4512256,126.6514948,47.0
|
| 22 |
+
37.4510425,126.6515538,46.0
|
| 23 |
+
37.451127,126.6513348,46.0
|
| 24 |
+
37.4513746,126.6517523,42.0
|
| 25 |
+
37.4506117,126.6531748,44.0
|
| 26 |
+
37.4509056,126.6523755,42.0
|
| 27 |
+
37.4517914,126.6530514,55.0
|
| 28 |
+
37.4514975,126.6537273,42.0
|
| 29 |
+
37.4515699,126.6534377,41.0
|
| 30 |
+
37.4517164,126.6525593,39.0
|
| 31 |
+
37.4514336,126.6522414,50.0
|
| 32 |
+
37.4512906,126.6521779,42.0
|
| 33 |
+
37.4506252,126.6513859,53.0
|
| 34 |
+
37.4504676,126.6517346,45.0
|
| 35 |
+
37.4502887,126.6514664,50.0
|
| 36 |
+
37.4501865,126.6517293,47.0
|
| 37 |
+
37.4500971,126.651917,49.0
|
| 38 |
+
37.4499438,126.6512143,50.0
|
| 39 |
+
37.4499054,126.6506027,51.0
|
| 40 |
+
37.4503398,126.6505276,49.0
|
| 41 |
+
37.4505698,126.6506188,43.0
|
| 42 |
+
37.4506251,126.6509514,45.0
|
| 43 |
+
37.4500532,126.6527818,46.0
|
| 44 |
+
37.4499255,126.6529267,43.0
|
| 45 |
+
37.4497977,126.6530554,44.0
|
| 46 |
+
37.4495805,126.6526316,48.0
|
| 47 |
+
37.449474,126.6528355,52.0
|
| 48 |
+
37.4492398,126.6524492,53.0
|
| 49 |
+
37.4489332,126.6520201,50.0
|
| 50 |
+
37.4489204,126.6522293,46.0
|
| 51 |
+
37.4479436,126.6529785,49.0
|
| 52 |
+
37.4486122,126.6533164,46.0
|
| 53 |
+
37.4486569,126.6536919,43.0
|
| 54 |
+
37.4489806,126.6539548,44.0
|
| 55 |
+
37.4488827,126.6542498,47.0
|
| 56 |
+
37.4495172,126.6545878,38.0
|
| 57 |
+
37.4494917,126.6541855,51.0
|
| 58 |
+
37.4496024,126.654502,52.0
|
| 59 |
+
37.4499814,126.6539816,52.0
|
| 60 |
+
37.4497003,126.6544966,46.0
|
| 61 |
+
37.4495939,126.654797,54.0
|
| 62 |
+
37.4493171,126.6552154,46.0
|
| 63 |
+
37.4491893,126.6552101,47.0
|
| 64 |
+
37.4491978,126.655076,45.0
|
| 65 |
+
37.4490317,126.6551242,47.0
|
| 66 |
+
37.4513577,126.6545939,51.0
|
| 67 |
+
37.4505187,126.6540735,53.0
|
| 68 |
+
37.4511234,126.6544705,60.0
|
| 69 |
+
37.4508636,126.6558974,43.0
|
| 70 |
+
37.4509659,126.6549157,44.0
|
| 71 |
+
37.4508935,126.6552698,39.0
|
| 72 |
+
37.4505826,126.6550338,56.0
|
| 73 |
+
37.4506465,126.6546851,52.0
|
| 74 |
+
37.4503569,126.6549479,59.0
|
| 75 |
+
37.4504548,126.6550123,54.0
|
| 76 |
+
37.4505655,126.655243,42.0
|
| 77 |
+
37.4503654,126.655495,47.0
|
| 78 |
+
37.4505016,126.6553824,41.0
|
| 79 |
+
37.4500523,126.6554818,41.0
|
| 80 |
+
37.4498416,126.6553664,46.0
|
| 81 |
+
37.450259,126.6542881,44.0
|
| 82 |
+
37.4502206,126.6544383,43.0
|
| 83 |
+
37.4500119,126.6549318,44.0
|
| 84 |
+
37.449931,126.6551249,51.0
|
| 85 |
+
37.4499437,126.6552644,46.0
|
| 86 |
+
37.4501013,126.6545617,50.0
|
| 87 |
+
37.4501525,126.654213,48.0
|
| 88 |
+
37.4499771,126.65462,48.0
|
| 89 |
+
37.4497514,126.6551403,52.0
|
| 90 |
+
37.4498331,126.6546207,48.0
|
| 91 |
+
37.4497777,126.6547173,52.0
|
| 92 |
+
37.448078,126.6556807,37.0
|
| 93 |
+
37.4483203,126.6558354,41.0
|
| 94 |
+
37.4483203,126.655504,47.0
|
| 95 |
+
37.44746,126.655224,52.0
|
| 96 |
+
37.4474539,126.6555703,45.0
|
| 97 |
+
37.4476721,126.6550472,55.0
|
| 98 |
+
37.4477023,126.655364,49.0
|
| 99 |
+
37.4477751,126.6551283,56.0
|
| 100 |
+
37.4488898,126.6557323,53.0
|
| 101 |
+
37.4490655,126.6560712,55.0
|
| 102 |
+
37.4489565,126.6559828,54.0
|
| 103 |
+
37.4492533,126.656108,59.0
|
| 104 |
+
37.4494472,126.6563216,63.0
|
| 105 |
+
37.4497198,126.6561375,58.0
|
| 106 |
+
37.4499379,126.656248,56.0
|
| 107 |
+
37.4485566,126.6557102,59.0
|
| 108 |
+
37.4483627,126.6551062,42.0
|
| 109 |
+
37.4506589,126.6570141,51.0
|
| 110 |
+
37.4503802,126.656469,58.0
|
| 111 |
+
37.4505559,126.6571835,48.0
|
| 112 |
+
37.4492957,126.656329,58.0
|
| 113 |
+
37.4495078,126.6564248,61.0
|
README.md
CHANGED
|
@@ -1,12 +1,6 @@
|
|
| 1 |
---
|
| 2 |
-
title:
|
| 3 |
-
emoji: ๐จ
|
| 4 |
-
colorFrom: pink
|
| 5 |
-
colorTo: blue
|
| 6 |
-
sdk: gradio
|
| 7 |
-
sdk_version: 6.0.1
|
| 8 |
app_file: app.py
|
| 9 |
-
|
|
|
|
| 10 |
---
|
| 11 |
-
|
| 12 |
-
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
|
|
|
| 1 |
---
|
| 2 |
+
title: Sampling_Proj
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
app_file: app.py
|
| 4 |
+
sdk: gradio
|
| 5 |
+
sdk_version: 5.35.0
|
| 6 |
---
|
|
|
|
|
|
app.py
ADDED
|
@@ -0,0 +1,539 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# sampling_sim_app.py
|
| 2 |
+
import os
|
| 3 |
+
import io
|
| 4 |
+
|
| 5 |
+
import matplotlib
|
| 6 |
+
matplotlib.use("Agg")
|
| 7 |
+
|
| 8 |
+
import numpy as np
|
| 9 |
+
import pandas as pd
|
| 10 |
+
import geopandas as gpd
|
| 11 |
+
import matplotlib.pyplot as plt
|
| 12 |
+
from shapely.geometry import Point
|
| 13 |
+
from shapely import wkt as shp_wkt
|
| 14 |
+
from PIL import Image
|
| 15 |
+
import contextily as ctx # โ ์ถ๊ฐ
|
| 16 |
+
|
| 17 |
+
import gradio as gr
|
| 18 |
+
|
| 19 |
+
# ----------------- ๊ฒฝ๋ก ์ค์ -----------------
|
| 20 |
+
BASE_DIR = os.path.dirname(__file__)
|
| 21 |
+
DATA_DIR = os.path.join(BASE_DIR, "Data")
|
| 22 |
+
|
| 23 |
+
SHP_PATH = os.path.join(DATA_DIR, "inha_boundary.shp")
|
| 24 |
+
ZONES_PATH = os.path.join(DATA_DIR, "zones_์ต์ข
.geojson")
|
| 25 |
+
|
| 26 |
+
# ์ธก์ ๊ฒฐ๊ณผ CSV (lat, lon, dB ๋๋ ์์น, dB)
|
| 27 |
+
CSV_PATH = os.path.join(DATA_DIR, "์ธก์ ๊ฒฐ๊ณผ_์ต์ข
.csv")
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
# ---------- ์ ํธ: Figure -> numpy ----------
|
| 31 |
+
def fig_to_array(fig, dpi=100):
|
| 32 |
+
buf = io.BytesIO()
|
| 33 |
+
fig.savefig(buf, format="png", dpi=dpi, bbox_inches="tight")
|
| 34 |
+
buf.seek(0)
|
| 35 |
+
img = np.array(Image.open(buf))
|
| 36 |
+
plt.close(fig)
|
| 37 |
+
return img
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
# ---------- ๊ฒฝ๊ณ SHP ๋ก๋ฉ ----------
|
| 41 |
+
def load_boundary():
|
| 42 |
+
gdf4326 = gpd.read_file(SHP_PATH).to_crs(epsg=4326)
|
| 43 |
+
gdf3857 = gdf4326.to_crs(epsg=3857)
|
| 44 |
+
|
| 45 |
+
poly3857 = gdf3857.geometry.unary_union
|
| 46 |
+
if poly3857.geom_type == "MultiPolygon":
|
| 47 |
+
poly3857 = max(poly3857.geoms, key=lambda g: g.area)
|
| 48 |
+
|
| 49 |
+
return gdf4326, gdf3857, poly3857
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
# ---------- ์ธก์ ๊ฒฐ๊ณผ CSV ๋ก๋ฉ ----------
|
| 53 |
+
def load_points_from_csv():
|
| 54 |
+
try:
|
| 55 |
+
df_u = pd.read_csv(CSV_PATH, encoding="cp949")
|
| 56 |
+
except UnicodeDecodeError:
|
| 57 |
+
df_u = pd.read_csv(CSV_PATH, encoding="utf-8")
|
| 58 |
+
|
| 59 |
+
df_u.columns = [c.strip() for c in df_u.columns]
|
| 60 |
+
df_u = df_u.loc[:, ~df_u.columns.str.contains("^Unnamed")]
|
| 61 |
+
|
| 62 |
+
# ์ผ์ด์ค B: ์์น, dB
|
| 63 |
+
if "์์น" in df_u.columns and "dB" in df_u.columns:
|
| 64 |
+
pos_series = df_u["์์น"].astype(str).str.strip()
|
| 65 |
+
|
| 66 |
+
def safe_load_wkt(s):
|
| 67 |
+
s_up = s.upper()
|
| 68 |
+
if "POINT" not in s_up:
|
| 69 |
+
return None
|
| 70 |
+
try:
|
| 71 |
+
return shp_wkt.loads(s)
|
| 72 |
+
except Exception:
|
| 73 |
+
return None
|
| 74 |
+
|
| 75 |
+
geom = pos_series.apply(safe_load_wkt)
|
| 76 |
+
mask = geom.notnull()
|
| 77 |
+
if not mask.any():
|
| 78 |
+
raise ValueError("'์์น' ์ปฌ๋ผ์ ์ ํจํ POINT WKT๊ฐ ์๋ค.")
|
| 79 |
+
|
| 80 |
+
geom_valid = geom[mask]
|
| 81 |
+
lons = geom_valid.apply(lambda g: round(g.x, 7))
|
| 82 |
+
lats = geom_valid.apply(lambda g: round(g.y, 7))
|
| 83 |
+
dBs = pd.to_numeric(df_u.loc[mask, "dB"], errors="coerce")
|
| 84 |
+
|
| 85 |
+
df = pd.DataFrame({"lat": lats, "lon": lons, "dB": dBs}).dropna(
|
| 86 |
+
subset=["lat", "lon"]
|
| 87 |
+
)
|
| 88 |
+
return df
|
| 89 |
+
|
| 90 |
+
# ์ผ์ด์ค A: lat, lon, dB
|
| 91 |
+
if {"lat", "lon", "dB"}.issubset(df_u.columns):
|
| 92 |
+
df = df_u[["lat", "lon", "dB"]].copy()
|
| 93 |
+
df["lat"] = pd.to_numeric(df["lat"], errors="coerce").round(7)
|
| 94 |
+
df["lon"] = pd.to_numeric(df["lon"], errors="coerce").round(7)
|
| 95 |
+
df["dB"] = pd.to_numeric(df["dB"], errors="coerce")
|
| 96 |
+
df = df.dropna(subset=["lat", "lon"])
|
| 97 |
+
return df
|
| 98 |
+
|
| 99 |
+
raise ValueError("CSV๋ (lat, lon, dB) ๋๋ (์์น, dB) ํ์์ด์ด์ผ ํ๋ค.")
|
| 100 |
+
|
| 101 |
+
|
| 102 |
+
# ---------- ๊ตฌ์ญ GeoJSON ๋ก๋ฉ ----------
|
| 103 |
+
def load_zones(poly3857):
|
| 104 |
+
zones4326 = gpd.read_file(ZONES_PATH).to_crs(epsg=4326)
|
| 105 |
+
zones3857 = zones4326.to_crs(epsg=3857)
|
| 106 |
+
|
| 107 |
+
if "zone_id" not in zones3857.columns:
|
| 108 |
+
zones3857["zone_id"] = np.arange(1, len(zones3857) + 1)
|
| 109 |
+
|
| 110 |
+
zones3857["geom_clip"] = zones3857.geometry.intersection(poly3857)
|
| 111 |
+
zones3857["area"] = zones3857["geom_clip"].area
|
| 112 |
+
zones3857 = zones3857[zones3857["area"] > 0].copy()
|
| 113 |
+
|
| 114 |
+
A_total = zones3857["area"].sum()
|
| 115 |
+
zones3857["W_area"] = zones3857["area"] / A_total
|
| 116 |
+
|
| 117 |
+
return zones4326, zones3857
|
| 118 |
+
|
| 119 |
+
|
| 120 |
+
# ---------- ํฌ์ธํธ์ zone_id ๋ถ์ด๊ธฐ ----------
|
| 121 |
+
def attach_zone_id(points_df, zones3857):
|
| 122 |
+
pts4326 = gpd.GeoDataFrame(
|
| 123 |
+
points_df.copy(),
|
| 124 |
+
geometry=gpd.points_from_xy(points_df["lon"], points_df["lat"]),
|
| 125 |
+
crs=4326,
|
| 126 |
+
)
|
| 127 |
+
pts3857 = pts4326.to_crs(epsg=3857)
|
| 128 |
+
|
| 129 |
+
zones_clip = zones3857[["zone_id", "geom_clip"]].copy()
|
| 130 |
+
zones_clip = zones_clip.set_geometry("geom_clip")
|
| 131 |
+
zones_clip = zones_clip.rename_geometry("geometry")
|
| 132 |
+
|
| 133 |
+
joined = gpd.sjoin(
|
| 134 |
+
pts3857,
|
| 135 |
+
zones_clip[["zone_id", "geometry"]],
|
| 136 |
+
how="inner",
|
| 137 |
+
predicate="within",
|
| 138 |
+
)
|
| 139 |
+
|
| 140 |
+
out = joined[["lat", "lon", "dB", "zone_id"]].copy().reset_index(drop=True)
|
| 141 |
+
return out
|
| 142 |
+
|
| 143 |
+
|
| 144 |
+
# ---------- ๊ณตํต ์ค๋น: ๊ฒฝ๊ณ/๊ตฌ์ญ/ํฌ์ธํธ/์ธต์ ๋ณด ----------
|
| 145 |
+
def prepare_sampling_data():
|
| 146 |
+
boundary4326, boundary3857, poly3857 = load_boundary()
|
| 147 |
+
zones4326, zones3857 = load_zones(poly3857)
|
| 148 |
+
df_points = load_points_from_csv()
|
| 149 |
+
points_zone = attach_zone_id(df_points, zones3857)
|
| 150 |
+
|
| 151 |
+
# ์ธต๋ณ ๋ชจ์ง๋จ ํฌ๊ธฐ N_h
|
| 152 |
+
zone_sizes = points_zone.groupby("zone_id").size().rename("N_h")
|
| 153 |
+
zones_info = zones3857[["zone_id", "area", "W_area"]].merge(
|
| 154 |
+
zone_sizes, on="zone_id", how="left"
|
| 155 |
+
)
|
| 156 |
+
zones_info["N_h"] = zones_info["N_h"].fillna(0).astype(int)
|
| 157 |
+
|
| 158 |
+
# ์ธต๋ณ ํ์คํธ์ฐจ S_h (๋ค์ด๋ง ๋ฐฐ๋ถ์ฉ)
|
| 159 |
+
strata_std = points_zone.groupby("zone_id")["dB"].std(ddof=1).rename("S_h")
|
| 160 |
+
zones_info = zones_info.merge(strata_std, on="zone_id", how="left")
|
| 161 |
+
zones_info["S_h"] = zones_info["S_h"].fillna(0.0)
|
| 162 |
+
|
| 163 |
+
return boundary4326, zones4326, df_points, points_zone, zones_info
|
| 164 |
+
|
| 165 |
+
|
| 166 |
+
# ---------- ๋ฉด์ ๋น๋ก n_h ๊ณ์ฐ ----------
|
| 167 |
+
def allocate_n_by_area(zones_info, n_total):
|
| 168 |
+
zones = zones_info.copy()
|
| 169 |
+
zones["n_raw"] = n_total * zones["W_area"]
|
| 170 |
+
zones["n"] = zones["n_raw"].round().astype(int)
|
| 171 |
+
|
| 172 |
+
diff = n_total - zones["n"].sum()
|
| 173 |
+
if diff != 0:
|
| 174 |
+
order = zones["n_raw"].sort_values(ascending=(diff < 0)).index
|
| 175 |
+
for idx in order[:abs(diff)]:
|
| 176 |
+
zones.loc[idx, "n"] += 1 if diff > 0 else -1
|
| 177 |
+
|
| 178 |
+
zones["n"] = zones[["n", "N_h"]].min(axis=1)
|
| 179 |
+
return zones
|
| 180 |
+
|
| 181 |
+
|
| 182 |
+
# ---------- ๋ค์ด๋ง ๋ฐฐ๋ถ n_h ๊ณ์ฐ ----------
|
| 183 |
+
def allocate_n_neyman(zones_info, n_total):
|
| 184 |
+
zones = zones_info.copy()
|
| 185 |
+
if "S_h" not in zones.columns:
|
| 186 |
+
raise ValueError("zones_info์ S_h๊ฐ ์๋ค. ๋ค์ด๋ง ๋ฐฐ๋ถ ์ ์ S_h๋ฅผ ๊ณ์ฐํด์ผ ํ๋ค.")
|
| 187 |
+
|
| 188 |
+
zones["S_h"] = zones["S_h"].fillna(0.0)
|
| 189 |
+
|
| 190 |
+
# ๊ฐ์ค์น โ N_h * S_h
|
| 191 |
+
weight = zones["N_h"] * zones["S_h"]
|
| 192 |
+
if weight.sum() <= 0:
|
| 193 |
+
# ๋ถ์ฐ์ด ์ ๋ถ 0์ด๋ฉด N_h ๋น๋ก๋ก ๋ฐฐ๋ถ
|
| 194 |
+
weight = zones["N_h"].copy()
|
| 195 |
+
|
| 196 |
+
zones["n_raw"] = n_total * weight / weight.sum()
|
| 197 |
+
zones["n"] = zones["n_raw"].round().astype(int)
|
| 198 |
+
|
| 199 |
+
diff = n_total - zones["n"].sum()
|
| 200 |
+
if diff != 0:
|
| 201 |
+
order = zones["n_raw"].sort_values(ascending=(diff < 0)).index
|
| 202 |
+
for idx in order[:abs(diff)]:
|
| 203 |
+
zones.loc[idx, "n"] += 1 if diff > 0 else -1
|
| 204 |
+
|
| 205 |
+
zones["n"] = zones[["n", "N_h"]].min(axis=1)
|
| 206 |
+
return zones
|
| 207 |
+
|
| 208 |
+
|
| 209 |
+
# ---------- ์๋ฎฌ๋ ์ด์
----------
|
| 210 |
+
def simulate_sampling(points_zone_df, zones_info, n, R, strat_label):
|
| 211 |
+
y_all = points_zone_df["dB"].to_numpy()
|
| 212 |
+
N = len(y_all)
|
| 213 |
+
mu_pop = float(np.mean(y_all))
|
| 214 |
+
|
| 215 |
+
zones = zones_info.set_index("zone_id")
|
| 216 |
+
W_h = zones["N_h"] / zones["N_h"].sum()
|
| 217 |
+
n_h = zones["n"]
|
| 218 |
+
|
| 219 |
+
idx_by_zone = {}
|
| 220 |
+
for z in zones.index:
|
| 221 |
+
idx_by_zone[z] = points_zone_df.index[
|
| 222 |
+
points_zone_df["zone_id"] == z
|
| 223 |
+
].to_numpy()
|
| 224 |
+
|
| 225 |
+
srs_means = []
|
| 226 |
+
strat_means = []
|
| 227 |
+
|
| 228 |
+
for _ in range(R):
|
| 229 |
+
# SRS
|
| 230 |
+
n_eff = min(n, N)
|
| 231 |
+
idx_srs = np.random.choice(N, size=n_eff, replace=False)
|
| 232 |
+
mu_srs = float(np.mean(y_all[idx_srs]))
|
| 233 |
+
srs_means.append(mu_srs)
|
| 234 |
+
|
| 235 |
+
# Stratified
|
| 236 |
+
mu_str = 0.0
|
| 237 |
+
for z in zones.index:
|
| 238 |
+
N_h = int(zones.loc[z, "N_h"])
|
| 239 |
+
nh = int(n_h.loc[z])
|
| 240 |
+
if N_h == 0 or nh == 0:
|
| 241 |
+
continue
|
| 242 |
+
idx_pool = idx_by_zone[z]
|
| 243 |
+
if len(idx_pool) < nh:
|
| 244 |
+
nh = len(idx_pool)
|
| 245 |
+
choose = np.random.choice(idx_pool, size=nh, replace=False)
|
| 246 |
+
y_h = points_zone_df.loc[choose, "dB"].to_numpy()
|
| 247 |
+
ybar_h = float(np.mean(y_h))
|
| 248 |
+
mu_str += float(W_h.loc[z]) * ybar_h
|
| 249 |
+
strat_means.append(mu_str)
|
| 250 |
+
|
| 251 |
+
srs_means = np.array(srs_means)
|
| 252 |
+
strat_means = np.array(strat_means)
|
| 253 |
+
|
| 254 |
+
def metrics(arr, name):
|
| 255 |
+
mean_hat = float(arr.mean())
|
| 256 |
+
var_hat = float(arr.var(ddof=1))
|
| 257 |
+
bias = mean_hat - mu_pop
|
| 258 |
+
mse = float(((arr - mu_pop) ** 2).mean())
|
| 259 |
+
return {
|
| 260 |
+
"design": name,
|
| 261 |
+
"mean_hat": mean_hat,
|
| 262 |
+
"var_hat": var_hat,
|
| 263 |
+
"bias": bias,
|
| 264 |
+
"MSE": mse,
|
| 265 |
+
}
|
| 266 |
+
|
| 267 |
+
m_srs = metrics(srs_means, "SRS")
|
| 268 |
+
m_str = metrics(strat_means, strat_label)
|
| 269 |
+
|
| 270 |
+
df_metrics = pd.DataFrame([m_srs, m_str])
|
| 271 |
+
df_metrics["deff_vs_SRS"] = df_metrics["var_hat"] / df_metrics["var_hat"].iloc[0]
|
| 272 |
+
|
| 273 |
+
# ์ซ์ 4์งธ ์๋ฆฌ๊น์ง ๋ฐ์ฌ๋ฆผ
|
| 274 |
+
num_cols = ["mean_hat", "var_hat", "bias", "MSE", "deff_vs_SRS"]
|
| 275 |
+
df_metrics[num_cols] = df_metrics[num_cols].round(4)
|
| 276 |
+
|
| 277 |
+
return mu_pop, srs_means, strat_means, df_metrics
|
| 278 |
+
|
| 279 |
+
|
| 280 |
+
# ---------- ๊ตฌ์ญ ์์ฝ ํ
์ด๋ธ ----------
|
| 281 |
+
def build_zones_table(zones_alloc):
|
| 282 |
+
zones_table = zones_alloc[["zone_id", "area", "W_area", "N_h", "n"]].copy()
|
| 283 |
+
zones_table = zones_table.rename(
|
| 284 |
+
columns={
|
| 285 |
+
"area": "area_m2",
|
| 286 |
+
"W_area": "area_weight",
|
| 287 |
+
"N_h": "N_pop",
|
| 288 |
+
"n": "n_alloc",
|
| 289 |
+
}
|
| 290 |
+
)
|
| 291 |
+
zones_table["sampling_frac"] = zones_table["n_alloc"] / zones_table["N_pop"]
|
| 292 |
+
|
| 293 |
+
total_area_m2 = zones_table["area_m2"].sum()
|
| 294 |
+
total_area_weight = zones_table["area_weight"].sum()
|
| 295 |
+
total_N = zones_table["N_pop"].sum()
|
| 296 |
+
total_n = zones_table["n_alloc"].sum()
|
| 297 |
+
total_sampling_frac = total_n / total_N if total_N > 0 else np.nan
|
| 298 |
+
|
| 299 |
+
total_row = {
|
| 300 |
+
"zone_id": "๏ฟฝ๏ฟฝ๏ฟฝ๊ณ",
|
| 301 |
+
"area_m2": total_area_m2,
|
| 302 |
+
"area_weight": total_area_weight,
|
| 303 |
+
"N_pop": total_N,
|
| 304 |
+
"n_alloc": total_n,
|
| 305 |
+
"sampling_frac": total_sampling_frac,
|
| 306 |
+
}
|
| 307 |
+
|
| 308 |
+
zones_table = zones_table[
|
| 309 |
+
["zone_id", "area_m2", "area_weight", "N_pop", "n_alloc", "sampling_frac"]
|
| 310 |
+
]
|
| 311 |
+
zones_table = pd.concat([zones_table, pd.DataFrame([total_row])], ignore_index=True)
|
| 312 |
+
|
| 313 |
+
# ์ซ์ ์ปฌ๋ผ 4์งธ ์๋ฆฌ๊น์ง ๋ฐ์ฌ๋ฆผ
|
| 314 |
+
num_cols_zone = ["area_m2", "area_weight", "N_pop", "n_alloc", "sampling_frac"]
|
| 315 |
+
for col in num_cols_zone:
|
| 316 |
+
zones_table[col] = pd.to_numeric(zones_table[col], errors="coerce").round(4)
|
| 317 |
+
|
| 318 |
+
return zones_table, float(total_N), float(total_n)
|
| 319 |
+
|
| 320 |
+
|
| 321 |
+
# ---------- ์๊ฐํ ----------
|
| 322 |
+
def plot_population_map(boundary4326, zones4326, points_df):
|
| 323 |
+
g_boundary = boundary4326.to_crs(epsg=3857)
|
| 324 |
+
g_zones = zones4326.to_crs(epsg=3857)
|
| 325 |
+
g_pts = gpd.GeoDataFrame(
|
| 326 |
+
points_df.copy(),
|
| 327 |
+
geometry=gpd.points_from_xy(points_df["lon"], points_df["lat"]),
|
| 328 |
+
crs=4326,
|
| 329 |
+
).to_crs(epsg=3857)
|
| 330 |
+
|
| 331 |
+
fig, ax = plt.subplots(figsize=(8, 8))
|
| 332 |
+
|
| 333 |
+
# ๋ฒ ์ด์ค๋งต ๋จผ์ ๊น๊ธฐ
|
| 334 |
+
minx, miny, maxx, maxy = g_boundary.total_bounds
|
| 335 |
+
ax.set_xlim(minx, maxx)
|
| 336 |
+
ax.set_ylim(miny, maxy)
|
| 337 |
+
ctx.add_basemap(ax, source=ctx.providers.OpenStreetMap.Mapnik, alpha=0.7)
|
| 338 |
+
|
| 339 |
+
# ๊ทธ ์์ ๊ฒฝ๊ณ/๊ตฌ์ญ/ํฌ์ธํธ
|
| 340 |
+
g_boundary.plot(ax=ax, facecolor="none", edgecolor="black", linewidth=2)
|
| 341 |
+
if len(g_zones) > 0:
|
| 342 |
+
g_zones.plot(
|
| 343 |
+
ax=ax,
|
| 344 |
+
facecolor="none",
|
| 345 |
+
edgecolor="red",
|
| 346 |
+
linewidth=1.5,
|
| 347 |
+
alpha=0.7,
|
| 348 |
+
)
|
| 349 |
+
|
| 350 |
+
g_pts.plot(
|
| 351 |
+
ax=ax,
|
| 352 |
+
column="dB",
|
| 353 |
+
cmap="viridis",
|
| 354 |
+
markersize=20,
|
| 355 |
+
edgecolor="black",
|
| 356 |
+
linewidth=0.2,
|
| 357 |
+
legend=False,
|
| 358 |
+
alpha=0.9,
|
| 359 |
+
)
|
| 360 |
+
|
| 361 |
+
ax.set_title("Population points with zones", fontsize=12)
|
| 362 |
+
ax.axis("off")
|
| 363 |
+
plt.tight_layout()
|
| 364 |
+
return fig_to_array(fig)
|
| 365 |
+
|
| 366 |
+
|
| 367 |
+
def plot_histograms(srs_means, strat_means, mu_pop, strat_label):
|
| 368 |
+
fig, ax = plt.subplots(figsize=(8, 5))
|
| 369 |
+
|
| 370 |
+
ax.hist(srs_means, bins=20, alpha=0.5, label="SRS")
|
| 371 |
+
ax.hist(strat_means, bins=20, alpha=0.5, label=strat_label)
|
| 372 |
+
ax.axvline(mu_pop, color="k", linestyle="--", label="Population mean")
|
| 373 |
+
|
| 374 |
+
ax.set_xlabel("Sample mean (dB)")
|
| 375 |
+
ax.set_ylabel("Frequency")
|
| 376 |
+
ax.legend()
|
| 377 |
+
ax.set_title("Sampling distribution of mean")
|
| 378 |
+
plt.tight_layout()
|
| 379 |
+
return fig_to_array(fig)
|
| 380 |
+
|
| 381 |
+
|
| 382 |
+
# ---------- Gradio ์ฝ๋ฐฑ: ๋ฉด์ ๋น๋ก ----------
|
| 383 |
+
def run_sim_area(n, R):
|
| 384 |
+
n = int(n)
|
| 385 |
+
R = int(R)
|
| 386 |
+
|
| 387 |
+
boundary4326, zones4326, df_points, points_zone, zones_info = prepare_sampling_data()
|
| 388 |
+
|
| 389 |
+
# ๋ฉด์ ๋น๋ก ๋ฐฐ๋ถ
|
| 390 |
+
zones_alloc = allocate_n_by_area(zones_info, n)
|
| 391 |
+
zones_table, total_N, total_n = build_zones_table(zones_alloc)
|
| 392 |
+
|
| 393 |
+
mu_pop, srs_means, strat_means, df_metrics = simulate_sampling(
|
| 394 |
+
points_zone, zones_alloc, n, R, "Stratified (area-proportional)"
|
| 395 |
+
)
|
| 396 |
+
|
| 397 |
+
map_img = plot_population_map(boundary4326, zones4326, df_points)
|
| 398 |
+
hist_img = plot_histograms(
|
| 399 |
+
srs_means, strat_means, mu_pop, "Stratified (area-proportional)"
|
| 400 |
+
)
|
| 401 |
+
|
| 402 |
+
summary = (
|
| 403 |
+
f"[๋ฉด์ ๋น๋ก ์ธตํ]\n"
|
| 404 |
+
f"๋ชจ์ง๋จ ํฌ์ธํธ ์: {int(total_N)}๊ฐ\n"
|
| 405 |
+
f"๊ตฌ์ญ ์: {len(zones_alloc)}๊ฐ\n"
|
| 406 |
+
f"๋ชจ์ง๋จ ํ๊ท dB: {mu_pop:.4f}\n"
|
| 407 |
+
f"์ด ํ๋ณธํฌ๊ธฐ n = {int(total_n)} (์
๋ ฅ๊ฐ {n}), ๋ฐ๋ณต R = {R}"
|
| 408 |
+
)
|
| 409 |
+
|
| 410 |
+
return map_img, hist_img, df_metrics, zones_table, summary
|
| 411 |
+
|
| 412 |
+
|
| 413 |
+
# ---------- Gradio ์ฝ๋ฐฑ: ๋ค์ด๋ง ----------
|
| 414 |
+
def run_sim_neyman(n, R):
|
| 415 |
+
n = int(n)
|
| 416 |
+
R = int(R)
|
| 417 |
+
|
| 418 |
+
boundary4326, zones4326, df_points, points_zone, zones_info = prepare_sampling_data()
|
| 419 |
+
|
| 420 |
+
# ๋ค์ด๋ง ๋ฐฐ๋ถ
|
| 421 |
+
zones_alloc = allocate_n_neyman(zones_info, n)
|
| 422 |
+
zones_table, total_N, total_n = build_zones_table(zones_alloc)
|
| 423 |
+
|
| 424 |
+
mu_pop, srs_means, strat_means, df_metrics = simulate_sampling(
|
| 425 |
+
points_zone, zones_alloc, n, R, "Stratified (Neyman)"
|
| 426 |
+
)
|
| 427 |
+
|
| 428 |
+
map_img = plot_population_map(boundary4326, zones4326, df_points)
|
| 429 |
+
hist_img = plot_histograms(
|
| 430 |
+
srs_means, strat_means, mu_pop, "Stratified (Neyman)"
|
| 431 |
+
)
|
| 432 |
+
|
| 433 |
+
summary = (
|
| 434 |
+
f"[๋ค์ด๋ง ์ธตํ]\n"
|
| 435 |
+
f"๋ชจ์ง๋จ ํฌ์ธํธ ์: {int(total_N)}๊ฐ\n"
|
| 436 |
+
f"๊ตฌ์ญ ์: {len(zones_alloc)}๊ฐ\n"
|
| 437 |
+
f"๋ชจ์ง๋จ ํ๊ท dB: {mu_pop:.4f}\n"
|
| 438 |
+
f"์ด ํ๋ณธํฌ๊ธฐ n = {int(total_n)} (์
๋ ฅ๊ฐ {n}), ๋ฐ๋ณต R = {R}"
|
| 439 |
+
)
|
| 440 |
+
|
| 441 |
+
return map_img, hist_img, df_metrics, zones_table, summary
|
| 442 |
+
|
| 443 |
+
|
| 444 |
+
# ---------- Gradio ์ฑ ----------
|
| 445 |
+
def build_app():
|
| 446 |
+
with gr.Blocks(title="ํ๋ณธ์ถ์ถ ์๋ฎฌ๋ ์ด์
(SRS vs ์ธตํ)") as demo:
|
| 447 |
+
|
| 448 |
+
with gr.Tab("SRS vs ๋ฉด์ ๋น๋ก ์ธตํ"):
|
| 449 |
+
with gr.Row():
|
| 450 |
+
n_area = gr.Number(label="ํ๋ณธํฌ๊ธฐ n", value=60, precision=0)
|
| 451 |
+
R_area = gr.Number(label="์๋ฎฌ๋ ์ด์
๋ฐ๋ณต ํ์ R", value=500, precision=0)
|
| 452 |
+
|
| 453 |
+
run_btn_area = gr.Button("๋ฉด์ ๋น๋ก ์ธตํ ์๋ฎฌ๋ ์ด์
์คํ", variant="primary")
|
| 454 |
+
|
| 455 |
+
with gr.Row():
|
| 456 |
+
map_img_area = gr.Image(label="Population + zones")
|
| 457 |
+
hist_img_area = gr.Image(label="Sampling distribution")
|
| 458 |
+
|
| 459 |
+
metrics_table_area = gr.Dataframe(
|
| 460 |
+
headers=[
|
| 461 |
+
"design",
|
| 462 |
+
"mean_hat",
|
| 463 |
+
"var_hat",
|
| 464 |
+
"bias",
|
| 465 |
+
"MSE",
|
| 466 |
+
"deff_vs_SRS",
|
| 467 |
+
],
|
| 468 |
+
label="์ฑ๋ฅ ๋น๊ต ์งํ",
|
| 469 |
+
interactive=False,
|
| 470 |
+
)
|
| 471 |
+
|
| 472 |
+
zones_table_area = gr.Dataframe(
|
| 473 |
+
label="๊ตฌ์ญ๋ณ ๋ฉด์ ๋ฐ ๋ชจ์ง๋จ/๋ฐฐ์ ํ๋ณธ์",
|
| 474 |
+
interactive=False,
|
| 475 |
+
)
|
| 476 |
+
|
| 477 |
+
summary_md_area = gr.Markdown()
|
| 478 |
+
|
| 479 |
+
run_btn_area.click(
|
| 480 |
+
fn=run_sim_area,
|
| 481 |
+
inputs=[n_area, R_area],
|
| 482 |
+
outputs=[
|
| 483 |
+
map_img_area,
|
| 484 |
+
hist_img_area,
|
| 485 |
+
metrics_table_area,
|
| 486 |
+
zones_table_area,
|
| 487 |
+
summary_md_area,
|
| 488 |
+
],
|
| 489 |
+
)
|
| 490 |
+
|
| 491 |
+
with gr.Tab("SRS vs ๋ค์ด๋ง ์ธตํ"):
|
| 492 |
+
with gr.Row():
|
| 493 |
+
n_neyman = gr.Number(label="ํ๋ณธํฌ๊ธฐ n", value=60, precision=0)
|
| 494 |
+
R_neyman = gr.Number(label="์๋ฎฌ๋ ์ด์
๋ฐ๋ณต ํ์ R", value=500, precision=0)
|
| 495 |
+
|
| 496 |
+
run_btn_neyman = gr.Button("๋ค์ด๋ง ์ธตํ ์๋ฎฌ๋ ์ด์
์คํ", variant="primary")
|
| 497 |
+
|
| 498 |
+
with gr.Row():
|
| 499 |
+
map_img_neyman = gr.Image(label="Population + zones")
|
| 500 |
+
hist_img_neyman = gr.Image(label="Sampling distribution")
|
| 501 |
+
|
| 502 |
+
metrics_table_neyman = gr.Dataframe(
|
| 503 |
+
headers=[
|
| 504 |
+
"design",
|
| 505 |
+
"mean_hat",
|
| 506 |
+
"var_hat",
|
| 507 |
+
"bias",
|
| 508 |
+
"MSE",
|
| 509 |
+
"deff_vs_SRS",
|
| 510 |
+
],
|
| 511 |
+
label="์ฑ๋ฅ ๋น๊ต ์งํ",
|
| 512 |
+
interactive=False,
|
| 513 |
+
)
|
| 514 |
+
|
| 515 |
+
zones_table_neyman = gr.Dataframe(
|
| 516 |
+
label="๊ตฌ์ญ๋ณ ๋ฉด์ ๋ฐ ๋ชจ์ง๋จ/๋ฐฐ์ ํ๋ณธ์",
|
| 517 |
+
interactive=False,
|
| 518 |
+
)
|
| 519 |
+
|
| 520 |
+
summary_md_neyman = gr.Markdown()
|
| 521 |
+
|
| 522 |
+
run_btn_neyman.click(
|
| 523 |
+
fn=run_sim_neyman,
|
| 524 |
+
inputs=[n_neyman, R_neyman],
|
| 525 |
+
outputs=[
|
| 526 |
+
map_img_neyman,
|
| 527 |
+
hist_img_neyman,
|
| 528 |
+
metrics_table_neyman,
|
| 529 |
+
zones_table_neyman,
|
| 530 |
+
summary_md_neyman,
|
| 531 |
+
],
|
| 532 |
+
)
|
| 533 |
+
|
| 534 |
+
return demo
|
| 535 |
+
|
| 536 |
+
|
| 537 |
+
if __name__ == "__main__":
|
| 538 |
+
app = build_app()
|
| 539 |
+
app.launch(share=True)
|
draw_zones.html
ADDED
|
@@ -0,0 +1,220 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html>
|
| 3 |
+
<head>
|
| 4 |
+
|
| 5 |
+
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
|
| 6 |
+
<script src="https://cdn.jsdelivr.net/npm/leaflet@1.9.3/dist/leaflet.js"></script>
|
| 7 |
+
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
|
| 8 |
+
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/js/bootstrap.bundle.min.js"></script>
|
| 9 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/Leaflet.awesome-markers/2.0.2/leaflet.awesome-markers.js"></script>
|
| 10 |
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/leaflet@1.9.3/dist/leaflet.css"/>
|
| 11 |
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css"/>
|
| 12 |
+
<link rel="stylesheet" href="https://netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap-glyphicons.css"/>
|
| 13 |
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.2.0/css/all.min.css"/>
|
| 14 |
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/Leaflet.awesome-markers/2.0.2/leaflet.awesome-markers.css"/>
|
| 15 |
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/python-visualization/folium/folium/templates/leaflet.awesome.rotate.min.css"/>
|
| 16 |
+
|
| 17 |
+
<meta name="viewport" content="width=device-width,
|
| 18 |
+
initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
| 19 |
+
<style>
|
| 20 |
+
#map_78266fbe1759aea8d6c235f8af0c0d47 {
|
| 21 |
+
position: relative;
|
| 22 |
+
width: 100.0%;
|
| 23 |
+
height: 100.0%;
|
| 24 |
+
left: 0.0%;
|
| 25 |
+
top: 0.0%;
|
| 26 |
+
}
|
| 27 |
+
.leaflet-container { font-size: 1rem; }
|
| 28 |
+
</style>
|
| 29 |
+
|
| 30 |
+
<style>html, body {
|
| 31 |
+
width: 100%;
|
| 32 |
+
height: 100%;
|
| 33 |
+
margin: 0;
|
| 34 |
+
padding: 0;
|
| 35 |
+
}
|
| 36 |
+
</style>
|
| 37 |
+
|
| 38 |
+
<style>#map {
|
| 39 |
+
position:absolute;
|
| 40 |
+
top:0;
|
| 41 |
+
bottom:0;
|
| 42 |
+
right:0;
|
| 43 |
+
left:0;
|
| 44 |
+
}
|
| 45 |
+
</style>
|
| 46 |
+
|
| 47 |
+
<script>
|
| 48 |
+
L_NO_TOUCH = false;
|
| 49 |
+
L_DISABLE_3D = false;
|
| 50 |
+
</script>
|
| 51 |
+
|
| 52 |
+
|
| 53 |
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.2/leaflet.draw.js"></script>
|
| 54 |
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.2/leaflet.draw.css"/>
|
| 55 |
+
</head>
|
| 56 |
+
<body>
|
| 57 |
+
|
| 58 |
+
|
| 59 |
+
<div class="folium-map" id="map_78266fbe1759aea8d6c235f8af0c0d47" ></div>
|
| 60 |
+
|
| 61 |
+
|
| 62 |
+
|
| 63 |
+
<style>
|
| 64 |
+
#export {
|
| 65 |
+
position: absolute;
|
| 66 |
+
top: 5px;
|
| 67 |
+
right: 10px;
|
| 68 |
+
z-index: 999;
|
| 69 |
+
background: white;
|
| 70 |
+
color: black;
|
| 71 |
+
padding: 6px;
|
| 72 |
+
border-radius: 4px;
|
| 73 |
+
font-family: 'Helvetica Neue';
|
| 74 |
+
cursor: pointer;
|
| 75 |
+
font-size: 12px;
|
| 76 |
+
text-decoration: none;
|
| 77 |
+
top: 90px;
|
| 78 |
+
}
|
| 79 |
+
</style>
|
| 80 |
+
<a href='#' id='export'>Export</a>
|
| 81 |
+
|
| 82 |
+
|
| 83 |
+
</body>
|
| 84 |
+
<script>
|
| 85 |
+
|
| 86 |
+
|
| 87 |
+
var map_78266fbe1759aea8d6c235f8af0c0d47 = L.map(
|
| 88 |
+
"map_78266fbe1759aea8d6c235f8af0c0d47",
|
| 89 |
+
{
|
| 90 |
+
center: [37.44975286338557, 126.65343455495042],
|
| 91 |
+
crs: L.CRS.EPSG3857,
|
| 92 |
+
...{
|
| 93 |
+
"zoom": 17,
|
| 94 |
+
"zoomControl": true,
|
| 95 |
+
"preferCanvas": false,
|
| 96 |
+
}
|
| 97 |
+
|
| 98 |
+
}
|
| 99 |
+
);
|
| 100 |
+
|
| 101 |
+
|
| 102 |
+
|
| 103 |
+
|
| 104 |
+
|
| 105 |
+
var tile_layer_c1196f4c91b6a6393d3df89cf55b8c8f = L.tileLayer(
|
| 106 |
+
"https://tile.openstreetmap.org/{z}/{x}/{y}.png",
|
| 107 |
+
{
|
| 108 |
+
"minZoom": 0,
|
| 109 |
+
"maxZoom": 19,
|
| 110 |
+
"maxNativeZoom": 19,
|
| 111 |
+
"noWrap": false,
|
| 112 |
+
"attribution": "\u0026copy; \u003ca href=\"https://www.openstreetmap.org/copyright\"\u003eOpenStreetMap\u003c/a\u003e contributors",
|
| 113 |
+
"subdomains": "abc",
|
| 114 |
+
"detectRetina": false,
|
| 115 |
+
"tms": false,
|
| 116 |
+
"opacity": 1,
|
| 117 |
+
}
|
| 118 |
+
|
| 119 |
+
);
|
| 120 |
+
|
| 121 |
+
|
| 122 |
+
tile_layer_c1196f4c91b6a6393d3df89cf55b8c8f.addTo(map_78266fbe1759aea8d6c235f8af0c0d47);
|
| 123 |
+
|
| 124 |
+
|
| 125 |
+
function geo_json_9b5f5972b80e71540402a2523e8a23d1_styler(feature) {
|
| 126 |
+
switch(feature.id) {
|
| 127 |
+
default:
|
| 128 |
+
return {"color": "blue", "fill": false, "weight": 3};
|
| 129 |
+
}
|
| 130 |
+
}
|
| 131 |
+
|
| 132 |
+
function geo_json_9b5f5972b80e71540402a2523e8a23d1_onEachFeature(feature, layer) {
|
| 133 |
+
|
| 134 |
+
layer.on({
|
| 135 |
+
});
|
| 136 |
+
};
|
| 137 |
+
var geo_json_9b5f5972b80e71540402a2523e8a23d1 = L.geoJson(null, {
|
| 138 |
+
onEachFeature: geo_json_9b5f5972b80e71540402a2523e8a23d1_onEachFeature,
|
| 139 |
+
|
| 140 |
+
style: geo_json_9b5f5972b80e71540402a2523e8a23d1_styler,
|
| 141 |
+
...{
|
| 142 |
+
}
|
| 143 |
+
});
|
| 144 |
+
|
| 145 |
+
function geo_json_9b5f5972b80e71540402a2523e8a23d1_add (data) {
|
| 146 |
+
geo_json_9b5f5972b80e71540402a2523e8a23d1
|
| 147 |
+
.addData(data);
|
| 148 |
+
}
|
| 149 |
+
geo_json_9b5f5972b80e71540402a2523e8a23d1_add({"features": [{"geometry": {"coordinates": [[[126.6504913, 37.4488536], [126.6502018, 37.4490381], [126.6501274, 37.4490101], [126.650006, 37.449035], [126.6499295, 37.4493095], [126.6497967, 37.4495766], [126.6496642, 37.4498464], [126.6493324, 37.4504076], [126.6490067, 37.4509487], [126.649781, 37.4514003], [126.6495914, 37.4517312], [126.6501326, 37.45175], [126.6505999, 37.4517726], [126.6510982, 37.4518266], [126.6512838, 37.4518467], [126.6517828, 37.4519342], [126.6520048, 37.4519731], [126.6520885, 37.4519878], [126.6524237, 37.4520465], [126.6525693, 37.452072], [126.6528855, 37.4521371], [126.6530797, 37.4521045], [126.6536373, 37.4518765], [126.6544021, 37.4516675], [126.6564271, 37.4511471], [126.6578465, 37.4507776], [126.6569217, 37.4492734], [126.6553859, 37.4466845], [126.6547144, 37.4468884], [126.6545294, 37.4469713], [126.6544155, 37.4470167], [126.653386, 37.4474272], [126.6527874, 37.4476634], [126.6507639, 37.4484888], [126.6505808, 37.4485626], [126.6505271, 37.4487565], [126.6504913, 37.4488536]]], "type": "Polygon"}, "id": "0", "type": "Feature"}], "type": "FeatureCollection"});
|
| 150 |
+
|
| 151 |
+
|
| 152 |
+
|
| 153 |
+
geo_json_9b5f5972b80e71540402a2523e8a23d1.addTo(map_78266fbe1759aea8d6c235f8af0c0d47);
|
| 154 |
+
|
| 155 |
+
|
| 156 |
+
var options = {
|
| 157 |
+
position: "topleft",
|
| 158 |
+
draw: {"circle": false, "circlemarker": false, "marker": false, "polygon": true, "polyline": false, "rectangle": true},
|
| 159 |
+
edit: {"edit": true, "remove": true},
|
| 160 |
+
}
|
| 161 |
+
// FeatureGroup is to store editable layers.
|
| 162 |
+
var drawnItems_draw_control_9d017ca223827f6de1a10b444cecfa37 =
|
| 163 |
+
new L.featureGroup().addTo(
|
| 164 |
+
map_78266fbe1759aea8d6c235f8af0c0d47
|
| 165 |
+
);
|
| 166 |
+
|
| 167 |
+
options.edit.featureGroup = drawnItems_draw_control_9d017ca223827f6de1a10b444cecfa37;
|
| 168 |
+
var draw_control_9d017ca223827f6de1a10b444cecfa37 = new L.Control.Draw(
|
| 169 |
+
options
|
| 170 |
+
).addTo( map_78266fbe1759aea8d6c235f8af0c0d47 );
|
| 171 |
+
map_78266fbe1759aea8d6c235f8af0c0d47.on(L.Draw.Event.CREATED, function(e) {
|
| 172 |
+
var layer = e.layer,
|
| 173 |
+
type = e.layerType;
|
| 174 |
+
var coords = JSON.stringify(layer.toGeoJSON());
|
| 175 |
+
layer.on('click', function() {
|
| 176 |
+
alert(coords);
|
| 177 |
+
console.log(coords);
|
| 178 |
+
});
|
| 179 |
+
drawnItems_draw_control_9d017ca223827f6de1a10b444cecfa37.addLayer(layer);
|
| 180 |
+
});
|
| 181 |
+
map_78266fbe1759aea8d6c235f8af0c0d47.on('draw:created', function(e) {
|
| 182 |
+
drawnItems_draw_control_9d017ca223827f6de1a10b444cecfa37.addLayer(e.layer);
|
| 183 |
+
});
|
| 184 |
+
|
| 185 |
+
|
| 186 |
+
document.getElementById('export').onclick = function(e) {
|
| 187 |
+
var data = drawnItems_draw_control_9d017ca223827f6de1a10b444cecfa37.toGeoJSON();
|
| 188 |
+
var convertedData = 'text/json;charset=utf-8,'
|
| 189 |
+
+ encodeURIComponent(JSON.stringify(data));
|
| 190 |
+
document.getElementById('export').setAttribute(
|
| 191 |
+
'href', 'data:' + convertedData
|
| 192 |
+
);
|
| 193 |
+
document.getElementById('export').setAttribute(
|
| 194 |
+
'download', "zones.geojson"
|
| 195 |
+
);
|
| 196 |
+
}
|
| 197 |
+
|
| 198 |
+
|
| 199 |
+
|
| 200 |
+
var layer_control_859bc6ff55e56629719267d89d3e2a9c_layers = {
|
| 201 |
+
base_layers : {
|
| 202 |
+
"openstreetmap" : tile_layer_c1196f4c91b6a6393d3df89cf55b8c8f,
|
| 203 |
+
},
|
| 204 |
+
overlays : {
|
| 205 |
+
"campus_boundary" : geo_json_9b5f5972b80e71540402a2523e8a23d1,
|
| 206 |
+
},
|
| 207 |
+
};
|
| 208 |
+
let layer_control_859bc6ff55e56629719267d89d3e2a9c = L.control.layers(
|
| 209 |
+
layer_control_859bc6ff55e56629719267d89d3e2a9c_layers.base_layers,
|
| 210 |
+
layer_control_859bc6ff55e56629719267d89d3e2a9c_layers.overlays,
|
| 211 |
+
{
|
| 212 |
+
"position": "topright",
|
| 213 |
+
"collapsed": true,
|
| 214 |
+
"autoZIndex": true,
|
| 215 |
+
}
|
| 216 |
+
).addTo(map_78266fbe1759aea8d6c235f8af0c0d47);
|
| 217 |
+
|
| 218 |
+
|
| 219 |
+
</script>
|
| 220 |
+
</html>
|
geo.ipynb
ADDED
|
File without changes
|
pin.py
ADDED
|
@@ -0,0 +1,376 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import io
|
| 3 |
+
|
| 4 |
+
import matplotlib
|
| 5 |
+
matplotlib.use("Agg") # ๋ฐฑ์๋ Agg๋ก ๊ณ ์
|
| 6 |
+
|
| 7 |
+
import geopandas as gpd
|
| 8 |
+
import pandas as pd
|
| 9 |
+
import numpy as np
|
| 10 |
+
import matplotlib.pyplot as plt
|
| 11 |
+
import contextily as ctx
|
| 12 |
+
from shapely.geometry import Point
|
| 13 |
+
from shapely import wkt as shp_wkt
|
| 14 |
+
from PIL import Image
|
| 15 |
+
|
| 16 |
+
import gradio as gr
|
| 17 |
+
|
| 18 |
+
# -------------------- ๊ฒฝ๋ก ์ค์ --------------------
|
| 19 |
+
SHP_PATH = r"C:\Users\USER\iCloudDrive\์ธํ๋ํ๊ต\5ํ๋
1ํ๊ธฐ\ํ๋ณธ๋ก ๋ฐ ์ค์ต\TeamProject\Data\inha_boundary.shp"
|
| 20 |
+
CSV_PATH = r"C:\Users\USER\iCloudDrive\์ธํ๋ํ๊ต\5ํ๋
1ํ๊ธฐ\ํ๋ณธ๋ก ๋ฐ ์ค์ต\TeamProject\๋ฐ์ดํฐ ์์ง\์ธก์ ๊ฒฐ๊ณผ.csv"
|
| 21 |
+
|
| 22 |
+
# ์ด๋ฏธ์ง ํด์๋(ํฝ์
)
|
| 23 |
+
IMG_W, IMG_H = 1200, 900
|
| 24 |
+
|
| 25 |
+
# -------------------- ์บ ํผ์ค ๊ฒฝ๊ณ ์ค๋น --------------------
|
| 26 |
+
gdf_boundary_4326 = gpd.read_file(SHP_PATH).to_crs(epsg=4326)
|
| 27 |
+
gdf_boundary_3857 = gdf_boundary_4326.to_crs(epsg=3857)
|
| 28 |
+
|
| 29 |
+
# DeprecationWarning ํผํ๊ธฐ ์ํด union_all ์ฐ์ ์ฌ์ฉ
|
| 30 |
+
try:
|
| 31 |
+
poly_3857 = gdf_boundary_3857.geometry.union_all()
|
| 32 |
+
except AttributeError:
|
| 33 |
+
poly_3857 = gdf_boundary_3857.geometry.unary_union
|
| 34 |
+
|
| 35 |
+
if poly_3857.geom_type == "MultiPolygon":
|
| 36 |
+
poly_3857 = max(poly_3857.geoms, key=lambda g: g.area)
|
| 37 |
+
|
| 38 |
+
BOUND_MINX, BOUND_MINY, BOUND_MAXX, BOUND_MAXY = poly_3857.bounds
|
| 39 |
+
|
| 40 |
+
# -------------------- ์ด๊ธฐ CSV ๋ก๋ฉ --------------------
|
| 41 |
+
# -------------------- ์ด๊ธฐ CSV ๋ก๋ฉ --------------------
|
| 42 |
+
if os.path.exists(CSV_PATH):
|
| 43 |
+
df_u = pd.read_csv(CSV_PATH, encoding="cp949")
|
| 44 |
+
|
| 45 |
+
# ์ปฌ๋ผ ์ ๋ฆฌ
|
| 46 |
+
df_u.columns = [c.strip() for c in df_u.columns]
|
| 47 |
+
df_u = df_u.loc[:, ~df_u.columns.str.contains("^Unnamed")]
|
| 48 |
+
|
| 49 |
+
if {"lat", "lon", "dB"}.issubset(df_u.columns):
|
| 50 |
+
# ์ด๋ฏธ lat/lon/dB ํ์์ด๋ฉด ๊ทธ๋๋ก ์ฌ์ฉ
|
| 51 |
+
df_init = df_u[["lat", "lon", "dB"]].copy()
|
| 52 |
+
elif "์์น" in df_u.columns and "dB" in df_u.columns:
|
| 53 |
+
# ์๋ ํ์: ์์น(WKT), dB โ lat/lon/dB๋ก ๋ณํ
|
| 54 |
+
pos_series = df_u["์์น"].astype(str).str.strip()
|
| 55 |
+
|
| 56 |
+
def safe_load_wkt(s):
|
| 57 |
+
s_up = s.upper()
|
| 58 |
+
if "POINT" not in s_up:
|
| 59 |
+
return None
|
| 60 |
+
try:
|
| 61 |
+
return shp_wkt.loads(s)
|
| 62 |
+
except Exception:
|
| 63 |
+
return None
|
| 64 |
+
|
| 65 |
+
geom = pos_series.apply(safe_load_wkt)
|
| 66 |
+
mask = geom.notnull()
|
| 67 |
+
|
| 68 |
+
if mask.any():
|
| 69 |
+
geom_valid = geom[mask]
|
| 70 |
+
lons = geom_valid.apply(lambda g: round(g.x, 7))
|
| 71 |
+
lats = geom_valid.apply(lambda g: round(g.y, 7))
|
| 72 |
+
dB_vals = pd.to_numeric(df_u.loc[mask, "dB"], errors="coerce")
|
| 73 |
+
|
| 74 |
+
df_init = pd.DataFrame(
|
| 75 |
+
{
|
| 76 |
+
"lat": lats.values,
|
| 77 |
+
"lon": lons.values,
|
| 78 |
+
"dB": dB_vals.values,
|
| 79 |
+
}
|
| 80 |
+
).dropna(subset=["lat", "lon"])
|
| 81 |
+
else:
|
| 82 |
+
df_init = pd.DataFrame(columns=["lat", "lon", "dB"])
|
| 83 |
+
else:
|
| 84 |
+
# ํ์์ ์์๋ณผ ์ ์์ผ๋ฉด ๋น DF
|
| 85 |
+
df_init = pd.DataFrame(columns=["lat", "lon", "dB"])
|
| 86 |
+
else:
|
| 87 |
+
df_init = pd.DataFrame(columns=["lat", "lon", "dB"])
|
| 88 |
+
|
| 89 |
+
# ํ์
๋ณด์
|
| 90 |
+
for col in ["lat", "lon", "dB"]:
|
| 91 |
+
if col not in df_init.columns:
|
| 92 |
+
df_init[col] = pd.Series(dtype=float)
|
| 93 |
+
|
| 94 |
+
|
| 95 |
+
|
| 96 |
+
# -------------------- ์ง๋ ์ด๋ฏธ์ง ์์ฑ --------------------
|
| 97 |
+
def make_map_image(df_points: pd.DataFrame):
|
| 98 |
+
"""์บ ํผ์ค ๊ฒฝ๊ณ + ์ ์ฅ๋ ํฌ์ธํธ๋ค์ ๊ทธ๋ฆฐ PNG ์ด๋ฏธ์ง๋ฅผ numpy ๋ฐฐ์ด๋ก ๋ฐํ."""
|
| 99 |
+
fig, ax = plt.subplots(
|
| 100 |
+
figsize=(IMG_W / 100, IMG_H / 100), dpi=100
|
| 101 |
+
) # โ ์ ํํ IMG_W x IMG_H ํฝ์
|
| 102 |
+
|
| 103 |
+
# ์บ ํผ์ค ํด๋ฆฌ๊ณค (ํ
๋๋ฆฌ๋ง)
|
| 104 |
+
gdf_boundary_3857.plot(
|
| 105 |
+
ax=ax,
|
| 106 |
+
facecolor="none",
|
| 107 |
+
edgecolor="darkblue",
|
| 108 |
+
linewidth=2,
|
| 109 |
+
alpha=1.0,
|
| 110 |
+
)
|
| 111 |
+
|
| 112 |
+
# ๋ฒ ์ด์ค๋งต
|
| 113 |
+
ctx.add_basemap(ax, source=ctx.providers.OpenStreetMap.Mapnik, alpha=0.7)
|
| 114 |
+
|
| 115 |
+
# ์ ์ฅ๋ ํฌ์ธํธ ์ฐ๊ธฐ
|
| 116 |
+
df_points = df_points.dropna(subset=["lat", "lon"])
|
| 117 |
+
if len(df_points) > 0:
|
| 118 |
+
gdf_pts = gpd.GeoDataFrame(
|
| 119 |
+
df_points.copy(),
|
| 120 |
+
geometry=gpd.points_from_xy(df_points["lon"], df_points["lat"]),
|
| 121 |
+
crs=4326,
|
| 122 |
+
).to_crs(epsg=3857)
|
| 123 |
+
|
| 124 |
+
gdf_pts.plot(
|
| 125 |
+
ax=ax,
|
| 126 |
+
column="dB",
|
| 127 |
+
cmap="viridis",
|
| 128 |
+
markersize=40,
|
| 129 |
+
edgecolor="black",
|
| 130 |
+
linewidth=0.3,
|
| 131 |
+
alpha=0.9,
|
| 132 |
+
legend=False,
|
| 133 |
+
zorder=5,
|
| 134 |
+
)
|
| 135 |
+
|
| 136 |
+
# ํด๋ฆฌ๊ณค bounds์ ๋ฑ ๋ง๊ฒ
|
| 137 |
+
ax.set_xlim(BOUND_MINX, BOUND_MAXX)
|
| 138 |
+
ax.set_ylim(BOUND_MINY, BOUND_MAXY)
|
| 139 |
+
ax.axis("off")
|
| 140 |
+
|
| 141 |
+
# ์ฌ๋ฐฑ ์ ๊ฑฐํด์ ์ ์ฒด ์บ๋ฒ์ค๋ฅผ ์ง๋์ ๋ง์ถค
|
| 142 |
+
plt.subplots_adjust(0, 0, 1, 1)
|
| 143 |
+
|
| 144 |
+
# Figure -> PNG bytes -> PIL -> numpy
|
| 145 |
+
buf = io.BytesIO()
|
| 146 |
+
fig.savefig(buf, format="png", dpi=100)
|
| 147 |
+
buf.seek(0)
|
| 148 |
+
img = np.array(Image.open(buf))
|
| 149 |
+
|
| 150 |
+
plt.close(fig)
|
| 151 |
+
return img
|
| 152 |
+
|
| 153 |
+
|
| 154 |
+
# -------------------- ํฝ์
โ ์๊ฒฝ๋ ๋ณํ --------------------
|
| 155 |
+
def pixel_to_latlon(x_px: int, y_px: int):
|
| 156 |
+
"""
|
| 157 |
+
Gradio ์ด๋ฏธ์ง ํด๋ฆญ ์ขํ(ํฝ์
, (x, y))๋ฅผ
|
| 158 |
+
EPSG:3857 โ EPSG:4326(lat, lon)์ผ๋ก ๋ณํ.
|
| 159 |
+
"""
|
| 160 |
+
# x: [0, IMG_W] -> [BOUND_MINX, BOUND_MAXX]
|
| 161 |
+
x_3857 = BOUND_MINX + (BOUND_MAXX - BOUND_MINX) * (x_px / IMG_W)
|
| 162 |
+
# y: ์๊ฐ 0, ์๋๊ฐ IMG_H โ [BOUND_MAXY, BOUND_MINY]๋ก ๋งคํ
|
| 163 |
+
y_3857 = BOUND_MAXY - (BOUND_MAXY - BOUND_MINY) * (y_px / IMG_H)
|
| 164 |
+
|
| 165 |
+
g = gpd.GeoSeries([Point(x_3857, y_3857)], crs=3857).to_crs(epsg=4326)
|
| 166 |
+
pt = g.iloc[0]
|
| 167 |
+
lat, lon = pt.y, pt.x
|
| 168 |
+
|
| 169 |
+
# ์ฌ๊ธฐ์ ์์์ 7์๋ฆฌ๋ก ๋ฐ์ฌ๋ฆผ
|
| 170 |
+
return round(float(lat), 7), round(float(lon), 7)
|
| 171 |
+
|
| 172 |
+
|
| 173 |
+
# -------------------- Gradio ์ฝ๋ฐฑ --------------------
|
| 174 |
+
def on_map_click(img, df_state, evt: gr.SelectData):
|
| 175 |
+
"""์ด๋ฏธ์ง ํด๋ฆญ ์ ์๊ฒฝ๋ ํ
์คํธ ๋ฐ์ค ๊ฐฑ์ ."""
|
| 176 |
+
if evt is None or evt.index is None:
|
| 177 |
+
return None, None
|
| 178 |
+
x, y = evt.index # (x_px, y_px)
|
| 179 |
+
lat, lon = pixel_to_latlon(x, y)
|
| 180 |
+
return lat, lon # ์ด๋ฏธ 7์๋ฆฌ๋ก ๋ฐ์ฌ๋ฆผ๋ ๊ฐ
|
| 181 |
+
|
| 182 |
+
|
| 183 |
+
def add_point(lat, lon, db, df_state):
|
| 184 |
+
"""lat/lon/dB ์ถ๊ฐํ๊ณ CSV ์ ์ฅ + ์ง๋ ๊ฐฑ์ ."""
|
| 185 |
+
if df_state is None or isinstance(df_state, dict):
|
| 186 |
+
df_state = df_init.copy()
|
| 187 |
+
|
| 188 |
+
if lat is None or lon is None or db is None:
|
| 189 |
+
msg = "์๋/๊ฒฝ๋/dB ์
๋ ฅ ์ค๋ฅ."
|
| 190 |
+
return df_state, make_map_image(df_state), df_state, msg
|
| 191 |
+
|
| 192 |
+
try:
|
| 193 |
+
lat = float(lat)
|
| 194 |
+
lon = float(lon)
|
| 195 |
+
db = float(db)
|
| 196 |
+
except ValueError:
|
| 197 |
+
msg = "์ซ์ ์ค๋ฅ."
|
| 198 |
+
return df_state, make_map_image(df_state), df_state, msg
|
| 199 |
+
|
| 200 |
+
# ์์ ํ๊ฒ ํ ๋ฒ ๋ 7์๋ฆฌ๋ก ๋ง์ถค
|
| 201 |
+
lat = round(lat, 7)
|
| 202 |
+
lon = round(lon, 7)
|
| 203 |
+
|
| 204 |
+
# ํด๋ฆฌ๊ณค ์์ธ์ง ์ฒดํฌ
|
| 205 |
+
pt = gpd.GeoSeries([Point(lon, lat)], crs=4326).to_crs(epsg=3857).iloc[0]
|
| 206 |
+
if not poly_3857.contains(pt):
|
| 207 |
+
msg = "์บ ํผ์ค ๊ฒฝ๊ณ ๋ฐ."
|
| 208 |
+
return df_state, make_map_image(df_state), df_state, msg
|
| 209 |
+
|
| 210 |
+
new_row = pd.DataFrame([{"lat": lat, "lon": lon, "dB": db}])
|
| 211 |
+
new_df = pd.concat([df_state, new_row], ignore_index=True)
|
| 212 |
+
|
| 213 |
+
os.makedirs(os.path.dirname(CSV_PATH), exist_ok=True)
|
| 214 |
+
new_df[["lat", "lon", "dB"]].to_csv(CSV_PATH, index=False, encoding="cp949")
|
| 215 |
+
|
| 216 |
+
# ๋ฉ์์ง๋ 7์๋ฆฌ๋ก
|
| 217 |
+
msg = f"{len(new_df)}๊ฐ ์ ์ ์ฅ๋จ (๋ง์ง๋ง: lat={lat:.7f}, lon={lon:.7f}, dB={db:.1f})"
|
| 218 |
+
return new_df, make_map_image(new_df), new_df, msg
|
| 219 |
+
|
| 220 |
+
def load_uploaded_csv(file, df_state):
|
| 221 |
+
"""
|
| 222 |
+
CSV ์
๋ก๋ ์:
|
| 223 |
+
- (์ผ์ด์ค A) '์์น', 'dB' ์ปฌ๋ผ์ด ์์ผ๋ฉด: ์์น(WKT) -> lat/lon, dB ๊ทธ๋๋ก
|
| 224 |
+
- (์ผ์ด์ค B) 'lat', 'lon', 'dB' ์ปฌ๋ผ์ด ์์ผ๋ฉด: ๊ทธ๋๋ก ์ฌ์ฉ
|
| 225 |
+
- ๋ ๋ค ์๋๋ฉด ์๋ฌ
|
| 226 |
+
"""
|
| 227 |
+
if df_state is None or isinstance(df_state, dict):
|
| 228 |
+
df_state = df_init.copy()
|
| 229 |
+
|
| 230 |
+
if file is None:
|
| 231 |
+
msg = "์
๋ก๋๋ ํ์ผ ์์."
|
| 232 |
+
return df_state, make_map_image(df_state), df_state, msg
|
| 233 |
+
|
| 234 |
+
# CSV ์ฝ๊ธฐ (์ธ์ฝ๋ฉ ์๋)
|
| 235 |
+
try:
|
| 236 |
+
df_u = pd.read_csv(file.name, encoding="cp949")
|
| 237 |
+
except UnicodeDecodeError:
|
| 238 |
+
df_u = pd.read_csv(file.name, encoding="utf-8")
|
| 239 |
+
|
| 240 |
+
# ์ปฌ๋ผ ์ด๋ฆ ๊ณต๋ฐฑ/Unnamed ์ ๋ฆฌ
|
| 241 |
+
df_u.columns = [c.strip() for c in df_u.columns]
|
| 242 |
+
df_u = df_u.loc[:, ~df_u.columns.str.contains("^Unnamed")]
|
| 243 |
+
|
| 244 |
+
# ---------- ์ผ์ด์ค B: lat/lon/dB ํ์ ----------
|
| 245 |
+
if {"lat", "lon", "dB"}.issubset(df_u.columns):
|
| 246 |
+
new_df = df_u[["lat", "lon", "dB"]].copy()
|
| 247 |
+
# ์ซ์/๋ฐ์ฌ๋ฆผ ๋ณด์
|
| 248 |
+
new_df["lat"] = pd.to_numeric(new_df["lat"], errors="coerce").round(7)
|
| 249 |
+
new_df["lon"] = pd.to_numeric(new_df["lon"], errors="coerce").round(7)
|
| 250 |
+
new_df["dB"] = pd.to_numeric(new_df["dB"], errors="coerce")
|
| 251 |
+
new_df = new_df.dropna(subset=["lat", "lon"])
|
| 252 |
+
|
| 253 |
+
df_merged = new_df.copy()
|
| 254 |
+
|
| 255 |
+
os.makedirs(os.path.dirname(CSV_PATH), exist_ok=True)
|
| 256 |
+
df_merged[["lat", "lon", "dB"]].to_csv(CSV_PATH, index=False, encoding="cp949")
|
| 257 |
+
|
| 258 |
+
msg = f"lat/lon/dB ํ์ CSV์์ {len(df_merged)}๊ฐ ์ ์ฝ์ด์ด."
|
| 259 |
+
return df_merged, make_map_image(df_merged), df_merged, msg
|
| 260 |
+
|
| 261 |
+
# ---------- ์ผ์ด์ค A: ์์น(WKT), dB ํ์ ----------
|
| 262 |
+
if "์์น" in df_u.columns and "dB" in df_u.columns:
|
| 263 |
+
pos_series = df_u["์์น"].astype(str).str.strip()
|
| 264 |
+
|
| 265 |
+
def safe_load_wkt(s):
|
| 266 |
+
s_up = s.upper()
|
| 267 |
+
if "POINT" not in s_up:
|
| 268 |
+
return None
|
| 269 |
+
try:
|
| 270 |
+
return shp_wkt.loads(s)
|
| 271 |
+
except Exception:
|
| 272 |
+
return None
|
| 273 |
+
|
| 274 |
+
geom = pos_series.apply(safe_load_wkt)
|
| 275 |
+
mask = geom.notnull()
|
| 276 |
+
|
| 277 |
+
if not mask.any():
|
| 278 |
+
msg = "'์์น' ์ปฌ๋ผ์ ์ ํจํ POINT WKT๊ฐ ์๋ค."
|
| 279 |
+
return df_state, make_map_image(df_state), df_state, msg
|
| 280 |
+
|
| 281 |
+
geom_valid = geom[mask]
|
| 282 |
+
lons = geom_valid.apply(lambda g: round(g.x, 7))
|
| 283 |
+
lats = geom_valid.apply(lambda g: round(g.y, 7))
|
| 284 |
+
dB_vals = pd.to_numeric(df_u.loc[mask, "dB"], errors="coerce")
|
| 285 |
+
|
| 286 |
+
new_df = pd.DataFrame(
|
| 287 |
+
{
|
| 288 |
+
"lat": lats.values,
|
| 289 |
+
"lon": lons.values,
|
| 290 |
+
"dB": dB_vals.values,
|
| 291 |
+
}
|
| 292 |
+
).dropna(subset=["lat", "lon"])
|
| 293 |
+
|
| 294 |
+
df_merged = new_df.copy()
|
| 295 |
+
|
| 296 |
+
os.makedirs(os.path.dirname(CSV_PATH), exist_ok=True)
|
| 297 |
+
df_merged[["lat", "lon", "dB"]].to_csv(CSV_PATH, index=False, encoding="cp949")
|
| 298 |
+
|
| 299 |
+
msg = f"[์์น, dB] ํ์ CSV์์ ์ ํจํ ์ {len(df_merged)}๊ฐ ์ฝ์ด์ด."
|
| 300 |
+
return df_merged, make_map_image(df_merged), df_merged, msg
|
| 301 |
+
|
| 302 |
+
# ---------- ๋ ๋ค ์๋๋ฉด ----------
|
| 303 |
+
msg = "CSV ํ์์ ์์๋ณผ ์ ์๋ค. (์์น,dB ๋๋ lat,lon,dB ํ์)"
|
| 304 |
+
return df_state, make_map_image(df_state), df_state, msg
|
| 305 |
+
|
| 306 |
+
|
| 307 |
+
|
| 308 |
+
# -------------------- Gradio ์ฑ --------------------
|
| 309 |
+
def build_app():
|
| 310 |
+
init_img = make_map_image(df_init)
|
| 311 |
+
|
| 312 |
+
with gr.Blocks(title="์์ ์ธก์ ๊ธฐ๋ก๊ธฐ") as demo:
|
| 313 |
+
gr.Markdown(
|
| 314 |
+
"## ์ธํ๋ ์บ ํผ์ค ์์ ์ธก์ \n"
|
| 315 |
+
"- ์ง๋ ์ด๋ฏธ์ง ํด๋ฆญ โ ์/๊ฒฝ๋ ์๋ ์
๋ ฅ โ dB ์ ์ฅ\n"
|
| 316 |
+
"- ๋๋ [์์น, dB] CSV ์
๋ก๋ํด์ ํ ๋ฒ์ ๋ณด์ฌ์ฃผ๊ธฐ"
|
| 317 |
+
)
|
| 318 |
+
|
| 319 |
+
df_state = gr.State(df_init)
|
| 320 |
+
|
| 321 |
+
with gr.Row():
|
| 322 |
+
map_img = gr.Image(
|
| 323 |
+
value=init_img,
|
| 324 |
+
type="numpy",
|
| 325 |
+
label=None,
|
| 326 |
+
interactive=True,
|
| 327 |
+
)
|
| 328 |
+
|
| 329 |
+
with gr.Column():
|
| 330 |
+
lat_box = gr.Number(label="์๋ (lat)", interactive=False)
|
| 331 |
+
lon_box = gr.Number(label="๊ฒฝ๋ (lon)", interactive=False)
|
| 332 |
+
db_box = gr.Number(label="๋ฐ์๋ฒจ (dB)")
|
| 333 |
+
|
| 334 |
+
add_btn = gr.Button("ํ์ฌ ์ขํ ์ถ๊ฐ + CSV ์ ์ฅ", variant="primary")
|
| 335 |
+
csv_upload = gr.File(
|
| 336 |
+
label="CSV ์
๋ก๋ ([์์น, dB] ํ์)",
|
| 337 |
+
file_types=[".csv"],
|
| 338 |
+
)
|
| 339 |
+
|
| 340 |
+
status = gr.Markdown()
|
| 341 |
+
|
| 342 |
+
table = gr.Dataframe(
|
| 343 |
+
value=df_init,
|
| 344 |
+
headers=["lat", "lon", "dB"],
|
| 345 |
+
label="์ ์ฅ๋ ์ธก์ ๊ฐ",
|
| 346 |
+
interactive=False,
|
| 347 |
+
wrap=True,
|
| 348 |
+
)
|
| 349 |
+
|
| 350 |
+
# ์ด๋ฏธ์ง ํด๋ฆญ ์: lat/lon ๊ฐฑ์
|
| 351 |
+
map_img.select(
|
| 352 |
+
fn=on_map_click,
|
| 353 |
+
inputs=[map_img, df_state],
|
| 354 |
+
outputs=[lat_box, lon_box],
|
| 355 |
+
)
|
| 356 |
+
|
| 357 |
+
# ๋ฒํผ ํด๋ฆญ ์: DF/์ง๋/์ํ ๊ฐฑ์ + CSV ์ ์ฅ
|
| 358 |
+
add_btn.click(
|
| 359 |
+
fn=add_point,
|
| 360 |
+
inputs=[lat_box, lon_box, db_box, df_state],
|
| 361 |
+
outputs=[table, map_img, df_state, status],
|
| 362 |
+
)
|
| 363 |
+
|
| 364 |
+
# CSV ์
๋ก๋ ์: ์
๋ก๋ ๋ฐ์ดํฐ๋ก ์ง๋/ํ
์ด๋ธ/์ํ ๊ฐฑ์
|
| 365 |
+
csv_upload.change(
|
| 366 |
+
fn=load_uploaded_csv,
|
| 367 |
+
inputs=[csv_upload, df_state],
|
| 368 |
+
outputs=[table, map_img, df_state, status],
|
| 369 |
+
)
|
| 370 |
+
|
| 371 |
+
return demo
|
| 372 |
+
|
| 373 |
+
|
| 374 |
+
if __name__ == "__main__":
|
| 375 |
+
app = build_app()
|
| 376 |
+
app.launch(share=True)
|
simul.py
ADDED
|
@@ -0,0 +1,539 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# sampling_sim_app.py
|
| 2 |
+
import os
|
| 3 |
+
import io
|
| 4 |
+
|
| 5 |
+
import matplotlib
|
| 6 |
+
matplotlib.use("Agg")
|
| 7 |
+
|
| 8 |
+
import numpy as np
|
| 9 |
+
import pandas as pd
|
| 10 |
+
import geopandas as gpd
|
| 11 |
+
import matplotlib.pyplot as plt
|
| 12 |
+
from shapely.geometry import Point
|
| 13 |
+
from shapely import wkt as shp_wkt
|
| 14 |
+
from PIL import Image
|
| 15 |
+
import contextily as ctx # โ ์ถ๊ฐ
|
| 16 |
+
|
| 17 |
+
import gradio as gr
|
| 18 |
+
|
| 19 |
+
# ----------------- ๊ฒฝ๋ก ์ค์ -----------------
|
| 20 |
+
BASE_DIR = os.path.dirname(__file__)
|
| 21 |
+
DATA_DIR = os.path.join(BASE_DIR, "Data")
|
| 22 |
+
|
| 23 |
+
SHP_PATH = os.path.join(DATA_DIR, "inha_boundary.shp")
|
| 24 |
+
ZONES_PATH = os.path.join(DATA_DIR, "zones_์ต์ข
.geojson")
|
| 25 |
+
|
| 26 |
+
# ์ธก์ ๊ฒฐ๊ณผ CSV (lat, lon, dB ๋๋ ์์น, dB)
|
| 27 |
+
CSV_PATH = os.path.join(DATA_DIR, "์ธก์ ๊ฒฐ๊ณผ_์ต์ข
.csv")
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
# ---------- ์ ํธ: Figure -> numpy ----------
|
| 31 |
+
def fig_to_array(fig, dpi=100):
|
| 32 |
+
buf = io.BytesIO()
|
| 33 |
+
fig.savefig(buf, format="png", dpi=dpi, bbox_inches="tight")
|
| 34 |
+
buf.seek(0)
|
| 35 |
+
img = np.array(Image.open(buf))
|
| 36 |
+
plt.close(fig)
|
| 37 |
+
return img
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
# ---------- ๊ฒฝ๊ณ SHP ๋ก๋ฉ ----------
|
| 41 |
+
def load_boundary():
|
| 42 |
+
gdf4326 = gpd.read_file(SHP_PATH).to_crs(epsg=4326)
|
| 43 |
+
gdf3857 = gdf4326.to_crs(epsg=3857)
|
| 44 |
+
|
| 45 |
+
poly3857 = gdf3857.geometry.unary_union
|
| 46 |
+
if poly3857.geom_type == "MultiPolygon":
|
| 47 |
+
poly3857 = max(poly3857.geoms, key=lambda g: g.area)
|
| 48 |
+
|
| 49 |
+
return gdf4326, gdf3857, poly3857
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
# ---------- ์ธก์ ๊ฒฐ๊ณผ CSV ๋ก๋ฉ ----------
|
| 53 |
+
def load_points_from_csv():
|
| 54 |
+
try:
|
| 55 |
+
df_u = pd.read_csv(CSV_PATH, encoding="cp949")
|
| 56 |
+
except UnicodeDecodeError:
|
| 57 |
+
df_u = pd.read_csv(CSV_PATH, encoding="utf-8")
|
| 58 |
+
|
| 59 |
+
df_u.columns = [c.strip() for c in df_u.columns]
|
| 60 |
+
df_u = df_u.loc[:, ~df_u.columns.str.contains("^Unnamed")]
|
| 61 |
+
|
| 62 |
+
# ์ผ์ด์ค B: ์์น, dB
|
| 63 |
+
if "์์น" in df_u.columns and "dB" in df_u.columns:
|
| 64 |
+
pos_series = df_u["์์น"].astype(str).str.strip()
|
| 65 |
+
|
| 66 |
+
def safe_load_wkt(s):
|
| 67 |
+
s_up = s.upper()
|
| 68 |
+
if "POINT" not in s_up:
|
| 69 |
+
return None
|
| 70 |
+
try:
|
| 71 |
+
return shp_wkt.loads(s)
|
| 72 |
+
except Exception:
|
| 73 |
+
return None
|
| 74 |
+
|
| 75 |
+
geom = pos_series.apply(safe_load_wkt)
|
| 76 |
+
mask = geom.notnull()
|
| 77 |
+
if not mask.any():
|
| 78 |
+
raise ValueError("'์์น' ์ปฌ๋ผ์ ์ ํจํ POINT WKT๊ฐ ์๋ค.")
|
| 79 |
+
|
| 80 |
+
geom_valid = geom[mask]
|
| 81 |
+
lons = geom_valid.apply(lambda g: round(g.x, 7))
|
| 82 |
+
lats = geom_valid.apply(lambda g: round(g.y, 7))
|
| 83 |
+
dBs = pd.to_numeric(df_u.loc[mask, "dB"], errors="coerce")
|
| 84 |
+
|
| 85 |
+
df = pd.DataFrame({"lat": lats, "lon": lons, "dB": dBs}).dropna(
|
| 86 |
+
subset=["lat", "lon"]
|
| 87 |
+
)
|
| 88 |
+
return df
|
| 89 |
+
|
| 90 |
+
# ์ผ์ด์ค A: lat, lon, dB
|
| 91 |
+
if {"lat", "lon", "dB"}.issubset(df_u.columns):
|
| 92 |
+
df = df_u[["lat", "lon", "dB"]].copy()
|
| 93 |
+
df["lat"] = pd.to_numeric(df["lat"], errors="coerce").round(7)
|
| 94 |
+
df["lon"] = pd.to_numeric(df["lon"], errors="coerce").round(7)
|
| 95 |
+
df["dB"] = pd.to_numeric(df["dB"], errors="coerce")
|
| 96 |
+
df = df.dropna(subset=["lat", "lon"])
|
| 97 |
+
return df
|
| 98 |
+
|
| 99 |
+
raise ValueError("CSV๋ (lat, lon, dB) ๋๋ (์์น, dB) ํ์์ด์ด์ผ ํ๋ค.")
|
| 100 |
+
|
| 101 |
+
|
| 102 |
+
# ---------- ๊ตฌ์ญ GeoJSON ๋ก๋ฉ ----------
|
| 103 |
+
def load_zones(poly3857):
|
| 104 |
+
zones4326 = gpd.read_file(ZONES_PATH).to_crs(epsg=4326)
|
| 105 |
+
zones3857 = zones4326.to_crs(epsg=3857)
|
| 106 |
+
|
| 107 |
+
if "zone_id" not in zones3857.columns:
|
| 108 |
+
zones3857["zone_id"] = np.arange(1, len(zones3857) + 1)
|
| 109 |
+
|
| 110 |
+
zones3857["geom_clip"] = zones3857.geometry.intersection(poly3857)
|
| 111 |
+
zones3857["area"] = zones3857["geom_clip"].area
|
| 112 |
+
zones3857 = zones3857[zones3857["area"] > 0].copy()
|
| 113 |
+
|
| 114 |
+
A_total = zones3857["area"].sum()
|
| 115 |
+
zones3857["W_area"] = zones3857["area"] / A_total
|
| 116 |
+
|
| 117 |
+
return zones4326, zones3857
|
| 118 |
+
|
| 119 |
+
|
| 120 |
+
# ---------- ํฌ์ธํธ์ zone_id ๋ถ์ด๊ธฐ ----------
|
| 121 |
+
def attach_zone_id(points_df, zones3857):
|
| 122 |
+
pts4326 = gpd.GeoDataFrame(
|
| 123 |
+
points_df.copy(),
|
| 124 |
+
geometry=gpd.points_from_xy(points_df["lon"], points_df["lat"]),
|
| 125 |
+
crs=4326,
|
| 126 |
+
)
|
| 127 |
+
pts3857 = pts4326.to_crs(epsg=3857)
|
| 128 |
+
|
| 129 |
+
zones_clip = zones3857[["zone_id", "geom_clip"]].copy()
|
| 130 |
+
zones_clip = zones_clip.set_geometry("geom_clip")
|
| 131 |
+
zones_clip = zones_clip.rename_geometry("geometry")
|
| 132 |
+
|
| 133 |
+
joined = gpd.sjoin(
|
| 134 |
+
pts3857,
|
| 135 |
+
zones_clip[["zone_id", "geometry"]],
|
| 136 |
+
how="inner",
|
| 137 |
+
predicate="within",
|
| 138 |
+
)
|
| 139 |
+
|
| 140 |
+
out = joined[["lat", "lon", "dB", "zone_id"]].copy().reset_index(drop=True)
|
| 141 |
+
return out
|
| 142 |
+
|
| 143 |
+
|
| 144 |
+
# ---------- ๊ณตํต ์ค๋น: ๊ฒฝ๊ณ/๊ตฌ์ญ/ํฌ์ธํธ/์ธต์ ๋ณด ----------
|
| 145 |
+
def prepare_sampling_data():
|
| 146 |
+
boundary4326, boundary3857, poly3857 = load_boundary()
|
| 147 |
+
zones4326, zones3857 = load_zones(poly3857)
|
| 148 |
+
df_points = load_points_from_csv()
|
| 149 |
+
points_zone = attach_zone_id(df_points, zones3857)
|
| 150 |
+
|
| 151 |
+
# ์ธต๋ณ ๋ชจ์ง๋จ ํฌ๊ธฐ N_h
|
| 152 |
+
zone_sizes = points_zone.groupby("zone_id").size().rename("N_h")
|
| 153 |
+
zones_info = zones3857[["zone_id", "area", "W_area"]].merge(
|
| 154 |
+
zone_sizes, on="zone_id", how="left"
|
| 155 |
+
)
|
| 156 |
+
zones_info["N_h"] = zones_info["N_h"].fillna(0).astype(int)
|
| 157 |
+
|
| 158 |
+
# ์ธต๋ณ ํ์คํธ์ฐจ S_h (๋ค์ด๋ง ๋ฐฐ๋ถ์ฉ)
|
| 159 |
+
strata_std = points_zone.groupby("zone_id")["dB"].std(ddof=1).rename("S_h")
|
| 160 |
+
zones_info = zones_info.merge(strata_std, on="zone_id", how="left")
|
| 161 |
+
zones_info["S_h"] = zones_info["S_h"].fillna(0.0)
|
| 162 |
+
|
| 163 |
+
return boundary4326, zones4326, df_points, points_zone, zones_info
|
| 164 |
+
|
| 165 |
+
|
| 166 |
+
# ---------- ๋ฉด์ ๋น๋ก n_h ๊ณ์ฐ ----------
|
| 167 |
+
def allocate_n_by_area(zones_info, n_total):
|
| 168 |
+
zones = zones_info.copy()
|
| 169 |
+
zones["n_raw"] = n_total * zones["W_area"]
|
| 170 |
+
zones["n"] = zones["n_raw"].round().astype(int)
|
| 171 |
+
|
| 172 |
+
diff = n_total - zones["n"].sum()
|
| 173 |
+
if diff != 0:
|
| 174 |
+
order = zones["n_raw"].sort_values(ascending=(diff < 0)).index
|
| 175 |
+
for idx in order[:abs(diff)]:
|
| 176 |
+
zones.loc[idx, "n"] += 1 if diff > 0 else -1
|
| 177 |
+
|
| 178 |
+
zones["n"] = zones[["n", "N_h"]].min(axis=1)
|
| 179 |
+
return zones
|
| 180 |
+
|
| 181 |
+
|
| 182 |
+
# ---------- ๋ค์ด๋ง ๋ฐฐ๋ถ n_h ๊ณ์ฐ ----------
|
| 183 |
+
def allocate_n_neyman(zones_info, n_total):
|
| 184 |
+
zones = zones_info.copy()
|
| 185 |
+
if "S_h" not in zones.columns:
|
| 186 |
+
raise ValueError("zones_info์ S_h๊ฐ ์๋ค. ๋ค์ด๋ง ๋ฐฐ๋ถ ์ ์ S_h๋ฅผ ๊ณ์ฐํด์ผ ํ๋ค.")
|
| 187 |
+
|
| 188 |
+
zones["S_h"] = zones["S_h"].fillna(0.0)
|
| 189 |
+
|
| 190 |
+
# ๊ฐ์ค์น โ N_h * S_h
|
| 191 |
+
weight = zones["N_h"] * zones["S_h"]
|
| 192 |
+
if weight.sum() <= 0:
|
| 193 |
+
# ๋ถ์ฐ์ด ์ ๋ถ 0์ด๋ฉด N_h ๋น๋ก๋ก ๋ฐฐ๋ถ
|
| 194 |
+
weight = zones["N_h"].copy()
|
| 195 |
+
|
| 196 |
+
zones["n_raw"] = n_total * weight / weight.sum()
|
| 197 |
+
zones["n"] = zones["n_raw"].round().astype(int)
|
| 198 |
+
|
| 199 |
+
diff = n_total - zones["n"].sum()
|
| 200 |
+
if diff != 0:
|
| 201 |
+
order = zones["n_raw"].sort_values(ascending=(diff < 0)).index
|
| 202 |
+
for idx in order[:abs(diff)]:
|
| 203 |
+
zones.loc[idx, "n"] += 1 if diff > 0 else -1
|
| 204 |
+
|
| 205 |
+
zones["n"] = zones[["n", "N_h"]].min(axis=1)
|
| 206 |
+
return zones
|
| 207 |
+
|
| 208 |
+
|
| 209 |
+
# ---------- ์๋ฎฌ๋ ์ด์
----------
|
| 210 |
+
def simulate_sampling(points_zone_df, zones_info, n, R, strat_label):
|
| 211 |
+
y_all = points_zone_df["dB"].to_numpy()
|
| 212 |
+
N = len(y_all)
|
| 213 |
+
mu_pop = float(np.mean(y_all))
|
| 214 |
+
|
| 215 |
+
zones = zones_info.set_index("zone_id")
|
| 216 |
+
W_h = zones["N_h"] / zones["N_h"].sum()
|
| 217 |
+
n_h = zones["n"]
|
| 218 |
+
|
| 219 |
+
idx_by_zone = {}
|
| 220 |
+
for z in zones.index:
|
| 221 |
+
idx_by_zone[z] = points_zone_df.index[
|
| 222 |
+
points_zone_df["zone_id"] == z
|
| 223 |
+
].to_numpy()
|
| 224 |
+
|
| 225 |
+
srs_means = []
|
| 226 |
+
strat_means = []
|
| 227 |
+
|
| 228 |
+
for _ in range(R):
|
| 229 |
+
# SRS
|
| 230 |
+
n_eff = min(n, N)
|
| 231 |
+
idx_srs = np.random.choice(N, size=n_eff, replace=False)
|
| 232 |
+
mu_srs = float(np.mean(y_all[idx_srs]))
|
| 233 |
+
srs_means.append(mu_srs)
|
| 234 |
+
|
| 235 |
+
# Stratified
|
| 236 |
+
mu_str = 0.0
|
| 237 |
+
for z in zones.index:
|
| 238 |
+
N_h = int(zones.loc[z, "N_h"])
|
| 239 |
+
nh = int(n_h.loc[z])
|
| 240 |
+
if N_h == 0 or nh == 0:
|
| 241 |
+
continue
|
| 242 |
+
idx_pool = idx_by_zone[z]
|
| 243 |
+
if len(idx_pool) < nh:
|
| 244 |
+
nh = len(idx_pool)
|
| 245 |
+
choose = np.random.choice(idx_pool, size=nh, replace=False)
|
| 246 |
+
y_h = points_zone_df.loc[choose, "dB"].to_numpy()
|
| 247 |
+
ybar_h = float(np.mean(y_h))
|
| 248 |
+
mu_str += float(W_h.loc[z]) * ybar_h
|
| 249 |
+
strat_means.append(mu_str)
|
| 250 |
+
|
| 251 |
+
srs_means = np.array(srs_means)
|
| 252 |
+
strat_means = np.array(strat_means)
|
| 253 |
+
|
| 254 |
+
def metrics(arr, name):
|
| 255 |
+
mean_hat = float(arr.mean())
|
| 256 |
+
var_hat = float(arr.var(ddof=1))
|
| 257 |
+
bias = mean_hat - mu_pop
|
| 258 |
+
mse = float(((arr - mu_pop) ** 2).mean())
|
| 259 |
+
return {
|
| 260 |
+
"design": name,
|
| 261 |
+
"mean_hat": mean_hat,
|
| 262 |
+
"var_hat": var_hat,
|
| 263 |
+
"bias": bias,
|
| 264 |
+
"MSE": mse,
|
| 265 |
+
}
|
| 266 |
+
|
| 267 |
+
m_srs = metrics(srs_means, "SRS")
|
| 268 |
+
m_str = metrics(strat_means, strat_label)
|
| 269 |
+
|
| 270 |
+
df_metrics = pd.DataFrame([m_srs, m_str])
|
| 271 |
+
df_metrics["deff_vs_SRS"] = df_metrics["var_hat"] / df_metrics["var_hat"].iloc[0]
|
| 272 |
+
|
| 273 |
+
# ์ซ์ 4์งธ ์๋ฆฌ๊น์ง ๋ฐ์ฌ๋ฆผ
|
| 274 |
+
num_cols = ["mean_hat", "var_hat", "bias", "MSE", "deff_vs_SRS"]
|
| 275 |
+
df_metrics[num_cols] = df_metrics[num_cols].round(4)
|
| 276 |
+
|
| 277 |
+
return mu_pop, srs_means, strat_means, df_metrics
|
| 278 |
+
|
| 279 |
+
|
| 280 |
+
# ---------- ๊ตฌ์ญ ์์ฝ ํ
์ด๋ธ ----------
|
| 281 |
+
def build_zones_table(zones_alloc):
|
| 282 |
+
zones_table = zones_alloc[["zone_id", "area", "W_area", "N_h", "n"]].copy()
|
| 283 |
+
zones_table = zones_table.rename(
|
| 284 |
+
columns={
|
| 285 |
+
"area": "area_m2",
|
| 286 |
+
"W_area": "area_weight",
|
| 287 |
+
"N_h": "N_pop",
|
| 288 |
+
"n": "n_alloc",
|
| 289 |
+
}
|
| 290 |
+
)
|
| 291 |
+
zones_table["sampling_frac"] = zones_table["n_alloc"] / zones_table["N_pop"]
|
| 292 |
+
|
| 293 |
+
total_area_m2 = zones_table["area_m2"].sum()
|
| 294 |
+
total_area_weight = zones_table["area_weight"].sum()
|
| 295 |
+
total_N = zones_table["N_pop"].sum()
|
| 296 |
+
total_n = zones_table["n_alloc"].sum()
|
| 297 |
+
total_sampling_frac = total_n / total_N if total_N > 0 else np.nan
|
| 298 |
+
|
| 299 |
+
total_row = {
|
| 300 |
+
"zone_id": "๏ฟฝ๏ฟฝ๏ฟฝ๊ณ",
|
| 301 |
+
"area_m2": total_area_m2,
|
| 302 |
+
"area_weight": total_area_weight,
|
| 303 |
+
"N_pop": total_N,
|
| 304 |
+
"n_alloc": total_n,
|
| 305 |
+
"sampling_frac": total_sampling_frac,
|
| 306 |
+
}
|
| 307 |
+
|
| 308 |
+
zones_table = zones_table[
|
| 309 |
+
["zone_id", "area_m2", "area_weight", "N_pop", "n_alloc", "sampling_frac"]
|
| 310 |
+
]
|
| 311 |
+
zones_table = pd.concat([zones_table, pd.DataFrame([total_row])], ignore_index=True)
|
| 312 |
+
|
| 313 |
+
# ์ซ์ ์ปฌ๋ผ 4์งธ ์๋ฆฌ๊น์ง ๋ฐ์ฌ๋ฆผ
|
| 314 |
+
num_cols_zone = ["area_m2", "area_weight", "N_pop", "n_alloc", "sampling_frac"]
|
| 315 |
+
for col in num_cols_zone:
|
| 316 |
+
zones_table[col] = pd.to_numeric(zones_table[col], errors="coerce").round(4)
|
| 317 |
+
|
| 318 |
+
return zones_table, float(total_N), float(total_n)
|
| 319 |
+
|
| 320 |
+
|
| 321 |
+
# ---------- ์๊ฐํ ----------
|
| 322 |
+
def plot_population_map(boundary4326, zones4326, points_df):
|
| 323 |
+
g_boundary = boundary4326.to_crs(epsg=3857)
|
| 324 |
+
g_zones = zones4326.to_crs(epsg=3857)
|
| 325 |
+
g_pts = gpd.GeoDataFrame(
|
| 326 |
+
points_df.copy(),
|
| 327 |
+
geometry=gpd.points_from_xy(points_df["lon"], points_df["lat"]),
|
| 328 |
+
crs=4326,
|
| 329 |
+
).to_crs(epsg=3857)
|
| 330 |
+
|
| 331 |
+
fig, ax = plt.subplots(figsize=(8, 8))
|
| 332 |
+
|
| 333 |
+
# ๋ฒ ์ด์ค๋งต ๋จผ์ ๊น๊ธฐ
|
| 334 |
+
minx, miny, maxx, maxy = g_boundary.total_bounds
|
| 335 |
+
ax.set_xlim(minx, maxx)
|
| 336 |
+
ax.set_ylim(miny, maxy)
|
| 337 |
+
ctx.add_basemap(ax, source=ctx.providers.OpenStreetMap.Mapnik, alpha=0.7)
|
| 338 |
+
|
| 339 |
+
# ๊ทธ ์์ ๊ฒฝ๊ณ/๊ตฌ์ญ/ํฌ์ธํธ
|
| 340 |
+
g_boundary.plot(ax=ax, facecolor="none", edgecolor="black", linewidth=2)
|
| 341 |
+
if len(g_zones) > 0:
|
| 342 |
+
g_zones.plot(
|
| 343 |
+
ax=ax,
|
| 344 |
+
facecolor="none",
|
| 345 |
+
edgecolor="red",
|
| 346 |
+
linewidth=1.5,
|
| 347 |
+
alpha=0.7,
|
| 348 |
+
)
|
| 349 |
+
|
| 350 |
+
g_pts.plot(
|
| 351 |
+
ax=ax,
|
| 352 |
+
column="dB",
|
| 353 |
+
cmap="viridis",
|
| 354 |
+
markersize=20,
|
| 355 |
+
edgecolor="black",
|
| 356 |
+
linewidth=0.2,
|
| 357 |
+
legend=False,
|
| 358 |
+
alpha=0.9,
|
| 359 |
+
)
|
| 360 |
+
|
| 361 |
+
ax.set_title("Population points with zones", fontsize=12)
|
| 362 |
+
ax.axis("off")
|
| 363 |
+
plt.tight_layout()
|
| 364 |
+
return fig_to_array(fig)
|
| 365 |
+
|
| 366 |
+
|
| 367 |
+
def plot_histograms(srs_means, strat_means, mu_pop, strat_label):
|
| 368 |
+
fig, ax = plt.subplots(figsize=(8, 5))
|
| 369 |
+
|
| 370 |
+
ax.hist(srs_means, bins=20, alpha=0.5, label="SRS")
|
| 371 |
+
ax.hist(strat_means, bins=20, alpha=0.5, label=strat_label)
|
| 372 |
+
ax.axvline(mu_pop, color="k", linestyle="--", label="Population mean")
|
| 373 |
+
|
| 374 |
+
ax.set_xlabel("Sample mean (dB)")
|
| 375 |
+
ax.set_ylabel("Frequency")
|
| 376 |
+
ax.legend()
|
| 377 |
+
ax.set_title("Sampling distribution of mean")
|
| 378 |
+
plt.tight_layout()
|
| 379 |
+
return fig_to_array(fig)
|
| 380 |
+
|
| 381 |
+
|
| 382 |
+
# ---------- Gradio ์ฝ๋ฐฑ: ๋ฉด์ ๋น๋ก ----------
|
| 383 |
+
def run_sim_area(n, R):
|
| 384 |
+
n = int(n)
|
| 385 |
+
R = int(R)
|
| 386 |
+
|
| 387 |
+
boundary4326, zones4326, df_points, points_zone, zones_info = prepare_sampling_data()
|
| 388 |
+
|
| 389 |
+
# ๋ฉด์ ๋น๋ก ๋ฐฐ๋ถ
|
| 390 |
+
zones_alloc = allocate_n_by_area(zones_info, n)
|
| 391 |
+
zones_table, total_N, total_n = build_zones_table(zones_alloc)
|
| 392 |
+
|
| 393 |
+
mu_pop, srs_means, strat_means, df_metrics = simulate_sampling(
|
| 394 |
+
points_zone, zones_alloc, n, R, "Stratified (area-proportional)"
|
| 395 |
+
)
|
| 396 |
+
|
| 397 |
+
map_img = plot_population_map(boundary4326, zones4326, df_points)
|
| 398 |
+
hist_img = plot_histograms(
|
| 399 |
+
srs_means, strat_means, mu_pop, "Stratified (area-proportional)"
|
| 400 |
+
)
|
| 401 |
+
|
| 402 |
+
summary = (
|
| 403 |
+
f"[๋ฉด์ ๋น๋ก ์ธตํ]\n"
|
| 404 |
+
f"๋ชจ์ง๋จ ํฌ์ธํธ ์: {int(total_N)}๊ฐ\n"
|
| 405 |
+
f"๊ตฌ์ญ ์: {len(zones_alloc)}๊ฐ\n"
|
| 406 |
+
f"๋ชจ์ง๋จ ํ๊ท dB: {mu_pop:.4f}\n"
|
| 407 |
+
f"์ด ํ๋ณธํฌ๊ธฐ n = {int(total_n)} (์
๋ ฅ๊ฐ {n}), ๋ฐ๋ณต R = {R}"
|
| 408 |
+
)
|
| 409 |
+
|
| 410 |
+
return map_img, hist_img, df_metrics, zones_table, summary
|
| 411 |
+
|
| 412 |
+
|
| 413 |
+
# ---------- Gradio ์ฝ๋ฐฑ: ๋ค์ด๋ง ----------
|
| 414 |
+
def run_sim_neyman(n, R):
|
| 415 |
+
n = int(n)
|
| 416 |
+
R = int(R)
|
| 417 |
+
|
| 418 |
+
boundary4326, zones4326, df_points, points_zone, zones_info = prepare_sampling_data()
|
| 419 |
+
|
| 420 |
+
# ๋ค์ด๋ง ๋ฐฐ๋ถ
|
| 421 |
+
zones_alloc = allocate_n_neyman(zones_info, n)
|
| 422 |
+
zones_table, total_N, total_n = build_zones_table(zones_alloc)
|
| 423 |
+
|
| 424 |
+
mu_pop, srs_means, strat_means, df_metrics = simulate_sampling(
|
| 425 |
+
points_zone, zones_alloc, n, R, "Stratified (Neyman)"
|
| 426 |
+
)
|
| 427 |
+
|
| 428 |
+
map_img = plot_population_map(boundary4326, zones4326, df_points)
|
| 429 |
+
hist_img = plot_histograms(
|
| 430 |
+
srs_means, strat_means, mu_pop, "Stratified (Neyman)"
|
| 431 |
+
)
|
| 432 |
+
|
| 433 |
+
summary = (
|
| 434 |
+
f"[๋ค์ด๋ง ์ธตํ]\n"
|
| 435 |
+
f"๋ชจ์ง๋จ ํฌ์ธํธ ์: {int(total_N)}๊ฐ\n"
|
| 436 |
+
f"๊ตฌ์ญ ์: {len(zones_alloc)}๊ฐ\n"
|
| 437 |
+
f"๋ชจ์ง๋จ ํ๊ท dB: {mu_pop:.4f}\n"
|
| 438 |
+
f"์ด ํ๋ณธํฌ๊ธฐ n = {int(total_n)} (์
๋ ฅ๊ฐ {n}), ๋ฐ๋ณต R = {R}"
|
| 439 |
+
)
|
| 440 |
+
|
| 441 |
+
return map_img, hist_img, df_metrics, zones_table, summary
|
| 442 |
+
|
| 443 |
+
|
| 444 |
+
# ---------- Gradio ์ฑ ----------
|
| 445 |
+
def build_app():
|
| 446 |
+
with gr.Blocks(title="ํ๋ณธ์ถ์ถ ์๋ฎฌ๋ ์ด์
(SRS vs ์ธตํ)") as demo:
|
| 447 |
+
|
| 448 |
+
with gr.Tab("SRS vs ๋ฉด์ ๋น๋ก ์ธตํ"):
|
| 449 |
+
with gr.Row():
|
| 450 |
+
n_area = gr.Number(label="ํ๋ณธํฌ๊ธฐ n", value=60, precision=0)
|
| 451 |
+
R_area = gr.Number(label="์๋ฎฌ๋ ์ด์
๋ฐ๋ณต ํ์ R", value=500, precision=0)
|
| 452 |
+
|
| 453 |
+
run_btn_area = gr.Button("๋ฉด์ ๋น๋ก ์ธตํ ์๋ฎฌ๋ ์ด์
์คํ", variant="primary")
|
| 454 |
+
|
| 455 |
+
with gr.Row():
|
| 456 |
+
map_img_area = gr.Image(label="Population + zones")
|
| 457 |
+
hist_img_area = gr.Image(label="Sampling distribution")
|
| 458 |
+
|
| 459 |
+
metrics_table_area = gr.Dataframe(
|
| 460 |
+
headers=[
|
| 461 |
+
"design",
|
| 462 |
+
"mean_hat",
|
| 463 |
+
"var_hat",
|
| 464 |
+
"bias",
|
| 465 |
+
"MSE",
|
| 466 |
+
"deff_vs_SRS",
|
| 467 |
+
],
|
| 468 |
+
label="์ฑ๋ฅ ๋น๊ต ์งํ",
|
| 469 |
+
interactive=False,
|
| 470 |
+
)
|
| 471 |
+
|
| 472 |
+
zones_table_area = gr.Dataframe(
|
| 473 |
+
label="๊ตฌ์ญ๋ณ ๋ฉด์ ๋ฐ ๋ชจ์ง๋จ/๋ฐฐ์ ํ๋ณธ์",
|
| 474 |
+
interactive=False,
|
| 475 |
+
)
|
| 476 |
+
|
| 477 |
+
summary_md_area = gr.Markdown()
|
| 478 |
+
|
| 479 |
+
run_btn_area.click(
|
| 480 |
+
fn=run_sim_area,
|
| 481 |
+
inputs=[n_area, R_area],
|
| 482 |
+
outputs=[
|
| 483 |
+
map_img_area,
|
| 484 |
+
hist_img_area,
|
| 485 |
+
metrics_table_area,
|
| 486 |
+
zones_table_area,
|
| 487 |
+
summary_md_area,
|
| 488 |
+
],
|
| 489 |
+
)
|
| 490 |
+
|
| 491 |
+
with gr.Tab("SRS vs ๋ค์ด๋ง ์ธตํ"):
|
| 492 |
+
with gr.Row():
|
| 493 |
+
n_neyman = gr.Number(label="ํ๋ณธํฌ๊ธฐ n", value=60, precision=0)
|
| 494 |
+
R_neyman = gr.Number(label="์๋ฎฌ๋ ์ด์
๋ฐ๋ณต ํ์ R", value=500, precision=0)
|
| 495 |
+
|
| 496 |
+
run_btn_neyman = gr.Button("๋ค์ด๋ง ์ธตํ ์๋ฎฌ๋ ์ด์
์คํ", variant="primary")
|
| 497 |
+
|
| 498 |
+
with gr.Row():
|
| 499 |
+
map_img_neyman = gr.Image(label="Population + zones")
|
| 500 |
+
hist_img_neyman = gr.Image(label="Sampling distribution")
|
| 501 |
+
|
| 502 |
+
metrics_table_neyman = gr.Dataframe(
|
| 503 |
+
headers=[
|
| 504 |
+
"design",
|
| 505 |
+
"mean_hat",
|
| 506 |
+
"var_hat",
|
| 507 |
+
"bias",
|
| 508 |
+
"MSE",
|
| 509 |
+
"deff_vs_SRS",
|
| 510 |
+
],
|
| 511 |
+
label="์ฑ๋ฅ ๋น๊ต ์งํ",
|
| 512 |
+
interactive=False,
|
| 513 |
+
)
|
| 514 |
+
|
| 515 |
+
zones_table_neyman = gr.Dataframe(
|
| 516 |
+
label="๊ตฌ์ญ๋ณ ๋ฉด์ ๋ฐ ๋ชจ์ง๋จ/๋ฐฐ์ ํ๋ณธ์",
|
| 517 |
+
interactive=False,
|
| 518 |
+
)
|
| 519 |
+
|
| 520 |
+
summary_md_neyman = gr.Markdown()
|
| 521 |
+
|
| 522 |
+
run_btn_neyman.click(
|
| 523 |
+
fn=run_sim_neyman,
|
| 524 |
+
inputs=[n_neyman, R_neyman],
|
| 525 |
+
outputs=[
|
| 526 |
+
map_img_neyman,
|
| 527 |
+
hist_img_neyman,
|
| 528 |
+
metrics_table_neyman,
|
| 529 |
+
zones_table_neyman,
|
| 530 |
+
summary_md_neyman,
|
| 531 |
+
],
|
| 532 |
+
)
|
| 533 |
+
|
| 534 |
+
return demo
|
| 535 |
+
|
| 536 |
+
|
| 537 |
+
if __name__ == "__main__":
|
| 538 |
+
app = build_app()
|
| 539 |
+
app.launch(share=True)
|
tset.ipynb
ADDED
|
@@ -0,0 +1,1135 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"cells": [
|
| 3 |
+
{
|
| 4 |
+
"cell_type": "markdown",
|
| 5 |
+
"id": "9afdef8a",
|
| 6 |
+
"metadata": {},
|
| 7 |
+
"source": [
|
| 8 |
+
"# ๊ฒฝ๊ณ์ ๋ณด ์์ฑ"
|
| 9 |
+
]
|
| 10 |
+
},
|
| 11 |
+
{
|
| 12 |
+
"cell_type": "code",
|
| 13 |
+
"execution_count": 18,
|
| 14 |
+
"id": "014473d8",
|
| 15 |
+
"metadata": {},
|
| 16 |
+
"outputs": [
|
| 17 |
+
{
|
| 18 |
+
"name": "stdout",
|
| 19 |
+
"output_type": "stream",
|
| 20 |
+
"text": [
|
| 21 |
+
"๐ ์ธํ๋ํ๊ต ๊ฒฝ๊ณ ์ ๋ณด ์ถ์ถ ์ค...\n",
|
| 22 |
+
"์๋ต ์ํ ์ฝ๋: 504\n",
|
| 23 |
+
"โ API ์ค๋ฅ ๋ฐ์\n",
|
| 24 |
+
"๐ ๋์ฒด ๋ฐฉ๋ฒ์ ์๋ํฉ๋๋ค...\n",
|
| 25 |
+
"๐ Plan B: ์ขํ ๋ฒ์ ๊ฒ์ ๋ฐฉ๋ฒ...\n",
|
| 26 |
+
"โ ๋์ฒด ๋ฐฉ๋ฒ ์ฑ๊ณต!\n",
|
| 27 |
+
"โ 3๊ฐ์ ์์ ๋ฐ๊ฒฌ\n",
|
| 28 |
+
"๐ ๋ฐ์ ์์ ๊ฐ์: 3\n",
|
| 29 |
+
" [0] type: way, tags: {'amenity': 'university', 'building': 'yes', 'education': 'university', 'name': '๋๋น๋ ๊ด', 'name:en': 'Student Club Hall'}\n",
|
| 30 |
+
" ์ขํ ๊ฐ์: 13\n",
|
| 31 |
+
" ๋ฉด์ : 0.00000008\n",
|
| 32 |
+
" โ ์ถ๊ฐ๋จ\n",
|
| 33 |
+
" [1] type: way, tags: {'amenity': 'university', 'education': 'university', 'name': '์ธํ๋ํ๊ต', 'name:en': 'Inha University', 'name:ja': 'ไป่ทๅคงๅญฆๆ ก', 'name:zh': 'ไป่ทๅคงๅญฆ', 'wikidata': 'Q488851'}\n",
|
| 34 |
+
" ์ขํ ๊ฐ์: 37\n",
|
| 35 |
+
" ๋ฉด์ : 0.00002906\n",
|
| 36 |
+
" โ ์ถ๊ฐ๋จ\n",
|
| 37 |
+
" [2] type: way, tags: {'amenity': 'university', 'education': 'university', 'name': '์ธํ๊ณต์
์ ๋ฌธ๋ํ', 'name:en': 'Inha Technical College', 'name:ja': 'ไป่ทๅทฅๆฅญๅฐ้ๅคงๅญฆ', 'name:zh': 'ไป่ทๅทฅไธไธ้จๅคงๅญฆ'}\n",
|
| 38 |
+
" ์ขํ ๊ฐ์: 26\n",
|
| 39 |
+
" ๋ฉด์ : 0.00001058\n",
|
| 40 |
+
" โ ์ถ๊ฐ๋จ\n",
|
| 41 |
+
"๐ ์ด 3๊ฐ feature ์์ฑ\n",
|
| 42 |
+
" ๊ฐ์ฅ ํฐ polygon ์ ํ (๋ฉด์ : 0.00002906)\n",
|
| 43 |
+
"โ GeoJSON ํ์ผ ์ ์ฅ ์๋ฃ: inha_boundary.geojson\n",
|
| 44 |
+
"โ ์์ฑ ์ด๋ฏธ์ง (Esri) ์ถ๊ฐ ์๋ฃ\n",
|
| 45 |
+
"โ ์์ฑ ์ด๋ฏธ์ง ์ ์ฅ ์๋ฃ: inha_boundary_satellite.png\n",
|
| 46 |
+
"โ ์ง๋ ์คํ์ผ + ํด๋ฆฌํ ์ถ๊ฐ ์๋ฃ\n"
|
| 47 |
+
]
|
| 48 |
+
},
|
| 49 |
+
{
|
| 50 |
+
"name": "stderr",
|
| 51 |
+
"output_type": "stream",
|
| 52 |
+
"text": [
|
| 53 |
+
"C:\\Users\\USER\\AppData\\Local\\Temp\\ipykernel_4744\\1166856351.py:227: DeprecationWarning: The 'unary_union' attribute is deprecated, use the 'union_all()' method instead.\n",
|
| 54 |
+
" poly = gdf_web.geometry.unary_union\n"
|
| 55 |
+
]
|
| 56 |
+
},
|
| 57 |
+
{
|
| 58 |
+
"name": "stdout",
|
| 59 |
+
"output_type": "stream",
|
| 60 |
+
"text": [
|
| 61 |
+
"โ ์ง๋ ์ด๋ฏธ์ง ์ ์ฅ ์๋ฃ: inha_boundary_map.png\n",
|
| 62 |
+
"โ ํด๋ฆฌ๊ณค ์ด๋ฏธ์ง ์ ์ฅ ์๋ฃ: inha_boundary_polygon.png\n",
|
| 63 |
+
"โ Shapefile ์ ์ฅ ์๋ฃ: inha_boundary.shp\n",
|
| 64 |
+
"\n",
|
| 65 |
+
"๐ ๊ฒฝ๊ณ ์ ๋ณด:\n",
|
| 66 |
+
" - ์์ชฝ: 126.649007, ๋จ์ชฝ: 37.446685\n",
|
| 67 |
+
" - ๋์ชฝ: 126.657847, ๋ถ์ชฝ: 37.452137\n",
|
| 68 |
+
" - ์ค์ฌ์ : (126.653435, 37.449753)\n",
|
| 69 |
+
"\n",
|
| 70 |
+
"๐ ์ฒซ ๋ฒ์งธ ๊ฒฝ๊ณ์ ์ขํ:\n",
|
| 71 |
+
" ์ด 37๊ฐ์ ์ขํ์ \n",
|
| 72 |
+
" ์์์ : (126.6504913, 37.4488536)\n",
|
| 73 |
+
" ๋์ : (126.6504913, 37.4488536)\n"
|
| 74 |
+
]
|
| 75 |
+
},
|
| 76 |
+
{
|
| 77 |
+
"name": "stderr",
|
| 78 |
+
"output_type": "stream",
|
| 79 |
+
"text": [
|
| 80 |
+
"c:\\Users\\USER\\anaconda3\\envs\\torch_ev\\lib\\site-packages\\pyogrio\\raw.py:723: RuntimeWarning: Normalized/laundered field name: 'name:en' to 'name_en'\n",
|
| 81 |
+
" ogr_write(\n",
|
| 82 |
+
"c:\\Users\\USER\\anaconda3\\envs\\torch_ev\\lib\\site-packages\\pyogrio\\raw.py:723: RuntimeWarning: Normalized/laundered field name: 'name:ja' to 'name_ja'\n",
|
| 83 |
+
" ogr_write(\n",
|
| 84 |
+
"c:\\Users\\USER\\anaconda3\\envs\\torch_ev\\lib\\site-packages\\pyogrio\\raw.py:723: RuntimeWarning: Normalized/laundered field name: 'name:zh' to 'name_zh'\n",
|
| 85 |
+
" ogr_write(\n"
|
| 86 |
+
]
|
| 87 |
+
}
|
| 88 |
+
],
|
| 89 |
+
"source": [
|
| 90 |
+
"import numpy as np\n",
|
| 91 |
+
"import matplotlib.path as mpath\n",
|
| 92 |
+
"import matplotlib.patches as mpatches\n",
|
| 93 |
+
"import requests\n",
|
| 94 |
+
"import json\n",
|
| 95 |
+
"import geopandas as gpd\n",
|
| 96 |
+
"from shapely.geometry import shape, Polygon, MultiPolygon\n",
|
| 97 |
+
"import matplotlib.pyplot as plt\n",
|
| 98 |
+
"import contextily as ctx\n",
|
| 99 |
+
"from matplotlib import font_manager\n",
|
| 100 |
+
"\n",
|
| 101 |
+
"# ๋์ฒด ๋ฐฉ๋ฒ: ์ขํ ๋ฒ์๋ก ๊ฒ์\n",
|
| 102 |
+
"def get_inha_boundary_alternative():\n",
|
| 103 |
+
" print(\"๐ Plan B: ์ขํ ๋ฒ์ ๊ฒ์ ๋ฐฉ๋ฒ...\")\n",
|
| 104 |
+
" overpass_url = \"http://overpass-api.de/api/interpreter\"\n",
|
| 105 |
+
" \n",
|
| 106 |
+
" # ์ธํ๋ํ๊ต ์ฃผ๋ณ ์์ญ (์๋, ๊ฒฝ๋ ๋ฒ์)\n",
|
| 107 |
+
" overpass_query = f\"\"\"\n",
|
| 108 |
+
" [out:json][timeout:25];\n",
|
| 109 |
+
" (\n",
|
| 110 |
+
" way[\"amenity\"=\"university\"](37.445,126.650,37.456,126.662);\n",
|
| 111 |
+
" relation[\"amenity\"=\"university\"](37.445,126.650,37.456,126.662);\n",
|
| 112 |
+
" way[\"name~\"=\"์ธํ\"](37.445,126.650,37.456,126.662);\n",
|
| 113 |
+
" );\n",
|
| 114 |
+
" out geom;\n",
|
| 115 |
+
" \"\"\"\n",
|
| 116 |
+
" \n",
|
| 117 |
+
" try:\n",
|
| 118 |
+
" response = requests.post(overpass_url, data={'data': overpass_query}, timeout=30)\n",
|
| 119 |
+
" if response.status_code == 200:\n",
|
| 120 |
+
" data = response.json()\n",
|
| 121 |
+
" if data.get('elements'):\n",
|
| 122 |
+
" print(\"โ ๋์ฒด ๋ฐฉ๋ฒ ์ฑ๊ณต!\")\n",
|
| 123 |
+
" return data\n",
|
| 124 |
+
" except Exception as e:\n",
|
| 125 |
+
" print(f\"โ ๏ธ ๋์ฒด ๋ฐฉ๋ฒ ์คํจ: {e}\")\n",
|
| 126 |
+
" \n",
|
| 127 |
+
" print(\"๐ Plan C: ์๋ ๊ฒฝ๊ณ ์์ฑ...\")\n",
|
| 128 |
+
" return create_manual_boundary()\n",
|
| 129 |
+
"\n",
|
| 130 |
+
"# ์๋์ผ๋ก ๊ฒฝ๊ณ ์์ฑ (์ค์ ์ธํ๋ ๋ฉ์ธ ์บ ํผ์ค๋ง)\n",
|
| 131 |
+
"def create_manual_boundary():\n",
|
| 132 |
+
" print(\"โ
์ธํ๋ํ๊ต ๋ฉ์ธ ์บ ํผ์ค ๊ฒฝ๊ณ ์์ฑ\")\n",
|
| 133 |
+
" # ์ธํ๋ํ๊ต ๋ฉ์ธ ์บ ํผ์ค ๊ฒฝ๊ณ (์ ๋ฌธ-5ํธ๊ด-60์ฃผ๋
๊ธฐ๋
๊ด-๋ณธ๊ด-์ฒด์ก๊ด-ํ๋ฌธ ์)\n",
|
| 134 |
+
" coords = [\n",
|
| 135 |
+
" [126.65168, 37.45100], # ์ ๋ฌธ\n",
|
| 136 |
+
" [126.65150, 37.45095],\n",
|
| 137 |
+
" [126.65140, 37.45020],\n",
|
| 138 |
+
" [126.65100, 37.44920],\n",
|
| 139 |
+
" [126.65090, 37.44880],\n",
|
| 140 |
+
" [126.65120, 37.44860],\n",
|
| 141 |
+
" [126.65280, 37.44780],\n",
|
| 142 |
+
" [126.65450, 37.44680],\n",
|
| 143 |
+
" [126.65580, 37.44680], # ๋จ๋์ชฝ ๋ชจ์๋ฆฌ\n",
|
| 144 |
+
" [126.65750, 37.44720],\n",
|
| 145 |
+
" [126.65850, 37.44780],\n",
|
| 146 |
+
" [126.65900, 37.44860],\n",
|
| 147 |
+
" [126.65920, 37.44980],\n",
|
| 148 |
+
" [126.65900, 37.45100], # ๋์ชฝ ๊ฒฝ๊ณ\n",
|
| 149 |
+
" [126.65850, 37.45180],\n",
|
| 150 |
+
" [126.65750, 37.45240],\n",
|
| 151 |
+
" [126.65620, 37.45260], # ๋ถ๋์ชฝ ๋ชจ์๋ฆฌ\n",
|
| 152 |
+
" [126.65500, 37.45250],\n",
|
| 153 |
+
" [126.65380, 37.45220],\n",
|
| 154 |
+
" [126.65250, 37.45180],\n",
|
| 155 |
+
" [126.65168, 37.45100], # ์ ๋ฌธ์ผ๋ก ๋ซ๊ธฐ\n",
|
| 156 |
+
" ]\n",
|
| 157 |
+
" \n",
|
| 158 |
+
" return {\n",
|
| 159 |
+
" 'elements': [{\n",
|
| 160 |
+
" 'type': 'way',\n",
|
| 161 |
+
" 'geometry': [{'lon': c[0], 'lat': c[1]} for c in coords],\n",
|
| 162 |
+
" 'tags': {'name': '์ธํ๋ํ๊ต', 'amenity': 'university'}\n",
|
| 163 |
+
" }]\n",
|
| 164 |
+
" }\n",
|
| 165 |
+
"\n",
|
| 166 |
+
"# OpenStreetMap Overpass API๋ฅผ ์ฌ์ฉํ์ฌ ์ธํ๋ํ๊ต ๊ฒฝ๊ณ ์ถ์ถ\n",
|
| 167 |
+
"def get_inha_boundary():\n",
|
| 168 |
+
" overpass_url = \"http://overpass-api.de/api/interpreter\"\n",
|
| 169 |
+
" \n",
|
| 170 |
+
" # ์ธํ๋ํ๊ต๋ฅผ ๊ฒ์ํ๋ Overpass ์ฟผ๋ฆฌ (๋ ์ ํํ ํํฐ๋ง)\n",
|
| 171 |
+
" overpass_query = \"\"\"\n",
|
| 172 |
+
" [out:json][timeout:25];\n",
|
| 173 |
+
" (\n",
|
| 174 |
+
" way[\"name\"=\"์ธํ๋ํ๊ต\"][\"amenity\"=\"university\"];\n",
|
| 175 |
+
" relation[\"name\"=\"์ธํ๋ํ๊ต\"][\"amenity\"=\"university\"];\n",
|
| 176 |
+
" );\n",
|
| 177 |
+
" out geom;\n",
|
| 178 |
+
" \"\"\"\n",
|
| 179 |
+
" \n",
|
| 180 |
+
" try:\n",
|
| 181 |
+
" response = requests.get(overpass_url, params={'data': overpass_query}, timeout=30)\n",
|
| 182 |
+
" print(f\"์๋ต ์ํ ์ฝ๋: {response.status_code}\")\n",
|
| 183 |
+
" \n",
|
| 184 |
+
" if response.status_code != 200:\n",
|
| 185 |
+
" print(f\"โ API ์ค๋ฅ ๋ฐ์\")\n",
|
| 186 |
+
" print(\"๐ ๋์ฒด ๋ฐฉ๋ฒ์ ์๋ํฉ๋๋ค...\")\n",
|
| 187 |
+
" return get_inha_boundary_alternative()\n",
|
| 188 |
+
" \n",
|
| 189 |
+
" data = response.json()\n",
|
| 190 |
+
" if not data.get('elements'):\n",
|
| 191 |
+
" print(\"โ ๏ธ ๊ฒ์ ๊ฒฐ๊ณผ๊ฐ ์์ต๋๋ค. ๋์ฒด ๋ฐฉ๋ฒ์ ์๋ํฉ๋๋ค...\")\n",
|
| 192 |
+
" return get_inha_boundary_alternative()\n",
|
| 193 |
+
" return data\n",
|
| 194 |
+
" except Exception as e:\n",
|
| 195 |
+
" print(f\"โ ์์ฒญ ์คํจ: {e}\")\n",
|
| 196 |
+
" print(\"๐ ๋์ฒด ๋ฐฉ๋ฒ์ ์๋ํฉ๋๋ค...\")\n",
|
| 197 |
+
" return get_inha_boundary_alternative()\n",
|
| 198 |
+
"\n",
|
| 199 |
+
"# GeoJSON ํ์์ผ๋ก ๋ณํ\n",
|
| 200 |
+
"def convert_to_geojson(osm_data):\n",
|
| 201 |
+
" features = []\n",
|
| 202 |
+
" \n",
|
| 203 |
+
" print(f\"๐ ๋ฐ์ ์์ ๊ฐ์: {len(osm_data.get('elements', []))}\")\n",
|
| 204 |
+
" \n",
|
| 205 |
+
" for idx, element in enumerate(osm_data.get('elements', [])):\n",
|
| 206 |
+
" tags = element.get('tags', {})\n",
|
| 207 |
+
" print(f\" [{idx}] type: {element['type']}, tags: {tags}\")\n",
|
| 208 |
+
" \n",
|
| 209 |
+
" if element['type'] == 'way' and 'geometry' in element:\n",
|
| 210 |
+
" coords = [(node['lon'], node['lat']) for node in element['geometry']]\n",
|
| 211 |
+
" print(f\" ์ขํ ๊ฐ์: {len(coords)}\")\n",
|
| 212 |
+
" \n",
|
| 213 |
+
" if len(coords) > 5: # ์ต์ 5๊ฐ ์ด์\n",
|
| 214 |
+
" try:\n",
|
| 215 |
+
" polygon = Polygon(coords)\n",
|
| 216 |
+
" area = polygon.area\n",
|
| 217 |
+
" print(f\" ๋ฉด์ : {area:.8f}\")\n",
|
| 218 |
+
" \n",
|
| 219 |
+
" if polygon.is_valid:\n",
|
| 220 |
+
" features.append({\n",
|
| 221 |
+
" 'type': 'Feature',\n",
|
| 222 |
+
" 'geometry': polygon.__geo_interface__,\n",
|
| 223 |
+
" 'properties': tags\n",
|
| 224 |
+
" })\n",
|
| 225 |
+
" print(f\" โ ์ถ๊ฐ๋จ\")\n",
|
| 226 |
+
" except Exception as e:\n",
|
| 227 |
+
" print(f\" โ Polygon ์์ฑ ์คํจ: {e}\")\n",
|
| 228 |
+
" \n",
|
| 229 |
+
" elif element['type'] == 'relation' and 'members' in element:\n",
|
| 230 |
+
" all_coords = []\n",
|
| 231 |
+
" for member in element['members']:\n",
|
| 232 |
+
" if 'geometry' in member:\n",
|
| 233 |
+
" coords = [(node['lon'], node['lat']) for node in member['geometry']]\n",
|
| 234 |
+
" all_coords.extend(coords)\n",
|
| 235 |
+
" \n",
|
| 236 |
+
" print(f\" relation ์ขํ ๊ฐ์: {len(all_coords)}\")\n",
|
| 237 |
+
" \n",
|
| 238 |
+
" if len(all_coords) > 5:\n",
|
| 239 |
+
" try:\n",
|
| 240 |
+
" polygon = Polygon(all_coords)\n",
|
| 241 |
+
" if polygon.is_valid:\n",
|
| 242 |
+
" features.append({\n",
|
| 243 |
+
" 'type': 'Feature',\n",
|
| 244 |
+
" 'geometry': polygon.__geo_interface__,\n",
|
| 245 |
+
" 'properties': tags\n",
|
| 246 |
+
" })\n",
|
| 247 |
+
" print(f\" โ relation ์ถ๊ฐ๋จ\")\n",
|
| 248 |
+
" except Exception as e:\n",
|
| 249 |
+
" print(f\" โ Relation polygon ์คํจ: {e}\")\n",
|
| 250 |
+
" \n",
|
| 251 |
+
" print(f\"๐ ์ด {len(features)}๊ฐ feature ์์ฑ\")\n",
|
| 252 |
+
" \n",
|
| 253 |
+
" # ๋ฉด์ ์ด ๊ฐ์ฅ ํฐ polygon ์ ํ\n",
|
| 254 |
+
" if features and len(features) > 1:\n",
|
| 255 |
+
" features.sort(key=lambda f: Polygon(f['geometry']['coordinates'][0]).area, reverse=True)\n",
|
| 256 |
+
" print(f\" ๊ฐ์ฅ ํฐ polygon ์ ํ (๋ฉด์ : {Polygon(features[0]['geometry']['coordinates'][0]).area:.8f})\")\n",
|
| 257 |
+
" features = [features[0]]\n",
|
| 258 |
+
" \n",
|
| 259 |
+
" geojson = {\n",
|
| 260 |
+
" 'type': 'FeatureCollection',\n",
|
| 261 |
+
" 'features': features\n",
|
| 262 |
+
" }\n",
|
| 263 |
+
" \n",
|
| 264 |
+
" return geojson\n",
|
| 265 |
+
"\n",
|
| 266 |
+
"# ๊ฒฝ๊ณ ์๊ฐํ ๋ฐ ์ ์ฅ\n",
|
| 267 |
+
"def visualize_and_save(geojson_data, output_file='inha_boundary.geojson'):\n",
|
| 268 |
+
" # GeoJSON ํ์ผ๋ก ์ ์ฅ\n",
|
| 269 |
+
" with open(output_file, 'w', encoding='utf-8') as f:\n",
|
| 270 |
+
" json.dump(geojson_data, f, ensure_ascii=False, indent=2)\n",
|
| 271 |
+
" print(f\"โ GeoJSON ํ์ผ ์ ์ฅ ์๋ฃ: {output_file}\")\n",
|
| 272 |
+
" \n",
|
| 273 |
+
" # GeoDataFrame์ผ๋ก ๋ณํํ์ฌ ์๊ฐํ\n",
|
| 274 |
+
" if geojson_data['features']:\n",
|
| 275 |
+
" gdf = gpd.GeoDataFrame.from_features(geojson_data['features'])\n",
|
| 276 |
+
" gdf.set_crs(epsg=4326, inplace=True)\n",
|
| 277 |
+
" \n",
|
| 278 |
+
" # Web Mercator ํฌ์๋ฒ์ผ๋ก ๋ณํ\n",
|
| 279 |
+
" gdf_web = gdf.to_crs(epsg=3857)\n",
|
| 280 |
+
" \n",
|
| 281 |
+
" # ํ๊ธ ํฐํธ ์ค์ \n",
|
| 282 |
+
" try:\n",
|
| 283 |
+
" font_path = font_manager.findfont(font_manager.FontProperties(family='Malgun Gothic'))\n",
|
| 284 |
+
" plt.rcParams['font.family'] = 'Malgun Gothic'\n",
|
| 285 |
+
" except:\n",
|
| 286 |
+
" plt.rcParams['font.family'] = 'sans-serif'\n",
|
| 287 |
+
" \n",
|
| 288 |
+
" # ๋ฐฉ๋ฒ 1: ์์ฑ ์ด๋ฏธ์ง (Esri WorldImagery - ์ต์ )\n",
|
| 289 |
+
" fig1, ax1 = plt.subplots(figsize=(15, 12))\n",
|
| 290 |
+
" gdf_web.plot(ax=ax1, facecolor='none', edgecolor='red', linewidth=3, alpha=0.9)\n",
|
| 291 |
+
" \n",
|
| 292 |
+
" try:\n",
|
| 293 |
+
" # ์ต์ ์์ฑ ์ด๋ฏธ์ง ์์ค ์๋\n",
|
| 294 |
+
" ctx.add_basemap(ax1, source=ctx.providers.Esri.WorldImagery, alpha=0.8)\n",
|
| 295 |
+
" print(\"โ ์์ฑ ์ด๋ฏธ์ง (Esri) ์ถ๊ฐ ์๋ฃ\")\n",
|
| 296 |
+
" except:\n",
|
| 297 |
+
" try:\n",
|
| 298 |
+
" # Google Satellite ๋์ฒด\n",
|
| 299 |
+
" ctx.add_basemap(ax1, source='https://mt1.google.com/vt/lyrs=s&x={x}&y={y}&z={z}', alpha=0.8)\n",
|
| 300 |
+
" print(\"โ ์์ฑ ์ด๋ฏธ์ง (Google) ์ถ๊ฐ ์๋ฃ\")\n",
|
| 301 |
+
" except Exception as e:\n",
|
| 302 |
+
" print(f\"โ ๏ธ ์์ฑ ์ด๋ฏธ์ง ์ถ๊ฐ ์คํจ: {e}\")\n",
|
| 303 |
+
" \n",
|
| 304 |
+
" ax1.set_title('์ธํ๋ํ๊ต ๊ฒฝ๊ณ (์์ฑ)', fontsize=18, pad=20, weight='bold')\n",
|
| 305 |
+
" ax1.axis('off')\n",
|
| 306 |
+
" plt.tight_layout()\n",
|
| 307 |
+
" plt.savefig('inha_boundary_satellite.png', dpi=300, bbox_inches='tight', facecolor='white')\n",
|
| 308 |
+
" print(\"โ ์์ฑ ์ด๋ฏธ์ง ์ ์ฅ ์๋ฃ: inha_boundary_satellite.png\")\n",
|
| 309 |
+
" plt.close(fig1)\n",
|
| 310 |
+
" \n",
|
| 311 |
+
" # ๋ฐฉ๋ฒ 2: ์ง๋ ์คํ์ผ (OpenStreetMap)\n",
|
| 312 |
+
" # ๋ฐฉ๋ฒ 2: ์ง๋ ์คํ์ผ (OpenStreetMap) + ๊ฒฝ๊ณ ๋ฐ ๋ฐฐ๊ฒฝ ํด๋ฆฌํ\n",
|
| 313 |
+
" fig2, ax2 = plt.subplots(figsize=(15, 12))\n",
|
| 314 |
+
"\n",
|
| 315 |
+
" # Web Mercator ๊ธฐ์ค ํด๋ฆฌ๊ณค ์ค๋น (ํฉ์ณ์ง ํ๋์ geometry)\n",
|
| 316 |
+
" poly = gdf_web.geometry.unary_union\n",
|
| 317 |
+
"\n",
|
| 318 |
+
" # MultiPolygon์ด๋ฉด ๊ฐ์ฅ ํฐ ๊ฒ ํ๋๋ง ์ฌ์ฉ (์ ํ)\n",
|
| 319 |
+
" if poly.geom_type == \"MultiPolygon\":\n",
|
| 320 |
+
" poly = max(poly.geoms, key=lambda g: g.area)\n",
|
| 321 |
+
"\n",
|
| 322 |
+
" # ํด๋ฆฌ๊ณค์ matplotlib PathPatch๋ก ๋ณํ (clip์ฉ)\n",
|
| 323 |
+
" x, y = poly.exterior.coords.xy\n",
|
| 324 |
+
" coords = np.vstack([x, y]).T\n",
|
| 325 |
+
"\n",
|
| 326 |
+
" Path = mpath.Path\n",
|
| 327 |
+
" path_data = [(Path.MOVETO, coords[0])]\n",
|
| 328 |
+
" for c in coords[1:]:\n",
|
| 329 |
+
" path_data.append((Path.LINETO, c))\n",
|
| 330 |
+
" path_data.append((Path.CLOSEPOLY, coords[0]))\n",
|
| 331 |
+
"\n",
|
| 332 |
+
" codes, verts = zip(*path_data)\n",
|
| 333 |
+
" clip_path = mpath.Path(verts, codes)\n",
|
| 334 |
+
" clip_patch = mpatches.PathPatch(clip_path, facecolor=\"none\", edgecolor=\"none\")\n",
|
| 335 |
+
"\n",
|
| 336 |
+
" ax2.add_patch(clip_patch)\n",
|
| 337 |
+
"\n",
|
| 338 |
+
" # ์ฐ์ ํด๋ฆฌ๊ณค์ ์์น \n",
|
| 339 |
+
" gdf_web.plot(ax=ax2, facecolor='lightblue', edgecolor='darkblue', linewidth=2.5, alpha=0.6)\n",
|
| 340 |
+
"\n",
|
| 341 |
+
" try:\n",
|
| 342 |
+
" ctx.add_basemap(ax2, source=ctx.providers.OpenStreetMap.Mapnik, alpha=0.7)\n",
|
| 343 |
+
" # ๋ฐฉ๊ธ ์ถ๊ฐ๋ ๋ฐฐ๊ฒฝ ์ด๋ฏธ์ง์ ํด๋ฆฝ ์ ์ฉ\n",
|
| 344 |
+
" if ax2.images:\n",
|
| 345 |
+
" ax2.images[-1].set_clip_path(clip_patch)\n",
|
| 346 |
+
" print(\"โ ์ง๋ ์คํ์ผ + ํด๋ฆฌํ ์ถ๊ฐ ์๋ฃ\")\n",
|
| 347 |
+
" except Exception as e:\n",
|
| 348 |
+
" print(f\"โ ๏ธ ์ง๋ ์ถ๊ฐ ์คํจ: {e}\")\n",
|
| 349 |
+
" \n",
|
| 350 |
+
" ax2.set_title('์ธํ๋ํ๊ต ๊ฒฝ๊ณ (์ง๋, boundary ๋ฐ ๋ฐฐ๊ฒฝ ์ ๊ฑฐ)', fontsize=18, pad=20, weight='bold')\n",
|
| 351 |
+
" ax2.axis('off')\n",
|
| 352 |
+
" plt.tight_layout()\n",
|
| 353 |
+
" plt.savefig('inha_boundary_map.png', dpi=300, bbox_inches='tight', facecolor='white')\n",
|
| 354 |
+
" print(\"โ ์ง๋ ์ด๋ฏธ์ง ์ ์ฅ ์๋ฃ: inha_boundary_map.png\")\n",
|
| 355 |
+
" plt.close(fig2)\n",
|
| 356 |
+
"\n",
|
| 357 |
+
" \n",
|
| 358 |
+
" # ๋ฐฉ๋ฒ 3: ๊ฒฝ๊ณ๋ง (ํด๋ฆฌ๊ณค๋ง ๊ฐ์กฐ)\n",
|
| 359 |
+
" fig3, ax3 = plt.subplots(figsize=(12, 10))\n",
|
| 360 |
+
" gdf.plot(ax=ax3, facecolor='#4CAF50', edgecolor='#1B5E20', linewidth=2.5, alpha=0.4)\n",
|
| 361 |
+
" ax3.set_title('์ธํ๋ํ๊ต ์บ ํผ์ค ์์ญ', fontsize=18, pad=20, weight='bold')\n",
|
| 362 |
+
" ax3.set_xlabel('๊ฒฝ๋ (Longitude)', fontsize=12)\n",
|
| 363 |
+
" ax3.set_ylabel('์๋ (Latitude)', fontsize=12)\n",
|
| 364 |
+
" ax3.grid(True, alpha=0.3, linestyle='--', linewidth=0.5)\n",
|
| 365 |
+
" ax3.set_facecolor('#f5f5f5')\n",
|
| 366 |
+
" plt.tight_layout()\n",
|
| 367 |
+
" plt.savefig('inha_boundary_polygon.png', dpi=300, bbox_inches='tight', facecolor='white')\n",
|
| 368 |
+
" print(\"โ ํด๋ฆฌ๊ณค ์ด๋ฏธ์ง ์ ์ฅ ์๋ฃ: inha_boundary_polygon.png\")\n",
|
| 369 |
+
" plt.close(fig3)\n",
|
| 370 |
+
" \n",
|
| 371 |
+
" # Shapefile๋ก๋ ์ ์ฅ (GIS ์ํํธ์จ์ด์์ ์ฌ์ฉ ๊ฐ๋ฅ)\n",
|
| 372 |
+
" try:\n",
|
| 373 |
+
" gdf.to_file('inha_boundary.shp')\n",
|
| 374 |
+
" print(\"โ Shapefile ์ ์ฅ ์๋ฃ: inha_boundary.shp\")\n",
|
| 375 |
+
" except Exception as e:\n",
|
| 376 |
+
" print(f\"โ ๏ธ Shapefile ์ ์ฅ ์คํจ: {e}\")\n",
|
| 377 |
+
" \n",
|
| 378 |
+
" # ๊ฒฝ๊ณ ์ ๋ณด ์ถ๋ ฅ\n",
|
| 379 |
+
" print(f\"\\n๐ ๊ฒฝ๊ณ ์ ๋ณด:\")\n",
|
| 380 |
+
" bounds = gdf.total_bounds\n",
|
| 381 |
+
" print(f\" - ์์ชฝ: {bounds[0]:.6f}, ๋จ์ชฝ: {bounds[1]:.6f}\")\n",
|
| 382 |
+
" print(f\" - ๋์ชฝ: {bounds[2]:.6f}, ๋ถ์ชฝ: {bounds[3]:.6f}\")\n",
|
| 383 |
+
" \n",
|
| 384 |
+
" # CRS ๋ณํ ํ ์ค์ฌ์ ๊ณ์ฐ (๊ฒฝ๊ณ ๋ฐฉ์ง)\n",
|
| 385 |
+
" gdf_projected = gdf.to_crs(epsg=5179) # ํ๊ตญ ํ๋ฉด์ง๊ฐ์ขํ๊ณ\n",
|
| 386 |
+
" centroid_proj = gdf_projected.centroid.iloc[0]\n",
|
| 387 |
+
" centroid_wgs84 = gpd.GeoSeries([centroid_proj], crs=5179).to_crs(4326).iloc[0]\n",
|
| 388 |
+
" print(f\" - ์ค์ฌ์ : ({centroid_wgs84.x:.6f}, {centroid_wgs84.y:.6f})\")\n",
|
| 389 |
+
" \n",
|
| 390 |
+
" return gdf\n",
|
| 391 |
+
" else:\n",
|
| 392 |
+
" print(\"โ ๊ฒฝ๊ณ ๋ฐ์ดํฐ๋ฅผ ์ฐพ์ ์ ์์ต๋๋ค.\")\n",
|
| 393 |
+
" return None\n",
|
| 394 |
+
"\n",
|
| 395 |
+
"# ๋ฉ์ธ ์คํ\n",
|
| 396 |
+
"if __name__ == \"__main__\":\n",
|
| 397 |
+
" print(\"๐ ์ธํ๋ํ๊ต ๊ฒฝ๊ณ ์ ๋ณด ์ถ์ถ ์ค...\")\n",
|
| 398 |
+
" \n",
|
| 399 |
+
" # 1. OSM ๋ฐ์ดํฐ ๊ฐ์ ธ์ค๊ธฐ\n",
|
| 400 |
+
" osm_data = get_inha_boundary()\n",
|
| 401 |
+
" print(f\"โ {len(osm_data.get('elements', []))}๊ฐ์ ์์ ๋ฐ๊ฒฌ\")\n",
|
| 402 |
+
" \n",
|
| 403 |
+
" # 2. GeoJSON์ผ๋ก ๋ณํ\n",
|
| 404 |
+
" geojson = convert_to_geojson(osm_data)\n",
|
| 405 |
+
" \n",
|
| 406 |
+
" # 3. ์ ์ฅ ๋ฐ ์๊ฐํ\n",
|
| 407 |
+
" gdf = visualize_and_save(geojson)\n",
|
| 408 |
+
" \n",
|
| 409 |
+
" # 4. ์ขํ ๋ฐ์ดํฐ ์ถ๋ ฅ (ํ์์)\n",
|
| 410 |
+
" if geojson['features']:\n",
|
| 411 |
+
" print(\"\\n๐ ์ฒซ ๋ฒ์งธ ๊ฒฝ๊ณ์ ์ขํ:\")\n",
|
| 412 |
+
" coords = geojson['features'][0]['geometry']['coordinates']\n",
|
| 413 |
+
" print(f\" ์ด {len(coords[0]) if coords else 0}๊ฐ์ ์ขํ์ \")\n",
|
| 414 |
+
" if coords and len(coords[0]) > 0:\n",
|
| 415 |
+
" print(f\" ์์์ : {coords[0][0]}\")\n",
|
| 416 |
+
" print(f\" ๋์ : {coords[0][-1]}\")"
|
| 417 |
+
]
|
| 418 |
+
},
|
| 419 |
+
{
|
| 420 |
+
"cell_type": "markdown",
|
| 421 |
+
"id": "79139ad6",
|
| 422 |
+
"metadata": {},
|
| 423 |
+
"source": [
|
| 424 |
+
"# ํ์ผ๋ก ๏ฟฝ๏ฟฝ๋ฌ์ค๊ธฐ"
|
| 425 |
+
]
|
| 426 |
+
},
|
| 427 |
+
{
|
| 428 |
+
"cell_type": "code",
|
| 429 |
+
"execution_count": 21,
|
| 430 |
+
"id": "6f2d7463",
|
| 431 |
+
"metadata": {},
|
| 432 |
+
"outputs": [
|
| 433 |
+
{
|
| 434 |
+
"name": "stderr",
|
| 435 |
+
"output_type": "stream",
|
| 436 |
+
"text": [
|
| 437 |
+
"C:\\Users\\USER\\AppData\\Local\\Temp\\ipykernel_4744\\2019802498.py:19: DeprecationWarning: The 'unary_union' attribute is deprecated, use the 'union_all()' method instead.\n",
|
| 438 |
+
" poly = gdf_web.geometry.unary_union\n"
|
| 439 |
+
]
|
| 440 |
+
},
|
| 441 |
+
{
|
| 442 |
+
"name": "stdout",
|
| 443 |
+
"output_type": "stream",
|
| 444 |
+
"text": [
|
| 445 |
+
"โ ์ ์ฅ ์๋ฃ: inha_boundary_map_from_shp.png\n"
|
| 446 |
+
]
|
| 447 |
+
}
|
| 448 |
+
],
|
| 449 |
+
"source": [
|
| 450 |
+
"import geopandas as gpd\n",
|
| 451 |
+
"import matplotlib.pyplot as plt\n",
|
| 452 |
+
"import contextily as ctx\n",
|
| 453 |
+
"import numpy as np\n",
|
| 454 |
+
"import matplotlib.path as mpath\n",
|
| 455 |
+
"import matplotlib.patches as mpatches\n",
|
| 456 |
+
"\n",
|
| 457 |
+
"def plot_clipped_map_from_shp(\n",
|
| 458 |
+
" shp_path=\"inha_boundary.shp\",\n",
|
| 459 |
+
" out_png=\"inha_boundary_map_from_shp.png\"\n",
|
| 460 |
+
"):\n",
|
| 461 |
+
" # 1) Shapefile ์ฝ๊ธฐ (shx/dbf/prj๋ ๊ฐ์ด ์๋์ผ๋ก ์ฝํ)\n",
|
| 462 |
+
" gdf = gpd.read_file(shp_path)\n",
|
| 463 |
+
"\n",
|
| 464 |
+
" # 2) Web Mercator๋ก ๋ณํ (contextily์ฉ)\n",
|
| 465 |
+
" gdf_web = gdf.to_crs(epsg=3857)\n",
|
| 466 |
+
"\n",
|
| 467 |
+
" # 3) ํด๋ฆฌ๊ณค ํ๋๋ก ํฉ์น๊ธฐ (MultiPolygon์ด๋ฉด ๊ฐ์ฅ ํฐ ๊ฒ ์ ํ)\n",
|
| 468 |
+
" poly = gdf_web.geometry.unary_union\n",
|
| 469 |
+
" if poly.geom_type == \"MultiPolygon\":\n",
|
| 470 |
+
" poly = max(poly.geoms, key=lambda g: g.area)\n",
|
| 471 |
+
"\n",
|
| 472 |
+
" # 4) clip์ ์ธ PathPatch ๋ง๋ค๊ธฐ\n",
|
| 473 |
+
" x, y = poly.exterior.coords.xy\n",
|
| 474 |
+
" coords = np.vstack([x, y]).T\n",
|
| 475 |
+
"\n",
|
| 476 |
+
" Path = mpath.Path\n",
|
| 477 |
+
" path_data = [(Path.MOVETO, coords[0])]\n",
|
| 478 |
+
" for c in coords[1:]:\n",
|
| 479 |
+
" path_data.append((Path.LINETO, c))\n",
|
| 480 |
+
" path_data.append((Path.CLOSEPOLY, coords[0]))\n",
|
| 481 |
+
"\n",
|
| 482 |
+
" codes, verts = zip(*path_data)\n",
|
| 483 |
+
" clip_path = mpath.Path(verts, codes)\n",
|
| 484 |
+
" clip_patch = mpatches.PathPatch(clip_path, facecolor=\"none\", edgecolor=\"none\")\n",
|
| 485 |
+
"\n",
|
| 486 |
+
" # 5) ๊ทธ๋ฆผ ์์ฑ\n",
|
| 487 |
+
" fig, ax = plt.subplots(figsize=(15, 12))\n",
|
| 488 |
+
"\n",
|
| 489 |
+
" # ํด๋ฆฌ๊ณค ๋จผ์ ์์น (๊ฒฝ๊ณ ํ์ธ์ฉ)\n",
|
| 490 |
+
" gdf_web.plot(ax=ax, facecolor=\"lightblue\", edgecolor=\"darkblue\", alpha=0.6, linewidth=2)\n",
|
| 491 |
+
"\n",
|
| 492 |
+
" # clip ํจ์น ์ถ๊ฐ\n",
|
| 493 |
+
" ax.add_patch(clip_patch)\n",
|
| 494 |
+
"\n",
|
| 495 |
+
" # 6) basemap ์ถ๊ฐ + ํด๋ฆฌํ\n",
|
| 496 |
+
" ctx.add_basemap(ax, source=ctx.providers.OpenStreetMap.Mapnik, alpha=0.7)\n",
|
| 497 |
+
" if ax.images:\n",
|
| 498 |
+
" ax.images[-1].set_clip_path(clip_patch)\n",
|
| 499 |
+
"\n",
|
| 500 |
+
" # 7) ์บ ํผ์ค ์์ญ๋ง ๋ณด์ด๊ฒ ์ถ ๋ฒ์๋ ํด๋ฆฌ๊ณค์ ๋ง๊ฒ ์๋ผ์ฃผ๊ธฐ\n",
|
| 501 |
+
" minx, miny, maxx, maxy = poly.bounds\n",
|
| 502 |
+
" ax.set_xlim(minx, maxx)\n",
|
| 503 |
+
" ax.set_ylim(miny, maxy)\n",
|
| 504 |
+
" ax.axis(\"off\")\n",
|
| 505 |
+
" plt.tight_layout()\n",
|
| 506 |
+
" plt.savefig(out_png, dpi=300, bbox_inches=\"tight\", facecolor=\"white\")\n",
|
| 507 |
+
" plt.close(fig)\n",
|
| 508 |
+
"\n",
|
| 509 |
+
" print(f\"โ ์ ์ฅ ์๋ฃ: {out_png}\")\n",
|
| 510 |
+
"\n",
|
| 511 |
+
"\n",
|
| 512 |
+
"plot_clipped_map_from_shp()\n"
|
| 513 |
+
]
|
| 514 |
+
},
|
| 515 |
+
{
|
| 516 |
+
"cell_type": "markdown",
|
| 517 |
+
"id": "9ee6be64",
|
| 518 |
+
"metadata": {},
|
| 519 |
+
"source": [
|
| 520 |
+
"# ํ๋ณธ ์ถ์ถ ๋น๊ต"
|
| 521 |
+
]
|
| 522 |
+
},
|
| 523 |
+
{
|
| 524 |
+
"cell_type": "code",
|
| 525 |
+
"execution_count": 29,
|
| 526 |
+
"id": "c68604ed",
|
| 527 |
+
"metadata": {},
|
| 528 |
+
"outputs": [
|
| 529 |
+
{
|
| 530 |
+
"name": "stderr",
|
| 531 |
+
"output_type": "stream",
|
| 532 |
+
"text": [
|
| 533 |
+
"C:\\Users\\USER\\AppData\\Local\\Temp\\ipykernel_4744\\3417582304.py:15: DeprecationWarning: The 'unary_union' attribute is deprecated, use the 'union_all()' method instead.\n",
|
| 534 |
+
" poly = gdf.geometry.unary_union # ํ๋์ ํด๋ฆฌ๊ณค์ผ๋ก ํฉ์น๊ธฐ\n"
|
| 535 |
+
]
|
| 536 |
+
},
|
| 537 |
+
{
|
| 538 |
+
"name": "stdout",
|
| 539 |
+
"output_type": "stream",
|
| 540 |
+
"text": [
|
| 541 |
+
"๊ฒฉ์ ์ธต๋ณ ํ๋ณธ ์ ํ ๋น (๋ฉด์ ๋น๋ก): [ 4 12 7 12 16 9]\n",
|
| 542 |
+
"๋์ผ๋ฉด์ ์ธต๋ณ ํ๋ณธ ์ ํ ๋น (๋์ผ ํ๋ณธ์): [10 10 10 10 10 10]\n"
|
| 543 |
+
]
|
| 544 |
+
},
|
| 545 |
+
{
|
| 546 |
+
"name": "stderr",
|
| 547 |
+
"output_type": "stream",
|
| 548 |
+
"text": [
|
| 549 |
+
"C:\\Users\\USER\\AppData\\Local\\Temp\\ipykernel_4744\\3417582304.py:205: DeprecationWarning: The 'unary_union' attribute is deprecated, use the 'union_all()' method instead.\n",
|
| 550 |
+
" poly_web = gdf_web.geometry.unary_union\n"
|
| 551 |
+
]
|
| 552 |
+
},
|
| 553 |
+
{
|
| 554 |
+
"name": "stdout",
|
| 555 |
+
"output_type": "stream",
|
| 556 |
+
"text": [
|
| 557 |
+
"โ ์๋ณธ ๊ฒฝ๊ณ ์ง๋ ์ ์ฅ: inha_boundary_base.png\n"
|
| 558 |
+
]
|
| 559 |
+
},
|
| 560 |
+
{
|
| 561 |
+
"name": "stderr",
|
| 562 |
+
"output_type": "stream",
|
| 563 |
+
"text": [
|
| 564 |
+
"C:\\Users\\USER\\AppData\\Local\\Temp\\ipykernel_4744\\3417582304.py:205: DeprecationWarning: The 'unary_union' attribute is deprecated, use the 'union_all()' method instead.\n",
|
| 565 |
+
" poly_web = gdf_web.geometry.unary_union\n"
|
| 566 |
+
]
|
| 567 |
+
},
|
| 568 |
+
{
|
| 569 |
+
"name": "stdout",
|
| 570 |
+
"output_type": "stream",
|
| 571 |
+
"text": [
|
| 572 |
+
"โ SRS ์ํ ์ง๋ ์ ์ฅ: inha_sampling_srs.png\n"
|
| 573 |
+
]
|
| 574 |
+
},
|
| 575 |
+
{
|
| 576 |
+
"name": "stderr",
|
| 577 |
+
"output_type": "stream",
|
| 578 |
+
"text": [
|
| 579 |
+
"C:\\Users\\USER\\AppData\\Local\\Temp\\ipykernel_4744\\3417582304.py:205: DeprecationWarning: The 'unary_union' attribute is deprecated, use the 'union_all()' method instead.\n",
|
| 580 |
+
" poly_web = gdf_web.geometry.unary_union\n"
|
| 581 |
+
]
|
| 582 |
+
},
|
| 583 |
+
{
|
| 584 |
+
"name": "stdout",
|
| 585 |
+
"output_type": "stream",
|
| 586 |
+
"text": [
|
| 587 |
+
"โ ์ธตํ ์ํ ์ง๋ ์ ์ฅ: inha_sampling_strata.png\n"
|
| 588 |
+
]
|
| 589 |
+
},
|
| 590 |
+
{
|
| 591 |
+
"name": "stderr",
|
| 592 |
+
"output_type": "stream",
|
| 593 |
+
"text": [
|
| 594 |
+
"C:\\Users\\USER\\AppData\\Local\\Temp\\ipykernel_4744\\3417582304.py:205: DeprecationWarning: The 'unary_union' attribute is deprecated, use the 'union_all()' method instead.\n",
|
| 595 |
+
" poly_web = gdf_web.geometry.unary_union\n"
|
| 596 |
+
]
|
| 597 |
+
},
|
| 598 |
+
{
|
| 599 |
+
"name": "stdout",
|
| 600 |
+
"output_type": "stream",
|
| 601 |
+
"text": [
|
| 602 |
+
"โ ๋์ผ๋ฉด์ ์ธตํ ์ํ ์ง๋ ์ ์ฅ: inha_sampling_strata_equalarea.png\n",
|
| 603 |
+
"\n",
|
| 604 |
+
"[SRS ์ํ ์ขํ (EPSG:5179)]\n",
|
| 605 |
+
" design geometry\n",
|
| 606 |
+
"0 SRS POINT (925278.467 1939423.964)\n",
|
| 607 |
+
"1 SRS POINT (925060.691 1939262.149)\n",
|
| 608 |
+
"2 SRS POINT (925344.356 1939270.6)\n",
|
| 609 |
+
"3 SRS POINT (925259.687 1939296.418)\n",
|
| 610 |
+
"4 SRS POINT (925386.793 1939152.443)\n",
|
| 611 |
+
"\n",
|
| 612 |
+
"[๊ฒฉ์ ์ธตํ ์ํ ์ขํ (EPSG:5179)]\n",
|
| 613 |
+
" stratum_id geometry\n",
|
| 614 |
+
"0 0 POINT (924882.652 1939247.19)\n",
|
| 615 |
+
"1 0 POINT (924924.472 1939181.424)\n",
|
| 616 |
+
"2 0 POINT (924947.85 1939212.952)\n",
|
| 617 |
+
"3 0 POINT (924930.148 1939196.918)\n",
|
| 618 |
+
"4 1 POINT (925147.586 1939174.715)\n",
|
| 619 |
+
"\n",
|
| 620 |
+
"[๋์ผ๋ฉด์ ์ธตํ ์ํ ์ขํ (EPSG:5179)]\n",
|
| 621 |
+
" stratum_id geometry\n",
|
| 622 |
+
"0 0 POINT (924846.854 1939231.61)\n",
|
| 623 |
+
"1 0 POINT (924830.9 1939503.537)\n",
|
| 624 |
+
"2 0 POINT (924832.812 1939290.495)\n",
|
| 625 |
+
"3 0 POINT (924882.953 1939275.119)\n",
|
| 626 |
+
"4 0 POINT (924776.295 1939433.993)\n"
|
| 627 |
+
]
|
| 628 |
+
}
|
| 629 |
+
],
|
| 630 |
+
"source": [
|
| 631 |
+
"import numpy as np\n",
|
| 632 |
+
"import geopandas as gpd\n",
|
| 633 |
+
"from shapely.geometry import Point, box\n",
|
| 634 |
+
"import matplotlib.pyplot as plt\n",
|
| 635 |
+
"import contextily as ctx\n",
|
| 636 |
+
"import matplotlib.path as mpath\n",
|
| 637 |
+
"import matplotlib.patches as mpatches\n",
|
| 638 |
+
"\n",
|
| 639 |
+
"# ===========================\n",
|
| 640 |
+
"# 1. ๊ณตํต: ๊ฒฝ๊ณ ๋ถ๋ฌ์ค๊ธฐ\n",
|
| 641 |
+
"# ===========================\n",
|
| 642 |
+
"def load_inha_boundary(shp_path=\"inha_boundary.shp\"):\n",
|
| 643 |
+
" gdf = gpd.read_file(shp_path) # prj ๊ธฐ์ค์ผ๋ก CRS ์ธ์\n",
|
| 644 |
+
" gdf = gdf.to_crs(epsg=5179) # ํ๊ตญ ํ๋ฉด์ง๊ฐ์ขํ๊ณ\n",
|
| 645 |
+
" poly = gdf.geometry.unary_union # ํ๋์ ํด๋ฆฌ๊ณค์ผ๋ก ํฉ์น๊ธฐ\n",
|
| 646 |
+
" return gdf, poly\n",
|
| 647 |
+
"\n",
|
| 648 |
+
"\n",
|
| 649 |
+
"# ===========================\n",
|
| 650 |
+
"# 2. ํด๋ฆฌ๊ณค ๋ด๋ถ ๋๋ค ์ํ๋ง (SRS)\n",
|
| 651 |
+
"# ===========================\n",
|
| 652 |
+
"def random_points_in_polygon(poly, n):\n",
|
| 653 |
+
" minx, miny, maxx, maxy = poly.bounds\n",
|
| 654 |
+
" points = []\n",
|
| 655 |
+
" # rejection sampling: bounding box์์ ๋ฝ์์, ํด๋ฆฌ๊ณค ์๋ง ์ฌ์ฉ\n",
|
| 656 |
+
" while len(points) < n:\n",
|
| 657 |
+
" xs = np.random.uniform(minx, maxx, n * 2)\n",
|
| 658 |
+
" ys = np.random.uniform(miny, maxy, n * 2)\n",
|
| 659 |
+
" for x, y in zip(xs, ys):\n",
|
| 660 |
+
" p = Point(x, y)\n",
|
| 661 |
+
" if poly.contains(p): # ๊ฒฝ๊ณ๊น์ง ํฌํจํ๋ ค๋ฉด contains ๋์ covers ์จ๋ ๋จ\n",
|
| 662 |
+
" points.append(p)\n",
|
| 663 |
+
" if len(points) == n:\n",
|
| 664 |
+
" break\n",
|
| 665 |
+
" return points\n",
|
| 666 |
+
"\n",
|
| 667 |
+
"\n",
|
| 668 |
+
"# ===========================\n",
|
| 669 |
+
"# 3-1. ํด๋ฆฌ๊ณค์ ๊ฒฉ์๋ก ๋๋ ํ, ์ธต(๊ตฌ์ญ) ๋ง๋ค๊ธฐ (๊ธฐ์กด ๋ฐฉ์)\n",
|
| 670 |
+
"# ===========================\n",
|
| 671 |
+
"def make_strata(poly, n_rows=2, n_cols=3):\n",
|
| 672 |
+
" \"\"\"\n",
|
| 673 |
+
" n_rows x n_cols ๊ฒฉ์ ์์ฑ ํ,\n",
|
| 674 |
+
" ๊ฐ cell๊ณผ ์บ ํผ์ค ํด๋ฆฌ๊ณค์ ๊ต์ฐจ(intersection)๋ฅผ strata๋ก ์ฌ์ฉ\n",
|
| 675 |
+
" \"\"\"\n",
|
| 676 |
+
" minx, miny, maxx, maxy = poly.bounds\n",
|
| 677 |
+
" dx = (maxx - minx) / n_cols\n",
|
| 678 |
+
" dy = (maxy - miny) / n_rows\n",
|
| 679 |
+
"\n",
|
| 680 |
+
" strata_geoms = []\n",
|
| 681 |
+
" for i in range(n_rows):\n",
|
| 682 |
+
" for j in range(n_cols):\n",
|
| 683 |
+
" cell = box(\n",
|
| 684 |
+
" minx + j * dx,\n",
|
| 685 |
+
" miny + i * dy,\n",
|
| 686 |
+
" minx + (j + 1) * dx,\n",
|
| 687 |
+
" miny + (i + 1) * dy,\n",
|
| 688 |
+
" )\n",
|
| 689 |
+
" inter = cell.intersection(poly)\n",
|
| 690 |
+
" if not inter.is_empty and inter.area > 0:\n",
|
| 691 |
+
" strata_geoms.append(inter)\n",
|
| 692 |
+
"\n",
|
| 693 |
+
" strata_gdf = gpd.GeoDataFrame(\n",
|
| 694 |
+
" {\"stratum_id\": range(len(strata_geoms))},\n",
|
| 695 |
+
" geometry=strata_geoms,\n",
|
| 696 |
+
" crs=\"EPSG:5179\"\n",
|
| 697 |
+
" )\n",
|
| 698 |
+
" return strata_gdf\n",
|
| 699 |
+
"\n",
|
| 700 |
+
"\n",
|
| 701 |
+
"# ===========================\n",
|
| 702 |
+
"# 3-2. ๋์ผ๋ฉด์ ์ผ๋ก ๋๋๋ ์ธต(๊ตฌ์ญ) ๋ง๋ค๊ธฐ\n",
|
| 703 |
+
"# - x์ถ ๋ฐฉํฅ์ผ๋ก ์๋ผ์ ๊ฐ ๋ฐด๋์ ํด๋ฆฌ๊ณค ๋ฉด์ ์ด ๊ฑฐ์ ๊ฐ๊ฒ\n",
|
| 704 |
+
"# ===========================\n",
|
| 705 |
+
"# ===========================\n",
|
| 706 |
+
"# 3-2. ๋์ผ๋ฉด์ ์ผ๋ก ๋๋๋ ์ธต(๊ตฌ์ญ) ๋ง๋ค๊ธฐ (๋น ๋ฅธ ๊ทผ์ฌ ๋ฒ์ )\n",
|
| 707 |
+
"# - ํด๋ฆฌ๊ณค ์์ ๋ฌด์์ ์ ๋ง์ด ๋ฝ๊ณ \n",
|
| 708 |
+
"# - x์ขํ ๊ธฐ์ค์ผ๋ก 6๋ฑ๋ถ(quantile) โ ๊ฑฐ์ ๋์ผ๋ฉด์ ์คํธ๋ฆฝ\n",
|
| 709 |
+
"# ===========================\n",
|
| 710 |
+
"def make_equal_area_strata(poly, n_strata=6, n_mc=10000):\n",
|
| 711 |
+
" \"\"\"\n",
|
| 712 |
+
" poly๋ฅผ x์ถ ๋ฐฉํฅ ์คํธ๋ฆฝ n_strata๊ฐ๋ก ๋๋๋,\n",
|
| 713 |
+
" ํด๋ฆฌ๊ณค ๋ด๋ถ์ ๊ท ์ผ ์ํ๋งํ ์ ๋ค์ x์ขํ ๋ถํฌ๋ฅผ ์ด์ฉํด\n",
|
| 714 |
+
" '๊ทผ์ฌ ๋์ผ๋ฉด์ '์ด ๋๋๋ก ์๋ฅธ๋ค.\n",
|
| 715 |
+
" - n_mc: ๋ชฌํ
์นด๋ฅผ๋ก ํฌ์ธํธ ๊ฐ์ (๋ง์์๋ก ๋ฉด์ ๊ทผ์ฌ ์ ํ, ๋๋ ค์ง)\n",
|
| 716 |
+
" \"\"\"\n",
|
| 717 |
+
"\n",
|
| 718 |
+
" # 1) ํด๋ฆฌ๊ณค ๋ด๋ถ์ ๋ชฌํ
์นด๋ฅผ๋ก ํฌ์ธํธ ์์ฑ\n",
|
| 719 |
+
" mc_points = random_points_in_polygon(poly, n_mc)\n",
|
| 720 |
+
" xs = np.array([p.x for p in mc_points])\n",
|
| 721 |
+
"\n",
|
| 722 |
+
" # 2) x์ขํ ์ ๋ ฌ ํ, n_strata๋ฑ๋ถ quantile ์์น ์ฐพ๊ธฐ\n",
|
| 723 |
+
" xs_sorted = np.sort(xs)\n",
|
| 724 |
+
" cuts = []\n",
|
| 725 |
+
" for i in range(1, n_strata):\n",
|
| 726 |
+
" q = i / n_strata\n",
|
| 727 |
+
" idx = int(q * len(xs_sorted))\n",
|
| 728 |
+
" cuts.append(xs_sorted[idx])\n",
|
| 729 |
+
"\n",
|
| 730 |
+
" # 3) ์๋ผ๋ผ x ๊ฒฝ๊ณ ๋ง๋ค๊ธฐ (์ข/์ฐ ๋ ํฌํจ)\n",
|
| 731 |
+
" minx, miny, maxx, maxy = poly.bounds\n",
|
| 732 |
+
" x_edges = [minx] + cuts + [maxx]\n",
|
| 733 |
+
"\n",
|
| 734 |
+
" # 4) ๊ฐ ์คํธ๋ฆฝ๊ณผ ํด๋ฆฌ๊ณค์ ๊ต์ฐจ๋ก strata ์์ฑ (intersection์ ์คํธ๋ฆฝ ๊ฐ์๋งํผ ๋ฑ 6๋ฒ)\n",
|
| 735 |
+
" strata_geoms = []\n",
|
| 736 |
+
" for j in range(n_strata):\n",
|
| 737 |
+
" cell = box(x_edges[j], miny, x_edges[j + 1], maxy)\n",
|
| 738 |
+
" inter = poly.intersection(cell)\n",
|
| 739 |
+
" if not inter.is_empty and inter.area > 0:\n",
|
| 740 |
+
" strata_geoms.append(inter)\n",
|
| 741 |
+
"\n",
|
| 742 |
+
" strata_gdf = gpd.GeoDataFrame(\n",
|
| 743 |
+
" {\"stratum_id\": range(len(strata_geoms))},\n",
|
| 744 |
+
" geometry=strata_geoms,\n",
|
| 745 |
+
" crs=\"EPSG:5179\"\n",
|
| 746 |
+
" )\n",
|
| 747 |
+
" return strata_gdf\n",
|
| 748 |
+
"\n",
|
| 749 |
+
"\n",
|
| 750 |
+
"\n",
|
| 751 |
+
"\n",
|
| 752 |
+
"# ===========================\n",
|
| 753 |
+
"# 4-1. ์ธตํ ์ํ๋ง (๋ฉด์ ๋น๋ก ํ ๋น, ๊ธฐ์กด)\n",
|
| 754 |
+
"# ===========================\n",
|
| 755 |
+
"def stratified_sampling(poly_strata_gdf, n_total):\n",
|
| 756 |
+
" areas = poly_strata_gdf.geometry.area.values\n",
|
| 757 |
+
" props = areas / areas.sum()\n",
|
| 758 |
+
"\n",
|
| 759 |
+
" # ๋ฉด์ ๋น๋ก ์ด๊ธฐ ํ ๋น\n",
|
| 760 |
+
" n_alloc = np.round(props * n_total).astype(int)\n",
|
| 761 |
+
"\n",
|
| 762 |
+
" # ์ดํฉ ๋ณด์ (sum == n_total ๋๋๋ก)\n",
|
| 763 |
+
" diff = n_total - n_alloc.sum()\n",
|
| 764 |
+
" if diff > 0:\n",
|
| 765 |
+
" # ๋ ํ์ํ ๋งํผ, ๋ฉด์ ์ด ํฐ ์ธต๋ถํฐ 1์ฉ ์ถ๊ฐ\n",
|
| 766 |
+
" idx_order = np.argsort(-areas)\n",
|
| 767 |
+
" for k in range(diff):\n",
|
| 768 |
+
" n_alloc[idx_order[k % len(n_alloc)]] += 1\n",
|
| 769 |
+
" elif diff < 0:\n",
|
| 770 |
+
" # ๋๋ฌด ๋ง์ด ํ ๋น๋ ๊ฒฝ์ฐ, ๋ฉด์ ์ด ์์ ์ธต๋ถํฐ 1์ฉ ๊ฐ์ (0 ๋ฐ์ผ๋ก๋ ์ ๊ฐ๊ฒ)\n",
|
| 771 |
+
" idx_order = np.argsort(areas)\n",
|
| 772 |
+
" k = 0\n",
|
| 773 |
+
" while diff < 0:\n",
|
| 774 |
+
" i = idx_order[k % len(n_alloc)]\n",
|
| 775 |
+
" if n_alloc[i] > 1: # ์ต์ 1๊ฐ๋ ์ ์ง\n",
|
| 776 |
+
" n_alloc[i] -= 1\n",
|
| 777 |
+
" diff += 1\n",
|
| 778 |
+
" k += 1\n",
|
| 779 |
+
"\n",
|
| 780 |
+
" # ๊ฐ ์ธต์์ ์ํ๋ง\n",
|
| 781 |
+
" all_points = []\n",
|
| 782 |
+
" stratum_ids = []\n",
|
| 783 |
+
" for geom, sid, n_i in zip(poly_strata_gdf.geometry,\n",
|
| 784 |
+
" poly_strata_gdf[\"stratum_id\"],\n",
|
| 785 |
+
" n_alloc):\n",
|
| 786 |
+
" pts = random_points_in_polygon(geom, n_i)\n",
|
| 787 |
+
" all_points.extend(pts)\n",
|
| 788 |
+
" stratum_ids.extend([sid] * len(pts))\n",
|
| 789 |
+
"\n",
|
| 790 |
+
" sample_gdf = gpd.GeoDataFrame(\n",
|
| 791 |
+
" {\"stratum_id\": stratum_ids},\n",
|
| 792 |
+
" geometry=all_points,\n",
|
| 793 |
+
" crs=poly_strata_gdf.crs,\n",
|
| 794 |
+
" )\n",
|
| 795 |
+
" return sample_gdf, n_alloc\n",
|
| 796 |
+
"\n",
|
| 797 |
+
"\n",
|
| 798 |
+
"# ===========================\n",
|
| 799 |
+
"# 4-2. ์ธตํ ์ํ๋ง (๋์ผ ํ๋ณธ์ ํ ๋น: n_total์ ์ธต ๊ฐ์๋ก ๊ท ๋ฑ ๋ถ๋ฐฐ)\n",
|
| 800 |
+
"# ===========================\n",
|
| 801 |
+
"def stratified_sampling_equal_n(poly_strata_gdf, n_total):\n",
|
| 802 |
+
" n_strata = len(poly_strata_gdf)\n",
|
| 803 |
+
" base = n_total // n_strata\n",
|
| 804 |
+
" rem = n_total % n_strata\n",
|
| 805 |
+
"\n",
|
| 806 |
+
" n_alloc = np.array([base] * n_strata)\n",
|
| 807 |
+
" for i in range(rem):\n",
|
| 808 |
+
" n_alloc[i] += 1\n",
|
| 809 |
+
"\n",
|
| 810 |
+
" all_points = []\n",
|
| 811 |
+
" stratum_ids = []\n",
|
| 812 |
+
" for geom, sid, n_i in zip(poly_strata_gdf.geometry,\n",
|
| 813 |
+
" poly_strata_gdf[\"stratum_id\"],\n",
|
| 814 |
+
" n_alloc):\n",
|
| 815 |
+
" pts = random_points_in_polygon(geom, n_i)\n",
|
| 816 |
+
" all_points.extend(pts)\n",
|
| 817 |
+
" stratum_ids.extend([sid] * len(pts))\n",
|
| 818 |
+
"\n",
|
| 819 |
+
" sample_gdf = gpd.GeoDataFrame(\n",
|
| 820 |
+
" {\"stratum_id\": stratum_ids},\n",
|
| 821 |
+
" geometry=all_points,\n",
|
| 822 |
+
" crs=poly_strata_gdf.crs,\n",
|
| 823 |
+
" )\n",
|
| 824 |
+
" return sample_gdf, n_alloc\n",
|
| 825 |
+
"\n",
|
| 826 |
+
"\n",
|
| 827 |
+
"# ===========================\n",
|
| 828 |
+
"# 5. ํด๋ฆฌํ์ฉ ํจ์น ์์ฑ\n",
|
| 829 |
+
"# ===========================\n",
|
| 830 |
+
"def make_clip_patch_and_poly_web(boundary_gdf_5179):\n",
|
| 831 |
+
" \"\"\"\n",
|
| 832 |
+
" ๊ฒฝ๊ณ gdf(EPGS:5179)์์ Web Mercator(3857) ๊ธฐ์ค ํด๋ฆฌ๊ณค + clip์ฉ PathPatch ๋ฐํ\n",
|
| 833 |
+
" \"\"\"\n",
|
| 834 |
+
" gdf_web = boundary_gdf_5179.to_crs(epsg=3857)\n",
|
| 835 |
+
" poly_web = gdf_web.geometry.unary_union\n",
|
| 836 |
+
"\n",
|
| 837 |
+
" # MultiPolygon์ด๋ฉด ๊ฐ์ฅ ํฐ ๊ฒ ์ฌ์ฉ\n",
|
| 838 |
+
" if poly_web.geom_type == \"MultiPolygon\":\n",
|
| 839 |
+
" poly_web = max(poly_web.geoms, key=lambda g: g.area)\n",
|
| 840 |
+
"\n",
|
| 841 |
+
" x, y = poly_web.exterior.coords.xy\n",
|
| 842 |
+
" coords = np.vstack([x, y]).T\n",
|
| 843 |
+
"\n",
|
| 844 |
+
" Path = mpath.Path\n",
|
| 845 |
+
" path_data = [(Path.MOVETO, coords[0])]\n",
|
| 846 |
+
" for c in coords[1:]:\n",
|
| 847 |
+
" path_data.append((Path.LINETO, c))\n",
|
| 848 |
+
" path_data.append((Path.CLOSEPOLY, coords[0]))\n",
|
| 849 |
+
"\n",
|
| 850 |
+
" codes, verts = zip(*path_data)\n",
|
| 851 |
+
" clip_path = mpath.Path(verts, codes)\n",
|
| 852 |
+
" clip_patch = mpatches.PathPatch(\n",
|
| 853 |
+
" clip_path,\n",
|
| 854 |
+
" facecolor=\"none\",\n",
|
| 855 |
+
" edgecolor=\"none\"\n",
|
| 856 |
+
" )\n",
|
| 857 |
+
"\n",
|
| 858 |
+
" return clip_patch, poly_web, gdf_web\n",
|
| 859 |
+
"\n",
|
| 860 |
+
"\n",
|
| 861 |
+
"# ===========================\n",
|
| 862 |
+
"# 6. ์๊ฐํ 1: ์๋ณธ ๊ฒฝ๊ณ๋ง (์ํ ์์)\n",
|
| 863 |
+
"# ===========================\n",
|
| 864 |
+
"def plot_base(gdf_boundary_5179,\n",
|
| 865 |
+
" out_png=\"inha_boundary_base.png\"):\n",
|
| 866 |
+
"\n",
|
| 867 |
+
" clip_patch, poly_web, boundary_web = make_clip_patch_and_poly_web(gdf_boundary_5179)\n",
|
| 868 |
+
"\n",
|
| 869 |
+
" fig, ax = plt.subplots(figsize=(12, 10))\n",
|
| 870 |
+
"\n",
|
| 871 |
+
" # clip ํจ์น\n",
|
| 872 |
+
" ax.add_patch(clip_patch)\n",
|
| 873 |
+
"\n",
|
| 874 |
+
" # ๊ฒฝ๊ณ(์ )\n",
|
| 875 |
+
" boundary_web.boundary.plot(ax=ax, linewidth=2, edgecolor=\"black\")\n",
|
| 876 |
+
"\n",
|
| 877 |
+
" # basemap\n",
|
| 878 |
+
" ctx.add_basemap(ax, source=ctx.providers.OpenStreetMap.Mapnik, alpha=0.9)\n",
|
| 879 |
+
"\n",
|
| 880 |
+
" # basemap ํด๋ฆฌํ\n",
|
| 881 |
+
" if ax.images:\n",
|
| 882 |
+
" ax.images[-1].set_clip_path(clip_patch)\n",
|
| 883 |
+
"\n",
|
| 884 |
+
" # ์ถ ๋ฒ์\n",
|
| 885 |
+
" minx, miny, maxx, maxy = poly_web.bounds\n",
|
| 886 |
+
" ax.set_xlim(minx, maxx)\n",
|
| 887 |
+
" ax.set_ylim(miny, maxy)\n",
|
| 888 |
+
"\n",
|
| 889 |
+
" # ๋ฐ๊นฅ ํฌ๋ช
\n",
|
| 890 |
+
" ax.set_facecolor(\"none\")\n",
|
| 891 |
+
" fig.patch.set_alpha(0.0)\n",
|
| 892 |
+
"\n",
|
| 893 |
+
" ax.axis(\"off\")\n",
|
| 894 |
+
" plt.tight_layout()\n",
|
| 895 |
+
" plt.savefig(out_png, dpi=300, bbox_inches=\"tight\", transparent=True)\n",
|
| 896 |
+
" plt.close(fig)\n",
|
| 897 |
+
" print(f\"โ ์๋ณธ ๊ฒฝ๊ณ ์ง๋ ์ ์ฅ: {out_png}\")\n",
|
| 898 |
+
"\n",
|
| 899 |
+
"\n",
|
| 900 |
+
"# ===========================\n",
|
| 901 |
+
"# 7. ์๊ฐํ 2: SRS ์ํ\n",
|
| 902 |
+
"# ===========================\n",
|
| 903 |
+
"def plot_srs(gdf_boundary_5179, srs_points_5179,\n",
|
| 904 |
+
" out_png=\"inha_sampling_srs.png\"):\n",
|
| 905 |
+
"\n",
|
| 906 |
+
" clip_patch, poly_web, boundary_web = make_clip_patch_and_poly_web(gdf_boundary_5179)\n",
|
| 907 |
+
" pts_web = srs_points_5179.to_crs(epsg=3857)\n",
|
| 908 |
+
"\n",
|
| 909 |
+
" fig, ax = plt.subplots(figsize=(12, 10))\n",
|
| 910 |
+
"\n",
|
| 911 |
+
" ax.add_patch(clip_patch)\n",
|
| 912 |
+
"\n",
|
| 913 |
+
" # ๊ฒฝ๊ณ(์ )\n",
|
| 914 |
+
" boundary_web.boundary.plot(ax=ax, linewidth=2, edgecolor=\"black\")\n",
|
| 915 |
+
"\n",
|
| 916 |
+
" # SRS ์ \n",
|
| 917 |
+
" pts_web.plot(ax=ax, markersize=30, color=\"red\", alpha=0.9)\n",
|
| 918 |
+
"\n",
|
| 919 |
+
" # basemap\n",
|
| 920 |
+
" ctx.add_basemap(ax, source=ctx.providers.OpenStreetMap.Mapnik, alpha=0.9)\n",
|
| 921 |
+
"\n",
|
| 922 |
+
" # basemap ํด๋ฆฌํ\n",
|
| 923 |
+
" if ax.images:\n",
|
| 924 |
+
" ax.images[-1].set_clip_path(clip_patch)\n",
|
| 925 |
+
"\n",
|
| 926 |
+
" # ์ถ ๋ฒ์\n",
|
| 927 |
+
" minx, miny, maxx, maxy = poly_web.bounds\n",
|
| 928 |
+
" ax.set_xlim(minx, maxx)\n",
|
| 929 |
+
" ax.set_ylim(miny, maxy)\n",
|
| 930 |
+
"\n",
|
| 931 |
+
" # ๋ฐ๊นฅ ํฌ๋ช
\n",
|
| 932 |
+
" ax.set_facecolor(\"none\")\n",
|
| 933 |
+
" fig.patch.set_alpha(0.0)\n",
|
| 934 |
+
"\n",
|
| 935 |
+
" ax.axis(\"off\")\n",
|
| 936 |
+
" plt.tight_layout()\n",
|
| 937 |
+
" plt.savefig(out_png, dpi=300, bbox_inches=\"tight\", transparent=True)\n",
|
| 938 |
+
" plt.close(fig)\n",
|
| 939 |
+
" print(f\"โ SRS ์ํ ์ง๋ ์ ์ฅ: {out_png}\")\n",
|
| 940 |
+
"\n",
|
| 941 |
+
"\n",
|
| 942 |
+
"# ===========================\n",
|
| 943 |
+
"# 8-1. ์๊ฐํ 3: ์ธตํ ์ํ (๊ฒฉ์ + ๋ฉด์ ๏ฟฝ๏ฟฝ๋ก)\n",
|
| 944 |
+
"# ===========================\n",
|
| 945 |
+
"def plot_strata(gdf_boundary_5179, strata_gdf_5179, sample_gdf_5179,\n",
|
| 946 |
+
" out_png=\"inha_sampling_strata.png\"):\n",
|
| 947 |
+
"\n",
|
| 948 |
+
" clip_patch, poly_web, boundary_web = make_clip_patch_and_poly_web(gdf_boundary_5179)\n",
|
| 949 |
+
" strata_web = strata_gdf_5179.to_crs(epsg=3857)\n",
|
| 950 |
+
" sample_web = sample_gdf_5179.to_crs(epsg=3857)\n",
|
| 951 |
+
"\n",
|
| 952 |
+
" fig, ax = plt.subplots(figsize=(12, 10))\n",
|
| 953 |
+
"\n",
|
| 954 |
+
" ax.add_patch(clip_patch)\n",
|
| 955 |
+
"\n",
|
| 956 |
+
" # ์ธต(๊ตฌ์ญ) ์์ญ ์์น \n",
|
| 957 |
+
" strata_web.plot(\n",
|
| 958 |
+
" ax=ax,\n",
|
| 959 |
+
" column=\"stratum_id\",\n",
|
| 960 |
+
" alpha=0.35,\n",
|
| 961 |
+
" edgecolor=\"black\",\n",
|
| 962 |
+
" linewidth=1,\n",
|
| 963 |
+
" legend=False\n",
|
| 964 |
+
" )\n",
|
| 965 |
+
"\n",
|
| 966 |
+
" # ์บ ํผ์ค ์ ์ฒด ๊ฒฝ๊ณ\n",
|
| 967 |
+
" boundary_web.boundary.plot(ax=ax, linewidth=2, edgecolor=\"black\")\n",
|
| 968 |
+
"\n",
|
| 969 |
+
" # ์ธตํ ์ํ ์ (์ธต๋ณ ์ ๊ตฌ๋ถ)\n",
|
| 970 |
+
" sample_web.plot(\n",
|
| 971 |
+
" ax=ax,\n",
|
| 972 |
+
" column=\"stratum_id\",\n",
|
| 973 |
+
" markersize=30,\n",
|
| 974 |
+
" cmap=\"tab10\",\n",
|
| 975 |
+
" legend=False\n",
|
| 976 |
+
" )\n",
|
| 977 |
+
"\n",
|
| 978 |
+
" # basemap\n",
|
| 979 |
+
" ctx.add_basemap(ax, source=ctx.providers.OpenStreetMap.Mapnik, alpha=0.9)\n",
|
| 980 |
+
"\n",
|
| 981 |
+
" # basemap ํด๋ฆฌํ\n",
|
| 982 |
+
" if ax.images:\n",
|
| 983 |
+
" ax.images[-1].set_clip_path(clip_patch)\n",
|
| 984 |
+
"\n",
|
| 985 |
+
" # ์ถ ๋ฒ์\n",
|
| 986 |
+
" minx, miny, maxx, maxy = poly_web.bounds\n",
|
| 987 |
+
" ax.set_xlim(minx, maxx)\n",
|
| 988 |
+
" ax.set_ylim(miny, maxy)\n",
|
| 989 |
+
"\n",
|
| 990 |
+
" # ๋ฐ๊นฅ ํฌ๋ช
\n",
|
| 991 |
+
" ax.set_facecolor(\"none\")\n",
|
| 992 |
+
" fig.patch.set_alpha(0.0)\n",
|
| 993 |
+
"\n",
|
| 994 |
+
" ax.axis(\"off\")\n",
|
| 995 |
+
" plt.tight_layout()\n",
|
| 996 |
+
" plt.savefig(out_png, dpi=300, bbox_inches=\"tight\", transparent=True)\n",
|
| 997 |
+
" plt.close(fig)\n",
|
| 998 |
+
" print(f\"โ ์ธตํ ์ํ ์ง๋ ์ ์ฅ: {out_png}\")\n",
|
| 999 |
+
"\n",
|
| 1000 |
+
"\n",
|
| 1001 |
+
"# ===========================\n",
|
| 1002 |
+
"# 8-2. ์๊ฐํ 4: ์ธตํ ์ํ (๋์ผ๋ฉด์ strata + ๋์ผ ํ๋ณธ์)\n",
|
| 1003 |
+
"# ===========================\n",
|
| 1004 |
+
"def plot_strata_equal(gdf_boundary_5179, strata_gdf_5179, sample_gdf_5179,\n",
|
| 1005 |
+
" out_png=\"inha_sampling_strata_equalarea.png\"):\n",
|
| 1006 |
+
"\n",
|
| 1007 |
+
" clip_patch, poly_web, boundary_web = make_clip_patch_and_poly_web(gdf_boundary_5179)\n",
|
| 1008 |
+
" strata_web = strata_gdf_5179.to_crs(epsg=3857)\n",
|
| 1009 |
+
" sample_web = sample_gdf_5179.to_crs(epsg=3857)\n",
|
| 1010 |
+
"\n",
|
| 1011 |
+
" fig, ax = plt.subplots(figsize=(12, 10))\n",
|
| 1012 |
+
"\n",
|
| 1013 |
+
" ax.add_patch(clip_patch)\n",
|
| 1014 |
+
"\n",
|
| 1015 |
+
" # ์ธต(๊ตฌ์ญ) ์์ญ ์์น \n",
|
| 1016 |
+
" strata_web.plot(\n",
|
| 1017 |
+
" ax=ax,\n",
|
| 1018 |
+
" column=\"stratum_id\",\n",
|
| 1019 |
+
" alpha=0.35,\n",
|
| 1020 |
+
" edgecolor=\"black\",\n",
|
| 1021 |
+
" linewidth=1,\n",
|
| 1022 |
+
" legend=False\n",
|
| 1023 |
+
" )\n",
|
| 1024 |
+
"\n",
|
| 1025 |
+
" # ์บ ํผ์ค ์ ์ฒด ๊ฒฝ๊ณ\n",
|
| 1026 |
+
" boundary_web.boundary.plot(ax=ax, linewidth=2, edgecolor=\"black\")\n",
|
| 1027 |
+
"\n",
|
| 1028 |
+
" # ์ธตํ ์ํ ์ (์ธต๋ณ ์ ๊ตฌ๋ถ)\n",
|
| 1029 |
+
" sample_web.plot(\n",
|
| 1030 |
+
" ax=ax,\n",
|
| 1031 |
+
" column=\"stratum_id\",\n",
|
| 1032 |
+
" markersize=30,\n",
|
| 1033 |
+
" cmap=\"tab10\",\n",
|
| 1034 |
+
" legend=False\n",
|
| 1035 |
+
" )\n",
|
| 1036 |
+
"\n",
|
| 1037 |
+
" # basemap\n",
|
| 1038 |
+
" ctx.add_basemap(ax, source=ctx.providers.OpenStreetMap.Mapnik, alpha=0.9)\n",
|
| 1039 |
+
"\n",
|
| 1040 |
+
" # basemap ํด๋ฆฌํ\n",
|
| 1041 |
+
" if ax.images:\n",
|
| 1042 |
+
" ax.images[-1].set_clip_path(clip_patch)\n",
|
| 1043 |
+
"\n",
|
| 1044 |
+
" # ์ถ ๋ฒ์\n",
|
| 1045 |
+
" minx, miny, maxx, maxy = poly_web.bounds\n",
|
| 1046 |
+
" ax.set_xlim(minx, maxx)\n",
|
| 1047 |
+
" ax.set_ylim(miny, maxy)\n",
|
| 1048 |
+
"\n",
|
| 1049 |
+
" # ๋ฐ๊นฅ ํฌ๋ช
\n",
|
| 1050 |
+
" ax.set_facecolor(\"none\")\n",
|
| 1051 |
+
" fig.patch.set_alpha(0.0)\n",
|
| 1052 |
+
"\n",
|
| 1053 |
+
"\n",
|
| 1054 |
+
" ax.axis(\"off\")\n",
|
| 1055 |
+
" plt.tight_layout()\n",
|
| 1056 |
+
" plt.savefig(out_png, dpi=300, bbox_inches=\"tight\", transparent=True)\n",
|
| 1057 |
+
" plt.close(fig)\n",
|
| 1058 |
+
" print(f\"โ ๋์ผ๋ฉด์ ์ธตํ ์ํ ์ง๋ ์ ์ฅ: {out_png}\")\n",
|
| 1059 |
+
"\n",
|
| 1060 |
+
"\n",
|
| 1061 |
+
"# ===========================\n",
|
| 1062 |
+
"# 9. ๋ฉ์ธ ์คํ\n",
|
| 1063 |
+
"# ===========================\n",
|
| 1064 |
+
"if __name__ == \"__main__\":\n",
|
| 1065 |
+
" # 1) ๊ฒฝ๊ณ ๋ถ๋ฌ์ค๊ธฐ\n",
|
| 1066 |
+
" boundary_gdf, boundary_poly = load_inha_boundary(\"inha_boundary.shp\")\n",
|
| 1067 |
+
"\n",
|
| 1068 |
+
" # 2) SRS ์ํ๋ง (์: 40๊ฐ)\n",
|
| 1069 |
+
" n_srs = 60\n",
|
| 1070 |
+
" srs_points = random_points_in_polygon(boundary_poly, n_srs)\n",
|
| 1071 |
+
" srs_gdf = gpd.GeoDataFrame(\n",
|
| 1072 |
+
" {\"design\": [\"SRS\"] * len(srs_points)},\n",
|
| 1073 |
+
" geometry=srs_points,\n",
|
| 1074 |
+
" crs=\"EPSG:5179\"\n",
|
| 1075 |
+
" )\n",
|
| 1076 |
+
"\n",
|
| 1077 |
+
" # 3-1) ๊ฒฉ์ ์ธต(๊ตฌ์ญ) ๋ง๋ค๊ณ ์ธตํ ์ํ๋ง (๋ฉด์ ๋น๋ก)\n",
|
| 1078 |
+
" strata_gdf = make_strata(boundary_poly, n_rows=2, n_cols=3)\n",
|
| 1079 |
+
" strat_sample_gdf, n_alloc = stratified_sampling(strata_gdf, n_total=60)\n",
|
| 1080 |
+
" print(\"๊ฒฉ์ ์ธต๋ณ ํ๋ณธ ์ ํ ๋น (๋ฉด์ ๋น๋ก):\", n_alloc)\n",
|
| 1081 |
+
"\n",
|
| 1082 |
+
" # 3-2) ๋์ผ๋ฉด์ strata ๋ง๋ค๊ณ ์ธตํ ์ํ๋ง (๋์ผ ํ๋ณธ์)\n",
|
| 1083 |
+
" equal_strata_gdf = make_equal_area_strata(boundary_poly, n_strata=6)\n",
|
| 1084 |
+
" equal_strat_sample_gdf, n_alloc_equal = stratified_sampling_equal_n(equal_strata_gdf, n_total=60)\n",
|
| 1085 |
+
" print(\"๋์ผ๋ฉด์ ์ธต๋ณ ํ๋ณธ ์ ํ ๋น (๋์ผ ํ๋ณธ์):\", n_alloc_equal)\n",
|
| 1086 |
+
"\n",
|
| 1087 |
+
" # 4) ์๋ณธ ๊ฒฝ๊ณ ์ง๋ (๋ฐ๊นฅ ํฌ๋ช
)\n",
|
| 1088 |
+
" plot_base(boundary_gdf, out_png=\"inha_boundary_base.png\")\n",
|
| 1089 |
+
"\n",
|
| 1090 |
+
" # 5) SRS ์ง๋\n",
|
| 1091 |
+
" plot_srs(boundary_gdf, srs_gdf,\n",
|
| 1092 |
+
" out_png=\"inha_sampling_srs.png\")\n",
|
| 1093 |
+
"\n",
|
| 1094 |
+
" # 6) ์ธตํ ์ง๋ (๊ฒฉ์ + ๋ฉด์ ๋น๋ก)\n",
|
| 1095 |
+
" plot_strata(boundary_gdf, strata_gdf, strat_sample_gdf,\n",
|
| 1096 |
+
" out_png=\"inha_sampling_strata.png\")\n",
|
| 1097 |
+
"\n",
|
| 1098 |
+
" # 7) ์ธตํ ์ง๋ (๋์ผ๋ฉด์ strata + ๋์ผ ํ๋ณธ์)\n",
|
| 1099 |
+
" plot_strata_equal(boundary_gdf, equal_strata_gdf, equal_strat_sample_gdf,\n",
|
| 1100 |
+
" out_png=\"inha_sampling_strata_equalarea.png\")\n",
|
| 1101 |
+
"\n",
|
| 1102 |
+
" # 8) ์ขํ ํ์ธ์ฉ ์ถ๋ ฅ\n",
|
| 1103 |
+
" print(\"\\n[SRS ์ํ ์ขํ (EPSG:5179)]\")\n",
|
| 1104 |
+
" print(srs_gdf.head())\n",
|
| 1105 |
+
"\n",
|
| 1106 |
+
" print(\"\\n[๊ฒฉ์ ์ธตํ ์ํ ์ขํ (EPSG:5179)]\")\n",
|
| 1107 |
+
" print(strat_sample_gdf.head())\n",
|
| 1108 |
+
"\n",
|
| 1109 |
+
" print(\"\\n[๋์ผ๋ฉด์ ์ธตํ ์ํ ์ขํ (EPSG:5179)]\")\n",
|
| 1110 |
+
" print(equal_strat_sample_gdf.head())\n"
|
| 1111 |
+
]
|
| 1112 |
+
}
|
| 1113 |
+
],
|
| 1114 |
+
"metadata": {
|
| 1115 |
+
"kernelspec": {
|
| 1116 |
+
"display_name": "torch_ev",
|
| 1117 |
+
"language": "python",
|
| 1118 |
+
"name": "python3"
|
| 1119 |
+
},
|
| 1120 |
+
"language_info": {
|
| 1121 |
+
"codemirror_mode": {
|
| 1122 |
+
"name": "ipython",
|
| 1123 |
+
"version": 3
|
| 1124 |
+
},
|
| 1125 |
+
"file_extension": ".py",
|
| 1126 |
+
"mimetype": "text/x-python",
|
| 1127 |
+
"name": "python",
|
| 1128 |
+
"nbconvert_exporter": "python",
|
| 1129 |
+
"pygments_lexer": "ipython3",
|
| 1130 |
+
"version": "3.10.16"
|
| 1131 |
+
}
|
| 1132 |
+
},
|
| 1133 |
+
"nbformat": 4,
|
| 1134 |
+
"nbformat_minor": 5
|
| 1135 |
+
}
|
๋ฐ์ดํฐ ์์ง/inha_boundary_with_points.png
ADDED
|
Git LFS Details
|
๋ฐ์ดํฐ ์์ง/๊น๋ค์.csv
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
lat,lon,dB
|
| 2 |
+
37.4516638,126.6527864,50.0
|
| 3 |
+
37.4512905,126.653364,49.0
|
| 4 |
+
37.4514279,126.652793,48.0
|
| 5 |
+
37.4511085,126.6535225,49.0
|
| 6 |
+
37.4510701,126.6531148,48.0
|
| 7 |
+
37.4513171,126.652632,47.0
|
| 8 |
+
37.4510595,126.6526267,50.0
|
| 9 |
+
37.4510309,126.6528753,51.0
|
| 10 |
+
37.4510631,126.6536844,57.0
|
| 11 |
+
37.450863,126.6535503,52.0
|
| 12 |
+
37.4507669,126.6537015,51.0
|
| 13 |
+
37.4512012,126.6539697,47.0
|
| 14 |
+
37.4505606,126.6533733,47.0
|
| 15 |
+
37.4509074,126.6521297,58.0
|
| 16 |
+
37.4507437,126.6524077,49.0
|
| 17 |
+
37.4506799,126.6527081,48.0
|
| 18 |
+
37.4505351,126.6524077,53.0
|
| 19 |
+
37.4503988,126.6532875,47.0
|
| 20 |
+
37.4503967,126.6529463,46.0
|
| 21 |
+
37.4512256,126.6514948,47.0
|
| 22 |
+
37.4510425,126.6515538,46.0
|
| 23 |
+
37.451127,126.6513348,46.0
|
| 24 |
+
37.4513746,126.6517523,42.0
|
| 25 |
+
37.4506117,126.6531748,44.0
|
| 26 |
+
37.4509056,126.6523755,42.0
|
| 27 |
+
37.4517914,126.6530514,55.0
|
| 28 |
+
37.4514975,126.6537273,42.0
|
| 29 |
+
37.4515699,126.6534377,41.0
|
| 30 |
+
37.4517164,126.6525593,39.0
|
| 31 |
+
37.4514336,126.6522414,50.0
|
| 32 |
+
37.4512906,126.6521779,42.0
|
| 33 |
+
37.4506252,126.6513859,53.0
|
| 34 |
+
37.4504676,126.6517346,45.0
|
| 35 |
+
37.4502887,126.6514664,50.0
|
| 36 |
+
37.4501865,126.6517293,47.0
|
| 37 |
+
37.4500971,126.651917,49.0
|
| 38 |
+
37.4499438,126.6512143,50.0
|
| 39 |
+
37.4499054,126.6506027,51.0
|
| 40 |
+
37.4503398,126.6505276,49.0
|
| 41 |
+
37.4505698,126.6506188,43.0
|
| 42 |
+
37.4506251,126.6509514,45.0
|
| 43 |
+
37.4500532,126.6527818,46.0
|
| 44 |
+
37.4499255,126.6529267,43.0
|
| 45 |
+
37.4497977,126.6530554,44.0
|
| 46 |
+
37.4495805,126.6526316,48.0
|
| 47 |
+
37.449474,126.6528355,52.0
|
| 48 |
+
37.4492398,126.6524492,53.0
|
| 49 |
+
37.4489332,126.6520201,50.0
|
| 50 |
+
37.4489204,126.6522293,46.0
|
| 51 |
+
37.4479436,126.6529785,49.0
|
| 52 |
+
37.4486122,126.6533164,46.0
|
| 53 |
+
37.4486569,126.6536919,43.0
|
| 54 |
+
37.4489806,126.6539548,44.0
|
| 55 |
+
37.4488827,126.6542498,47.0
|
| 56 |
+
37.4495172,126.6545878,38.0
|
| 57 |
+
37.4494917,126.6541855,51.0
|
| 58 |
+
37.4496024,126.654502,52.0
|
| 59 |
+
37.4499814,126.6539816,52.0
|
| 60 |
+
37.4497003,126.6544966,46.0
|
| 61 |
+
37.4495939,126.654797,54.0
|
| 62 |
+
37.4493171,126.6552154,46.0
|
| 63 |
+
37.4491893,126.6552101,47.0
|
| 64 |
+
37.4491978,126.655076,45.0
|
| 65 |
+
37.4490317,126.6551242,47.0
|
| 66 |
+
37.4513577,126.6545939,51.0
|
| 67 |
+
37.4505187,126.6540735,53.0
|
| 68 |
+
37.4511234,126.6544705,60.0
|
| 69 |
+
37.4508636,126.6558974,43.0
|
| 70 |
+
37.4509659,126.6549157,44.0
|
| 71 |
+
37.4508935,126.6552698,39.0
|
| 72 |
+
37.4505826,126.6550338,56.0
|
| 73 |
+
37.4506465,126.6546851,52.0
|
| 74 |
+
37.4503569,126.6549479,59.0
|
| 75 |
+
37.4504548,126.6550123,54.0
|
| 76 |
+
37.4505655,126.655243,42.0
|
| 77 |
+
37.4503654,126.655495,47.0
|
| 78 |
+
37.4505016,126.6553824,41.0
|
| 79 |
+
37.4500523,126.6554818,41.0
|
| 80 |
+
37.4498416,126.6553664,46.0
|
| 81 |
+
37.450259,126.6542881,44.0
|
| 82 |
+
37.4502206,126.6544383,43.0
|
| 83 |
+
37.4500119,126.6549318,44.0
|
| 84 |
+
37.449931,126.6551249,51.0
|
| 85 |
+
37.4499437,126.6552644,46.0
|
| 86 |
+
37.4501013,126.6545617,50.0
|
| 87 |
+
37.4501525,126.654213,48.0
|
| 88 |
+
37.4499771,126.65462,48.0
|
| 89 |
+
37.4497514,126.6551403,52.0
|
| 90 |
+
37.4498331,126.6546207,48.0
|
| 91 |
+
37.4497777,126.6547173,52.0
|
| 92 |
+
37.4490231,126.6561154,0.0
|
๋ฐ์ดํฐ ์์ง/๊น๋ค์.ipynb
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"cells": [
|
| 3 |
+
{
|
| 4 |
+
"cell_type": "code",
|
| 5 |
+
"execution_count": 26,
|
| 6 |
+
"id": "be7e70ab",
|
| 7 |
+
"metadata": {},
|
| 8 |
+
"outputs": [
|
| 9 |
+
{
|
| 10 |
+
"name": "stderr",
|
| 11 |
+
"output_type": "stream",
|
| 12 |
+
"text": [
|
| 13 |
+
"C:\\Users\\USER\\AppData\\Local\\Temp\\ipykernel_20792\\1924603428.py:19: DeprecationWarning: The 'unary_union' attribute is deprecated, use the 'union_all()' method instead.\n",
|
| 14 |
+
" poly = gdf_web.geometry.unary_union\n"
|
| 15 |
+
]
|
| 16 |
+
},
|
| 17 |
+
{
|
| 18 |
+
"name": "stdout",
|
| 19 |
+
"output_type": "stream",
|
| 20 |
+
"text": [
|
| 21 |
+
"ํฌ์ธํธ ๊ฐ์: 90\n",
|
| 22 |
+
"์ ์ฅ ์๋ฃ: inha_boundary_with_points.png\n"
|
| 23 |
+
]
|
| 24 |
+
}
|
| 25 |
+
],
|
| 26 |
+
"source": [
|
| 27 |
+
"import geopandas as gpd\n",
|
| 28 |
+
"import pandas as pd\n",
|
| 29 |
+
"import matplotlib.pyplot as plt\n",
|
| 30 |
+
"import contextily as ctx\n",
|
| 31 |
+
"import numpy as np\n",
|
| 32 |
+
"import matplotlib.path as mpath\n",
|
| 33 |
+
"import matplotlib.patches as mpatches\n",
|
| 34 |
+
"from shapely import wkt\n",
|
| 35 |
+
"\n",
|
| 36 |
+
"def plot_clipped_map_with_points(\n",
|
| 37 |
+
" shp_path=r\"C:\\Users\\USER\\iCloudDrive\\์ธํ๋ํ๊ต\\5ํ๋
1ํ๊ธฐ\\ํ๋ณธ๋ก ๋ฐ ์ค์ต\\TeamProject\\Data\\inha_boundary.shp\",\n",
|
| 38 |
+
" points_csv=r\"C:\\Users\\USER\\iCloudDrive\\์ธํ๋ํ๊ต\\5ํ๋
1ํ๊ธฐ\\ํ๋ณธ๋ก ๋ฐ ์ค์ต\\TeamProject\\๋ฐ์ดํฐ ์์ง\\๊น๋ค์.csv\",\n",
|
| 39 |
+
" out_png=\"inha_boundary_with_points.png\",\n",
|
| 40 |
+
"):\n",
|
| 41 |
+
" # ---------- 1) ์บ ํผ์ค ๊ฒฝ๊ณ ----------\n",
|
| 42 |
+
" gdf = gpd.read_file(shp_path)\n",
|
| 43 |
+
" gdf_web = gdf.to_crs(epsg=3857)\n",
|
| 44 |
+
"\n",
|
| 45 |
+
" poly = gdf_web.geometry.unary_union\n",
|
| 46 |
+
" if poly.geom_type == \"MultiPolygon\":\n",
|
| 47 |
+
" poly = max(poly.geoms, key=lambda g: g.area)\n",
|
| 48 |
+
"\n",
|
| 49 |
+
" x, y = poly.exterior.coords.xy\n",
|
| 50 |
+
" coords = np.vstack([x, y]).T\n",
|
| 51 |
+
"\n",
|
| 52 |
+
" Path = mpath.Path\n",
|
| 53 |
+
" path_data = [(Path.MOVETO, coords[0])]\n",
|
| 54 |
+
" for c in coords[1:]:\n",
|
| 55 |
+
" path_data.append((Path.LINETO, c))\n",
|
| 56 |
+
" path_data.append((Path.CLOSEPOLY, coords[0]))\n",
|
| 57 |
+
"\n",
|
| 58 |
+
" codes, verts = zip(*path_data)\n",
|
| 59 |
+
" clip_path = mpath.Path(verts, codes)\n",
|
| 60 |
+
" clip_patch = mpatches.PathPatch(clip_path, facecolor=\"none\", edgecolor=\"none\")\n",
|
| 61 |
+
"\n",
|
| 62 |
+
" # ---------- 2) CSV ํฌ์ธํธ ์ฝ๊ธฐ ----------\n",
|
| 63 |
+
" df_pts = pd.read_csv(points_csv, encoding=\"cp949\")\n",
|
| 64 |
+
"\n",
|
| 65 |
+
" # ์ปฌ๋ผ ์ด๋ฆ์ BOM ๋ถ์ด ์์ ๊ฐ๋ฅ์ฑ ์ฒ๋ฆฌ\n",
|
| 66 |
+
" df_pts.columns = [c.strip() for c in df_pts.columns]\n",
|
| 67 |
+
"\n",
|
| 68 |
+
" # WKT ์ปฌ๋ผ ์ฐพ๊ธฐ\n",
|
| 69 |
+
" if \"WKT\" not in df_pts.columns:\n",
|
| 70 |
+
" # ์ด๋ฆ์ 'WKT'๊ฐ ํฌํจ๋ ์ปฌ๋ผ ์ฐพ๊ธฐ\n",
|
| 71 |
+
" cand = [c for c in df_pts.columns if \"WKT\" in c.upper()]\n",
|
| 72 |
+
" if not cand:\n",
|
| 73 |
+
" # ๊ทธ๋๋ ์์ผ๋ฉด ์ฒซ ๋ฒ์งธ ์ปฌ๋ผ์ WKT๋ก ๊ฐ์ฃผ\n",
|
| 74 |
+
" cand = [df_pts.columns[0]]\n",
|
| 75 |
+
" df_pts = df_pts.rename(columns={cand[0]: \"WKT\"})\n",
|
| 76 |
+
"\n",
|
| 77 |
+
" # dB ์ปฌ๋ผ ์ฐพ๊ธฐ\n",
|
| 78 |
+
" if \"dB\" not in df_pts.columns:\n",
|
| 79 |
+
" value_cols = [c for c in df_pts.columns if c != \"WKT\"]\n",
|
| 80 |
+
" if not value_cols:\n",
|
| 81 |
+
" raise ValueError(\"dB ๊ฐ์ผ๋ก ์ธ ์ซ์ ์ปฌ๋ผ์ด ์์.\")\n",
|
| 82 |
+
" df_pts = df_pts.rename(columns={value_cols[0]: \"dB\"})\n",
|
| 83 |
+
"\n",
|
| 84 |
+
" # WKT โ geometry\n",
|
| 85 |
+
" df_pts[\"geometry\"] = df_pts[\"WKT\"].apply(wkt.loads)\n",
|
| 86 |
+
" gdf_pts = gpd.GeoDataFrame(df_pts, geometry=\"geometry\", crs=4326)\n",
|
| 87 |
+
" gdf_pts_web = gdf_pts.to_crs(epsg=3857)\n",
|
| 88 |
+
"\n",
|
| 89 |
+
" print(\"ํฌ์ธํธ ๊ฐ์:\", len(gdf_pts_web))\n",
|
| 90 |
+
"\n",
|
| 91 |
+
" # ---------- 3) ๊ทธ๋ฆผ ----------\n",
|
| 92 |
+
" fig, ax = plt.subplots(figsize=(15, 12))\n",
|
| 93 |
+
"\n",
|
| 94 |
+
" # ํด๋ฆฌ๊ณค: ํ
๋๋ฆฌ๋ง\n",
|
| 95 |
+
" gdf_web.plot(\n",
|
| 96 |
+
" ax=ax,\n",
|
| 97 |
+
" facecolor=\"none\", # ๋ด๋ถ ์์น X\n",
|
| 98 |
+
" edgecolor=\"darkblue\",\n",
|
| 99 |
+
" linewidth=2,\n",
|
| 100 |
+
" )\n",
|
| 101 |
+
"\n",
|
| 102 |
+
" ax.add_patch(clip_patch)\n",
|
| 103 |
+
"\n",
|
| 104 |
+
" # ๋ฒ ์ด์ค๋งต\n",
|
| 105 |
+
" ctx.add_basemap(ax, source=ctx.providers.OpenStreetMap.Mapnik, alpha=0.7)\n",
|
| 106 |
+
" if ax.images:\n",
|
| 107 |
+
" ax.images[-1].set_clip_path(clip_patch)\n",
|
| 108 |
+
"\n",
|
| 109 |
+
" # ํฌ์ธํธ (์ปฌ๋ฌ๋ฐ ์์)\n",
|
| 110 |
+
" gdf_pts_web.plot(\n",
|
| 111 |
+
" ax=ax,\n",
|
| 112 |
+
" column=\"dB\",\n",
|
| 113 |
+
" cmap=\"viridis\",\n",
|
| 114 |
+
" markersize=40,\n",
|
| 115 |
+
" edgecolor=\"black\",\n",
|
| 116 |
+
" linewidth=0.3,\n",
|
| 117 |
+
" alpha=0.9,\n",
|
| 118 |
+
" legend=False, # ์ปฌ๋ฌ๋ฐ ์ ๊ฑฐ\n",
|
| 119 |
+
" zorder=5, # ํญ์ ์์ ์ค๊ฒ\n",
|
| 120 |
+
" )\n",
|
| 121 |
+
"\n",
|
| 122 |
+
" minx, miny, maxx, maxy = poly.bounds\n",
|
| 123 |
+
" ax.set_xlim(minx, maxx)\n",
|
| 124 |
+
" ax.set_ylim(miny, maxy)\n",
|
| 125 |
+
" ax.axis(\"off\")\n",
|
| 126 |
+
"\n",
|
| 127 |
+
" plt.tight_layout()\n",
|
| 128 |
+
" plt.savefig(out_png, dpi=300, bbox_inches=\"tight\", facecolor=\"white\")\n",
|
| 129 |
+
" plt.close(fig)\n",
|
| 130 |
+
"\n",
|
| 131 |
+
" print(f\"์ ์ฅ ์๋ฃ: {out_png}\")\n",
|
| 132 |
+
"\n",
|
| 133 |
+
"\n",
|
| 134 |
+
"plot_clipped_map_with_points()\n"
|
| 135 |
+
]
|
| 136 |
+
}
|
| 137 |
+
],
|
| 138 |
+
"metadata": {
|
| 139 |
+
"kernelspec": {
|
| 140 |
+
"display_name": "torch_ev",
|
| 141 |
+
"language": "python",
|
| 142 |
+
"name": "python3"
|
| 143 |
+
},
|
| 144 |
+
"language_info": {
|
| 145 |
+
"codemirror_mode": {
|
| 146 |
+
"name": "ipython",
|
| 147 |
+
"version": 3
|
| 148 |
+
},
|
| 149 |
+
"file_extension": ".py",
|
| 150 |
+
"mimetype": "text/x-python",
|
| 151 |
+
"name": "python",
|
| 152 |
+
"nbconvert_exporter": "python",
|
| 153 |
+
"pygments_lexer": "ipython3",
|
| 154 |
+
"version": "3.10.16"
|
| 155 |
+
}
|
| 156 |
+
},
|
| 157 |
+
"nbformat": 4,
|
| 158 |
+
"nbformat_minor": 5
|
| 159 |
+
}
|
๋ฐ์ดํฐ ์์ง/์ธก์ ๊ฒฐ๊ณผ.csv
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
dB
|
| 2 |
+
45.0
|
| 3 |
+
52.0
|
| 4 |
+
55.0
|
| 5 |
+
49.0
|
| 6 |
+
56.0
|
| 7 |
+
49.0
|
| 8 |
+
37.0
|
| 9 |
+
47.0
|
| 10 |
+
41.0
|
| 11 |
+
42.0
|
| 12 |
+
59.0
|
| 13 |
+
46.0
|
| 14 |
+
43.0
|
| 15 |
+
47.0
|
| 16 |
+
53.0
|
| 17 |
+
46.0
|
| 18 |
+
50.0
|
| 19 |
+
54.0
|
| 20 |
+
44.0
|
| 21 |
+
0.0
|
| 22 |
+
47.0
|
| 23 |
+
55.0
|
| 24 |
+
47.0
|
| 25 |
+
45.0
|
| 26 |
+
53.0
|
| 27 |
+
59.0
|
| 28 |
+
58.0
|
| 29 |
+
46.0
|
| 30 |
+
63.0
|
| 31 |
+
52.0
|
| 32 |
+
51.0
|
| 33 |
+
61.0
|
| 34 |
+
38.0
|
| 35 |
+
48.0
|
| 36 |
+
54.0
|
| 37 |
+
52.0
|
| 38 |
+
46.0
|
| 39 |
+
58.0
|
| 40 |
+
52.0
|
| 41 |
+
52.0
|
| 42 |
+
44.0
|
| 43 |
+
48.0
|
| 44 |
+
46.0
|
| 45 |
+
51.0
|
| 46 |
+
43.0
|
| 47 |
+
51.0
|
| 48 |
+
56.0
|
| 49 |
+
46.0
|
| 50 |
+
50.0
|
| 51 |
+
48.0
|
| 52 |
+
52.0
|
| 53 |
+
44.0
|
| 54 |
+
41.0
|
| 55 |
+
46.0
|
| 56 |
+
49.0
|
| 57 |
+
50.0
|
| 58 |
+
48.0
|
| 59 |
+
47.0
|
| 60 |
+
43.0
|
| 61 |
+
44.0
|
| 62 |
+
50.0
|
| 63 |
+
49.0
|
| 64 |
+
59.0
|
| 65 |
+
47.0
|
| 66 |
+
58.0
|
| 67 |
+
46.0
|
| 68 |
+
47.0
|
| 69 |
+
54.0
|
| 70 |
+
45.0
|
| 71 |
+
41.0
|
| 72 |
+
53.0
|
| 73 |
+
53.0
|
| 74 |
+
48.0
|
| 75 |
+
47.0
|
| 76 |
+
42.0
|
| 77 |
+
43.0
|
| 78 |
+
56.0
|
| 79 |
+
44.0
|
| 80 |
+
45.0
|
| 81 |
+
53.0
|
| 82 |
+
52.0
|
| 83 |
+
51.0
|
| 84 |
+
48.0
|
| 85 |
+
49.0
|
| 86 |
+
51.0
|
| 87 |
+
52.0
|
| 88 |
+
43.0
|
| 89 |
+
39.0
|
| 90 |
+
42.0
|
| 91 |
+
58.0
|
| 92 |
+
44.0
|
| 93 |
+
51.0
|
| 94 |
+
46.0
|
| 95 |
+
50.0
|
| 96 |
+
57.0
|
| 97 |
+
48.0
|
| 98 |
+
49.0
|
| 99 |
+
60.0
|
| 100 |
+
46.0
|
| 101 |
+
47.0
|
| 102 |
+
47.0
|
| 103 |
+
49.0
|
| 104 |
+
42.0
|
| 105 |
+
47.0
|
| 106 |
+
51.0
|
| 107 |
+
42.0
|
| 108 |
+
48.0
|
| 109 |
+
50.0
|
| 110 |
+
42.0
|
| 111 |
+
41.0
|
| 112 |
+
50.0
|
| 113 |
+
39.0
|
| 114 |
+
55.0
|
๋ชจ์ํ์ ๋จ_์ ์์.pdf
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:ac79521fc0e43b7f144b53c0aada854cfc8186062c676285645280c590cb709b
|
| 3 |
+
size 2663276
|
์์ด๋์ด/์ธ์ ์ต๋์.txt
ADDED
|
@@ -0,0 +1,316 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import React, { useState, useEffect, useRef } from 'react';
|
| 2 |
+
|
| 3 |
+
const PolygonCircleFinder = () => {
|
| 4 |
+
const canvasRef = useRef(null);
|
| 5 |
+
const [polygon, setPolygon] = useState([
|
| 6 |
+
{ x: 200, y: 100 },
|
| 7 |
+
{ x: 350, y: 150 },
|
| 8 |
+
{ x: 400, y: 300 },
|
| 9 |
+
{ x: 250, y: 350 },
|
| 10 |
+
{ x: 100, y: 250 }
|
| 11 |
+
]);
|
| 12 |
+
const [minCircle, setMinCircle] = useState(null);
|
| 13 |
+
const [maxInnerCircle, setMaxInnerCircle] = useState(null);
|
| 14 |
+
const [draggingPoint, setDraggingPoint] = useState(null);
|
| 15 |
+
|
| 16 |
+
// ์ต์ ์ธ์ ์ ์ฐพ๊ธฐ (Welzl's algorithm)
|
| 17 |
+
const findMinEnclosingCircle = (points) => {
|
| 18 |
+
const shuffled = [...points].sort(() => Math.random() - 0.5);
|
| 19 |
+
return welzl(shuffled, [], shuffled.length);
|
| 20 |
+
};
|
| 21 |
+
|
| 22 |
+
const welzl = (P, R, n) => {
|
| 23 |
+
if (n === 0 || R.length === 3) {
|
| 24 |
+
return makeCircle(R);
|
| 25 |
+
}
|
| 26 |
+
|
| 27 |
+
const p = P[n - 1];
|
| 28 |
+
const circle = welzl(P, R, n - 1);
|
| 29 |
+
|
| 30 |
+
if (circle && isInside(circle, p)) {
|
| 31 |
+
return circle;
|
| 32 |
+
}
|
| 33 |
+
|
| 34 |
+
return welzl(P, [...R, p], n - 1);
|
| 35 |
+
};
|
| 36 |
+
|
| 37 |
+
const makeCircle = (points) => {
|
| 38 |
+
if (points.length === 0) return null;
|
| 39 |
+
if (points.length === 1) return { x: points[0].x, y: points[0].y, r: 0 };
|
| 40 |
+
if (points.length === 2) {
|
| 41 |
+
const center = {
|
| 42 |
+
x: (points[0].x + points[1].x) / 2,
|
| 43 |
+
y: (points[0].y + points[1].y) / 2
|
| 44 |
+
};
|
| 45 |
+
const r = distance(points[0], points[1]) / 2;
|
| 46 |
+
return { ...center, r };
|
| 47 |
+
}
|
| 48 |
+
|
| 49 |
+
// 3์ ์ผ๋ก ์ ๋ง๋ค๊ธฐ
|
| 50 |
+
return circleFrom3Points(points[0], points[1], points[2]);
|
| 51 |
+
};
|
| 52 |
+
|
| 53 |
+
const circleFrom3Points = (p1, p2, p3) => {
|
| 54 |
+
const ax = p1.x, ay = p1.y;
|
| 55 |
+
const bx = p2.x, by = p2.y;
|
| 56 |
+
const cx = p3.x, cy = p3.y;
|
| 57 |
+
|
| 58 |
+
const d = 2 * (ax * (by - cy) + bx * (cy - ay) + cx * (ay - by));
|
| 59 |
+
if (Math.abs(d) < 1e-10) return null;
|
| 60 |
+
|
| 61 |
+
const ux = ((ax * ax + ay * ay) * (by - cy) + (bx * bx + by * by) * (cy - ay) + (cx * cx + cy * cy) * (ay - by)) / d;
|
| 62 |
+
const uy = ((ax * ax + ay * ay) * (cx - bx) + (bx * bx + by * by) * (ax - cx) + (cx * cx + cy * cy) * (bx - ax)) / d;
|
| 63 |
+
|
| 64 |
+
const r = distance({ x: ux, y: uy }, p1);
|
| 65 |
+
return { x: ux, y: uy, r };
|
| 66 |
+
};
|
| 67 |
+
|
| 68 |
+
const distance = (p1, p2) => {
|
| 69 |
+
return Math.sqrt((p1.x - p2.x) ** 2 + (p1.y - p2.y) ** 2);
|
| 70 |
+
};
|
| 71 |
+
|
| 72 |
+
const isInside = (circle, point) => {
|
| 73 |
+
if (!circle) return false;
|
| 74 |
+
return distance(circle, point) <= circle.r + 1e-10;
|
| 75 |
+
};
|
| 76 |
+
|
| 77 |
+
// ์ ์ด ํด๋ฆฌ๊ณค ๋ด๋ถ์ ์๋์ง ํ์ธ
|
| 78 |
+
const isPointInPolygon = (point, polygon) => {
|
| 79 |
+
let inside = false;
|
| 80 |
+
for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
|
| 81 |
+
const xi = polygon[i].x, yi = polygon[i].y;
|
| 82 |
+
const xj = polygon[j].x, yj = polygon[j].y;
|
| 83 |
+
|
| 84 |
+
const intersect = ((yi > point.y) !== (yj > point.y))
|
| 85 |
+
&& (point.x < (xj - xi) * (point.y - yi) / (yj - yi) + xi);
|
| 86 |
+
if (intersect) inside = !inside;
|
| 87 |
+
}
|
| 88 |
+
return inside;
|
| 89 |
+
};
|
| 90 |
+
|
| 91 |
+
// ์ ์์ ํด๋ฆฌ๊ณค๊น์ง์ ์ต๋จ ๊ฑฐ๋ฆฌ
|
| 92 |
+
const distanceToPolygon = (point, polygon) => {
|
| 93 |
+
let minDist = Infinity;
|
| 94 |
+
|
| 95 |
+
for (let i = 0; i < polygon.length; i++) {
|
| 96 |
+
const j = (i + 1) % polygon.length;
|
| 97 |
+
const dist = distanceToSegment(point, polygon[i], polygon[j]);
|
| 98 |
+
minDist = Math.min(minDist, dist);
|
| 99 |
+
}
|
| 100 |
+
|
| 101 |
+
return minDist;
|
| 102 |
+
};
|
| 103 |
+
|
| 104 |
+
const distanceToSegment = (p, v, w) => {
|
| 105 |
+
const l2 = distance(v, w) ** 2;
|
| 106 |
+
if (l2 === 0) return distance(p, v);
|
| 107 |
+
|
| 108 |
+
let t = ((p.x - v.x) * (w.x - v.x) + (p.y - v.y) * (w.y - v.y)) / l2;
|
| 109 |
+
t = Math.max(0, Math.min(1, t));
|
| 110 |
+
|
| 111 |
+
const projection = {
|
| 112 |
+
x: v.x + t * (w.x - v.x),
|
| 113 |
+
y: v.y + t * (w.y - v.y)
|
| 114 |
+
};
|
| 115 |
+
|
| 116 |
+
return distance(p, projection);
|
| 117 |
+
};
|
| 118 |
+
|
| 119 |
+
// ์ธ์ ์ ์์์ ํด๋ฆฌ๊ณค ์ธ๋ถ์ ์ต๋ ์ ์ฐพ๊ธฐ
|
| 120 |
+
const findMaxInnerCircle = (enclosingCircle, polygon) => {
|
| 121 |
+
if (!enclosingCircle) return null;
|
| 122 |
+
|
| 123 |
+
let maxCircle = null;
|
| 124 |
+
let maxRadius = 0;
|
| 125 |
+
|
| 126 |
+
// ๊ทธ๋ฆฌ๋ ์ํ๋ง์ผ๋ก ์ต์ ์์น ์ฐพ๊ธฐ
|
| 127 |
+
const samples = 50;
|
| 128 |
+
const step = (enclosingCircle.r * 2) / samples;
|
| 129 |
+
|
| 130 |
+
for (let i = 0; i <= samples; i++) {
|
| 131 |
+
for (let j = 0; j <= samples; j++) {
|
| 132 |
+
const x = enclosingCircle.x - enclosingCircle.r + i * step;
|
| 133 |
+
const y = enclosingCircle.y - enclosingCircle.r + j * step;
|
| 134 |
+
const point = { x, y };
|
| 135 |
+
|
| 136 |
+
// ์ธ์ ์ ์์ ์๋์ง ํ์ธ
|
| 137 |
+
if (distance(point, enclosingCircle) > enclosingCircle.r) continue;
|
| 138 |
+
|
| 139 |
+
// ํด๋ฆฌ๊ณค ์ธ๋ถ์ ์๋์ง ํ์ธ
|
| 140 |
+
if (isPointInPolygon(point, polygon)) continue;
|
| 141 |
+
|
| 142 |
+
// ํด๋ฆฌ๊ณค๊น์ง์ ๊ฑฐ๋ฆฌ์ ์ธ์ ์ ๊ฒฝ๊ณ๊น์ง์ ๊ฑฐ๋ฆฌ ์ค ์์ ๊ฐ
|
| 143 |
+
const distToPoly = distanceToPolygon(point, polygon);
|
| 144 |
+
const distToEnclosing = enclosingCircle.r - distance(point, enclosingCircle);
|
| 145 |
+
const radius = Math.min(distToPoly, distToEnclosing);
|
| 146 |
+
|
| 147 |
+
if (radius > maxRadius) {
|
| 148 |
+
maxRadius = radius;
|
| 149 |
+
maxCircle = { x, y, r: radius };
|
| 150 |
+
}
|
| 151 |
+
}
|
| 152 |
+
}
|
| 153 |
+
|
| 154 |
+
return maxCircle;
|
| 155 |
+
};
|
| 156 |
+
|
| 157 |
+
useEffect(() => {
|
| 158 |
+
const mec = findMinEnclosingCircle(polygon);
|
| 159 |
+
setMinCircle(mec);
|
| 160 |
+
|
| 161 |
+
if (mec) {
|
| 162 |
+
const mic = findMaxInnerCircle(mec, polygon);
|
| 163 |
+
setMaxInnerCircle(mic);
|
| 164 |
+
}
|
| 165 |
+
}, [polygon]);
|
| 166 |
+
|
| 167 |
+
useEffect(() => {
|
| 168 |
+
const canvas = canvasRef.current;
|
| 169 |
+
if (!canvas) return;
|
| 170 |
+
|
| 171 |
+
const ctx = canvas.getContext('2d');
|
| 172 |
+
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
| 173 |
+
|
| 174 |
+
// ์ต์ ์ธ์ ์ ๊ทธ๋ฆฌ๊ธฐ
|
| 175 |
+
if (minCircle) {
|
| 176 |
+
ctx.strokeStyle = '#3b82f6';
|
| 177 |
+
ctx.lineWidth = 2;
|
| 178 |
+
ctx.beginPath();
|
| 179 |
+
ctx.arc(minCircle.x, minCircle.y, minCircle.r, 0, 2 * Math.PI);
|
| 180 |
+
ctx.stroke();
|
| 181 |
+
|
| 182 |
+
ctx.fillStyle = '#3b82f6';
|
| 183 |
+
ctx.font = '14px sans-serif';
|
| 184 |
+
ctx.fillText(`์ธ์ ์ r=${minCircle.r.toFixed(1)}`, minCircle.x - 60, minCircle.y - minCircle.r - 10);
|
| 185 |
+
}
|
| 186 |
+
|
| 187 |
+
// ํด๋ฆฌ๊ณค ๊ทธ๋ฆฌ๊ธฐ
|
| 188 |
+
ctx.fillStyle = 'rgba(139, 92, 246, 0.3)';
|
| 189 |
+
ctx.strokeStyle = '#8b5cf6';
|
| 190 |
+
ctx.lineWidth = 2;
|
| 191 |
+
ctx.beginPath();
|
| 192 |
+
ctx.moveTo(polygon[0].x, polygon[0].y);
|
| 193 |
+
for (let i = 1; i < polygon.length; i++) {
|
| 194 |
+
ctx.lineTo(polygon[i].x, polygon[i].y);
|
| 195 |
+
}
|
| 196 |
+
ctx.closePath();
|
| 197 |
+
ctx.fill();
|
| 198 |
+
ctx.stroke();
|
| 199 |
+
|
| 200 |
+
// ํด๋ฆฌ๊ณค ๊ผญ์ง์ ๊ทธ๋ฆฌ๊ธฐ
|
| 201 |
+
polygon.forEach((point, i) => {
|
| 202 |
+
ctx.fillStyle = '#8b5cf6';
|
| 203 |
+
ctx.beginPath();
|
| 204 |
+
ctx.arc(point.x, point.y, 6, 0, 2 * Math.PI);
|
| 205 |
+
ctx.fill();
|
| 206 |
+
});
|
| 207 |
+
|
| 208 |
+
// ์ต๋ ๋ด์ ์ ๊ทธ๋ฆฌ๊ธฐ
|
| 209 |
+
if (maxInnerCircle) {
|
| 210 |
+
ctx.strokeStyle = '#10b981';
|
| 211 |
+
ctx.fillStyle = 'rgba(16, 185, 129, 0.2)';
|
| 212 |
+
ctx.lineWidth = 2;
|
| 213 |
+
ctx.beginPath();
|
| 214 |
+
ctx.arc(maxInnerCircle.x, maxInnerCircle.y, maxInnerCircle.r, 0, 2 * Math.PI);
|
| 215 |
+
ctx.fill();
|
| 216 |
+
ctx.stroke();
|
| 217 |
+
|
| 218 |
+
ctx.fillStyle = '#10b981';
|
| 219 |
+
ctx.font = '14px sans-serif';
|
| 220 |
+
ctx.fillText(`์ต๋์ r=${maxInnerCircle.r.toFixed(1)}`, maxInnerCircle.x - 50, maxInnerCircle.y + maxInnerCircle.r + 20);
|
| 221 |
+
}
|
| 222 |
+
}, [polygon, minCircle, maxInnerCircle]);
|
| 223 |
+
|
| 224 |
+
const handleMouseDown = (e) => {
|
| 225 |
+
const canvas = canvasRef.current;
|
| 226 |
+
const rect = canvas.getBoundingClientRect();
|
| 227 |
+
const x = e.clientX - rect.left;
|
| 228 |
+
const y = e.clientY - rect.top;
|
| 229 |
+
|
| 230 |
+
for (let i = 0; i < polygon.length; i++) {
|
| 231 |
+
if (distance({ x, y }, polygon[i]) < 10) {
|
| 232 |
+
setDraggingPoint(i);
|
| 233 |
+
break;
|
| 234 |
+
}
|
| 235 |
+
}
|
| 236 |
+
};
|
| 237 |
+
|
| 238 |
+
const handleMouseMove = (e) => {
|
| 239 |
+
if (draggingPoint === null) return;
|
| 240 |
+
|
| 241 |
+
const canvas = canvasRef.current;
|
| 242 |
+
const rect = canvas.getBoundingClientRect();
|
| 243 |
+
const x = e.clientX - rect.left;
|
| 244 |
+
const y = e.clientY - rect.top;
|
| 245 |
+
|
| 246 |
+
const newPolygon = [...polygon];
|
| 247 |
+
newPolygon[draggingPoint] = { x, y };
|
| 248 |
+
setPolygon(newPolygon);
|
| 249 |
+
};
|
| 250 |
+
|
| 251 |
+
const handleMouseUp = () => {
|
| 252 |
+
setDraggingPoint(null);
|
| 253 |
+
};
|
| 254 |
+
|
| 255 |
+
const resetPolygon = () => {
|
| 256 |
+
setPolygon([
|
| 257 |
+
{ x: 200, y: 100 },
|
| 258 |
+
{ x: 350, y: 150 },
|
| 259 |
+
{ x: 400, y: 300 },
|
| 260 |
+
{ x: 250, y: 350 },
|
| 261 |
+
{ x: 100, y: 250 }
|
| 262 |
+
]);
|
| 263 |
+
};
|
| 264 |
+
|
| 265 |
+
return (
|
| 266 |
+
<div className="w-full max-w-4xl mx-auto p-6 bg-gray-50 rounded-lg">
|
| 267 |
+
<h1 className="text-2xl font-bold mb-4 text-gray-800">ํด๋ฆฌ๊ณค ์ ์ฐพ๊ธฐ</h1>
|
| 268 |
+
|
| 269 |
+
<div className="mb-4 p-4 bg-white rounded-lg shadow">
|
| 270 |
+
<h2 className="text-lg font-semibold mb-2">์ค๋ช
:</h2>
|
| 271 |
+
<ul className="text-sm text-gray-700 space-y-1">
|
| 272 |
+
<li>โข <span className="text-blue-600 font-semibold">ํ๋์ ์</span>: ํด๋ฆฌ๊ณค์ ํฌํจํ๋ ์ต์ ์ธ์ ์</li>
|
| 273 |
+
<li>โข <span className="text-green-600 font-semibold">์ด๋ก์ ์</span>: ์ธ์ ์ ๋ด๋ถ์์ ํด๋ฆฌ๊ณค ์ธ๋ถ์ ๋ค์ด๊ฐ๋ ์ต๋ ์</li>
|
| 274 |
+
<li>โข ํด๋ฆฌ๊ณค์ ๊ผญ์ง์ ์ ๋๋๊ทธํ์ฌ ๋ชจ์์ ๋ณ๊ฒฝํ ์ ์์ต๋๋ค</li>
|
| 275 |
+
</ul>
|
| 276 |
+
</div>
|
| 277 |
+
|
| 278 |
+
<div className="bg-white rounded-lg shadow-lg p-4 mb-4">
|
| 279 |
+
<canvas
|
| 280 |
+
ref={canvasRef}
|
| 281 |
+
width={600}
|
| 282 |
+
height={500}
|
| 283 |
+
className="border border-gray-300 rounded cursor-move"
|
| 284 |
+
onMouseDown={handleMouseDown}
|
| 285 |
+
onMouseMove={handleMouseMove}
|
| 286 |
+
onMouseUp={handleMouseUp}
|
| 287 |
+
onMouseLeave={handleMouseUp}
|
| 288 |
+
/>
|
| 289 |
+
</div>
|
| 290 |
+
|
| 291 |
+
<div className="flex gap-4">
|
| 292 |
+
<button
|
| 293 |
+
onClick={resetPolygon}
|
| 294 |
+
className="px-6 py-2 bg-purple-600 text-white rounded-lg hover:bg-purple-700 transition"
|
| 295 |
+
>
|
| 296 |
+
์ด๊ธฐํ
|
| 297 |
+
</button>
|
| 298 |
+
|
| 299 |
+
{minCircle && (
|
| 300 |
+
<div className="flex-1 p-3 bg-white rounded-lg shadow text-sm">
|
| 301 |
+
<div className="mb-1">
|
| 302 |
+
<span className="font-semibold">์ธ์ ์:</span> ์ค์ฌ({minCircle.x.toFixed(1)}, {minCircle.y.toFixed(1)}), ๋ฐ์ง๋ฆ {minCircle.r.toFixed(1)}
|
| 303 |
+
</div>
|
| 304 |
+
{maxInnerCircle && (
|
| 305 |
+
<div>
|
| 306 |
+
<span className="font-semibold">์ต๋์:</span> ์ค์ฌ({maxInnerCircle.x.toFixed(1)}, {maxInnerCircle.y.toFixed(1)}), ๋ฐ์ง๋ฆ {maxInnerCircle.r.toFixed(1)}
|
| 307 |
+
</div>
|
| 308 |
+
)}
|
| 309 |
+
</div>
|
| 310 |
+
)}
|
| 311 |
+
</div>
|
| 312 |
+
</div>
|
| 313 |
+
);
|
| 314 |
+
};
|
| 315 |
+
|
| 316 |
+
export default PolygonCircleFinder;
|