พอดีอยากได้ข้อมูลรายละเอียดแผนที่ขอบเขตของแต่ละจังหวัดในประเทศไทยและต้องการข้อมูลที่เก็บข้อมูลอยู่ในรูปแบบ GeoJSON(ไฟล์ .geojson) ที่แสดงขอบเขตของแต่ละจังหวัดของประเทศไทย เพื่อให้สามารถเอาข้อมูลนี้ไปแสดงผลร่วมกับไลบรารี่ leaflet ในการแสดงแผนที่ในรูปแบบ choropleth(แผนที่ซึ่งในแต่ละขอบเขตตามจังหวัดมีการลงสีหรือแรเงาให้แต่ละพื้นที่ตามข้อมูลตัวเลขเชิงปริมาณ ตัวอย่างเช่น จำนวน, ความหนาแน่น หรือข้อมูลอื่นๆ โดยสีที่แสดงในแต่ละขอบเขตของแต่ละจังหวัดนั้นจะแสดงตัวเลขเชิงปริมาณที่แตกต่างกันในแต่ละขอบเขตอีกทีหนึ่ง)
ตัวอย่างการใช้งานแผนที่แบบ choropleth ของไลบรารี่ leaflet
ลองค้นข้อมูลที่เป็นข้อมูลแผนที่แสดงขอบเขตของแต่ละจังหวัดของประเทศไทย ก็ไปเจอข้อมูลที่เป็น shapefile จากเวป
OpenDevelopmentMekong ซึ่งข้อมูลแสดงขอบเขตจังหวัดต่างๆของประเทศไทยนั้นถูกเก็บอยู่ในรูปแบบไฟล์ที่เป็น shapefile(.shp) เราก็เลือกดาวน์โหลดอันที่เป็น .SHP มาใช้งาน แล้วในข้อมูลที่ได้มาก็มีข้อมูลที่ใช้ร่วมกันเพื่อแสดงข้อมูลอื่นๆ ที่จำเป็นสำหรับแผนที่ในรูปแบบไฟล์(.shx, .dbf, .prj) มาด้วยกันและพอจะนำมาใช้ได้ ก็เลยคิดว่าจะเอาข้อมูลนี้แหละมาแปลงให้เป็นข้อมูลในรูปแบบ GeoJSON(.geojson)
พอดาวน์โหลดไฟล์แผนที่ดังกล่าวมาจะเป็น zip file พอแตกข้อมูลออกมาแล้วจะเห็นว่าจะมีไฟล์หลายไฟล์ที่ชื่อเดียวกันแต่เป็นไฟล์คนละนามสกุลกัน (.shp, .shx, .dbf, .prj) ซึ่งแต่ละไฟล์จะทำหน้าที่แตกต่างกันและเก็บข้อมูลกันคนละรูปแบบ เพื่อนำมาใช้ร่วมกันอีกที
สำหรับการแปลงไฟล์ข้อมูลรูปแบบ shapefile(.shp) ให้เป็นไฟล์ที่เก็บข้อมูลในเป็นรูปแบบ GeoJSON(.geojson) ในครั้งนี้เราจะใช้ไลบรารี่ของ python ที่ชื่อว่า GeoPandas เริ่มต้นด้วยการติดตั้งไลบรารี่ GeoPandas กันก่อน
ใน terminal รันคำสั่ง pip install เพื่อติดตั้งไลบรารี่ geopandas
# ใช้ pip ติดตั้ง geopandas pip install geopandas
เขียนโปรแกรมสำหรับแปลงข้อมูลในรูปแบบ shapefile(.shp) ให้อยู่ในรูปแบบ GeoJSON(.geojson) โดยในโปรแกรมนี้เราจะเรียกใช้ไลบรารี่ดังนี้:-
- geopandas: สำหรับแปลงข้อมูล
- matplotlib: สำหรับแสดงผลข้อมูลขอบเขตแผนที่จังหวัดของประเทศไทยหลังจากเราทำการแปลงข้อมูลเสร็จแล้ว
# เรียกใช้ไลบรารี่ geopandas
import geopandas as gpd
# เรียกใช้ไลบรารี่ matplotlib
import matplotlib.pyplot as plt
try:
# ใช้ library geopanda อ่านข้อมูลแผนที่ขอบเขตจังหวัดจากไฟล์ .shp และไฟล์อื่นๆ ที่มีชื่อเดียวกันแต่คนละนามสกุล(.shp, .dbf, .shx, .prj) เพื่อโหลดข้อมูลขึ้นมาในหน่วยความจำ
# เราจำเป็นต้องให้ไฟล์นามสกุล (.shp, shx, .dpf, .prj) ที่มีชื่อเดียวกันอยู่ในโฟลเดอร์เดียวกันด้วย เพราะเวลาฟังก์ชัน read_file() เรียกใช้งานไฟล์ .shp ก็จะทำการเรียกไฟล์นามกุลอื่นๆ ที่เกี่ยวข้องขึ้นมาเก็บไว้ในหน่วยความจำพร้อมกันด้วย
gdf = gpd.read_file("tha_admbnda_adm1_rtsd_20190221.shp", encoding='utf-8')
# ทำการแปลงข้อมูลที่โหลดมาเก็บไว้ในหน่วยความจำ ให้อยู่ในรูปแบบข้อมูล GeoJSON(.geojson)
gdf.to_file("provinces_geojson.geojson", driver='GeoJSON', encoding='utf-8')
# เรียกใช้ไลบรารี่ matplotlib เพื่อให้พลอตข้อมูลแผนที่ขอบเขตข้อมูลจังหวัดของประเทศไทยออกมาดู
gdf.plot()
plt.show()
except Exception as e:
print(e)
พอแปลงข้อมูลให้อยู่ในรูปแบบ GeoJSONเสร็จแล้ว เราให้ไลบรารี่ matplotlib ทำการแสดงขอบเขตแผนที่ของแต่ละจังหวัดของประเทศไทยออกมาดูเป็นตัวอย่างก็จะออกมาตามรูปด้านล่างนี้
สำหรับไฟล์ GeoJSON(.geojson) ที่ได้มาจากโปรแกรมข้างต้น เป็นไฟล์ที่มีความละเอียดค่อนข้างสูงตามข้อมูลต้นฉบับที่ได้มา ในกรณีของไฟล์นี้เมื่อทำการแปลงรูปแบบข้อมูลแล้ว ได้เป็นไฟล์ .geojson ที่มีขนาด 97 เมกกะไบต์ ซึ่งถือว่าเป็นไฟล์ขนาดค่อนข้างใหญ่
เราจึงจำเป็นต้องพิจารณาถึงการใช้งานข้อมูลแผนที่ของเราเอง ถ้าเราจำเป็นต้องดูข้อมูลขอบเขตแผนที่ซึ่งใช้งานค่อนข้างละเอียด มีการซูมเข้าไปเยอะๆ เราก็จะเป็นต้องใช้ข้อมูลที่มีความละเอียดสูงนั่นแหละ แต่เมื่อไฟล์ข้อมูลมีขนาดใหญ่เราก็จำเป็นต้องออกแบบโปรแกรมให้มีการบริหารจัดการหน่วยความจำให้ดีมากขึ้นแทน แต่ในกรณีนี้เราไม่ต้องการแผนที่ซึ่งมีความละเอียดสูงมาก ไม่ต้องการซูมแบบละเอียดมากและต้องการใช้หน่วยความจำไม่เยอะ เราเลยจำเป็นต้องหาวิธีลดความละเอียดข้อมูลขอบเขตของแผนที่ลงแทน
สำหรับการลดความละเอียดของข้อมูลแผนที่ลงนั้นก็ยังคงใช้งานไลบรารี่ GeoPandas ตามข้างต้น และเราจะเรียกใช้ฟังก์ชัน simplify() เพื่อใช้ลดความละเอียดของขอบเขตแผนที่(ซึ่งก็เป็นการลดเหลี่ยม, มุม ของข้อมูล polygon ต้นฉบับลง ให้เก็บข้อมูลน้อยลง แต่ข้อมูลยังไม่สูญเสียความเป็นรูปร่างต้นฉบับไปมาก) โดยฟังก์ชัน simplify() นี้เราสามารถระบุพารามิเตอร์ที่ชื่อ “tolerance” เข้าไปเพื่อบอกว่าเราต้องการให้ลดความละเอียดมากหรือน้อยลงแค่ไหน ตัวอย่างการใช้เช่น simplify(tolerance=0.001) ซึ่งถ้ายิ่งค่าสูงความละเอียดจะน้อยลง ยังไงก็ต้องลองปรับจูนตัวแปรนี้ดูเอาเอง ว่าค่าไหนที่เหมาะกับการใช้งานของเรา
เขียนโปรแกรมเพื่อทำการลดความละเอียดของข้อมูลแผนที่ในรูปแบบ GeoJSON
# เรียกใช้ไลบรารี่ geopandas
import geopandas as gpd
import matplotlib.pyplot as plt
try:
# อ่านข้อมูลจากไฟล์ .geojson ขึ้นมาในหน่วยความจำซึ่งเก็บไว้ในรูปแบบ GeoDataframe
gdf = gpd.read_file("provinces_geojson.geojson", encoding='utf-8')
# เรียกใช้ฟังก์ชัน simplify() เพื่อทำการลดความละเอียดของข้อมูลแผนที่
# ถ้าตัวแปร tolerance มีค่ามากขึ้น ความละเอียดของแผนที่จะยิ่งลดลง
gdf['geometry'] = gdf.simplify(tolerance=0.0001)
# ทำบันทึกข้อมูลแผนที่ซึ่งลดความละเอียดลงไปแล้ว ในรูปแบบไฟล์ GeoJSON
gdf.to_file("simplified_provinces_geojson.geojson", driver="GeoJSON" , encoding='utf-8')
# เรียกใช้ไลบรารี่ matplotlib เพื่อให้พลอตข้อมูลแผนที่ขอบเขตข้อมูลจังหวัดของประเทศไทยออกมาดู
gdf.plot()
plt.show()
except Exception as e:
print(e)
พอให้โปรแกรมทำการลดขนาดข้อมูลแผนที่เสร็จแล้ว เราเรียกใช้ไลบรารี่ matplotlib เพื่อให้ทำการแสดงขอบเขตแผนที่ของแต่ละจังหวัดของประเทศไทยออกมาอีกรอบดู(ซึ่งการซูมข้อมูลระดับนี้ก็จะไม่เห็นความแตกต่างของข้อมูลต้นฉบับกับข้อมูลแผนที่ที่ทำการลดความละเอียดลงมากนัก) ตัวอย่างแผนที่ก็จะออกมาตามรูปด้านล่างนี้
ส่วนขนาดของไฟล์ ก็ลดลงเยอะเช่นกัน จากประมาณ 97 เมกกะไบต์ ลดเหลือ 14 เมกกะไบต์
พอเสร็จแล้วเราก็จะได้ข้อมูลในรูปแบบ GeoJSON(.geojson) ที่สามารถเอาโหลดเพื่อใช้งานกับแผนที่แบบ choropleth ของไลบรารี่ leaflet ต่อไป แต่เราจะไม่ได้พูดถึงการนำไปใช้งานกับไลบรารี่ leaflet ในบทความนี้
