iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 15
0
Modern Web

用 Python 玩 PDF,結合Django 變成一個網頁系統系列 第 15

[Day 15] PDF 表格應用(2)

  • 分享至 

  • xImage
  •  

前幾天弄了台北市分區的表格,發現橫向資料太多,需要改滿多的...,就改變一下,先做行政各區的天氣預報

會這樣決定是因為想先把小部份完成,看一下效果,再做個全台北市的天氣預報。

各區天氣預報要呈現項目

  1. 一個行政區一頁
  2. 加上標題
  3. 表格顯示溫度、體感溫度、降雨機率、天氣現象、舒適度
  4. 每三個小時分隔,降雨機率為每六個小時
  5. 先弄隔天,看一下感覺。

整理資料局部程式碼,這邊將需要的欄位(溫度、體感溫度...),都用一個list處理

dataDictList = []
locations = resJson["records"]["locations"][0]["location"]
for index, location in enumerate(locations):
    weatherElements = location["weatherElement"]
    temperatureDictList = [] # 溫度
    aTemperatureDictList = [] # 體感溫度
    pop6HDictList = [] # 降雨機率 6hr
    wxDictList = [] # 天氣現象
    ciDictList = [] # 舒適度

    for weatherElement in weatherElements:
        # 溫度
        if weatherElement["elementName"] == "T":
            timeDicts = weatherElement["time"]
            for timeDict in timeDicts:
                temperatureDictList.append({
                    "dataTime": timeDict["dataTime"],
                    "value": timeDict["elementValue"][0]["value"],
                })
        #  體感溫度
        if weatherElement["elementName"] == "AT":
            timeDicts = weatherElement["time"]
            for timeDict in timeDicts:
                aTemperatureDictList.append({
                    "dataTime": timeDict["dataTime"],
                    "value": timeDict["elementValue"][0]["value"],
                })

        #  降雨機率 百分比
        if weatherElement["elementName"] == "PoP6h":
            timeDicts = weatherElement["time"]
            for timeDict in timeDicts:
                pop6HDictList.append({
                    "startTime": timeDict["startTime"],
                    "endTime": timeDict["endTime"],
                    "value": timeDict["elementValue"][0]["value"],
                })

        #  天氣現象 Text
        if weatherElement["elementName"] == "Wx":
            timeDicts = weatherElement["time"]
            for timeDict in timeDicts:
                wxDictList.append({
                    "startTime": timeDict["startTime"],
                    "endTime": timeDict["endTime"],
                    "value": timeDict["elementValue"][0]["value"],
                })
        # 舒適度指數
        if weatherElement["elementName"] == "CI":
            timeDicts = weatherElement["time"]
            for timeDict in timeDicts:
                ciDictList.append({
                    "dataTime": timeDict["dataTime"],
                    "valueNum": timeDict["elementValue"][0]["value"],
                    "value": timeDict["elementValue"][1]["value"],
                })
    tempDict = {
        "locationName": location["locationName"],
        "temperatureDictList": temperatureDictList,
        "aTemperatureDictList": aTemperatureDictList,
        "pop6HDictList": pop6HDictList,
        "wxDictList": wxDictList,
        "ciDictList": ciDictList,
    }
    dataDictList.append(tempDict)

這邊字體有多定義了標題一、標題二,字體大小不一樣
以各行政區一頁,跑迴圈呼叫 表格func,專門寫各區的表格,因為降雨機率為六個小時,所以會用到合併欄位
('SPAN', (3, 1), (3, 2)), 後面參數是從哪裡到哪裡。

處理Pdf 局部程式碼


def getPDFTableDistrict(dataDict, showDateText):
    tableStyle = TableStyle([
        ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
        ('FONTNAME', (0, 0), (-1, -1), 'kaiu'),
        ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
        ('GRID', (0, 0), (-1, -1), 0.5, colors.black),
        ('SPAN', (3, 1), (3, 2)),
        ('SPAN', (3, 3), (3, 4)),
        ('SPAN', (3, 5), (3, 6)),
        ('SPAN', (3, 7), (3, 8)),
    ])
    # dataDict["locationName"]
    headerList = [
        showDateText,
        Paragraph("溫度", style=styleNormalCustom),
        Paragraph("體感溫度", style=styleNormalCustom),
        Paragraph("降雨機率", style=styleNormalCustom),
        Paragraph("天氣現象", style=styleNormalCustom),
        Paragraph("舒適度", style=styleNormalCustom),
    ]
    bodyList = [
        ["00:00"], ["03:00"], ["06:00"], ["09:00"],
        ["12:00"], ["15:00"], ["18:00"], ["21:00"]
    ]

    def bodyGetIndex(dataTime):
        hour = int(dataTime.split(" ")[1].split(":")[0])
        bodyIndex = int(hour / 3)
        return bodyIndex

    for temperatureDict in dataDict["temperatureDictList"]:
        dataTime = temperatureDict["dataTime"]
        if showDateText in dataTime:
            bodyIndex = bodyGetIndex(dataTime)
            bodyList[bodyIndex].append(Paragraph(f"{temperatureDict['value']}℃", style=styleNormalCustom))

    for aTemperatureDict in dataDict["aTemperatureDictList"]:
        dataTime = aTemperatureDict["dataTime"]
        if showDateText in dataTime:
            bodyIndex = bodyGetIndex(dataTime)
            bodyList[bodyIndex].append(Paragraph(f"{aTemperatureDict['value']}℃", style=styleNormalCustom))

    for pop6HDict in dataDict["pop6HDictList"]:
        startTime = pop6HDict["startTime"]
        if showDateText in startTime:
            bodyIndex = bodyGetIndex(startTime)
            bodyList[bodyIndex].append(Paragraph(f"{pop6HDict['value']}%", style=styleNormalCustom))
            # 這裡+1 是為了補合併欄位的空格
            bodyList[bodyIndex + 1].append(Paragraph("", style=styleNormalCustom))

    for wxDict in dataDict["wxDictList"]:
        startTime = wxDict["startTime"]
        if showDateText in startTime:
            bodyIndex = bodyGetIndex(startTime)
            bodyList[bodyIndex].append(Paragraph(wxDict["value"], style=styleNormalCustom))

    for ciDict in dataDict["ciDictList"]:
        dataTime = ciDict["dataTime"]
        if showDateText in dataTime:
            bodyIndex = bodyGetIndex(dataTime)
            bodyList[bodyIndex].append(Paragraph(ciDict["value"], style=styleNormalCustom))

    tableDataList = [
        headerList,
        *bodyList,
    ]
    table = Table(tableDataList, style=tableStyle)
    return table
    
# 一般字體
styleNormalCustom = ParagraphStyle(
    'styleNormalCustom',
    fontName='kaiu',
    parent=styles["Normal"],
    alignment=TA_CENTER,
)
styleNormalCustomHeader = ParagraphStyle(
    'styleNormalCustom',
    fontName='kaiu',
    parent=styles["Normal"],
    alignment=TA_CENTER,
    fontSize=18
)

styleNormalCustomHeader2 = ParagraphStyle(
    'styleNormalCustom',
    fontName='kaiu',
    parent=styles["Normal"],
    alignment=TA_CENTER,
    fontSize=16
)

pdfmetrics.registerFont(TTFont('kaiu', "font/kaiu.ttf"))
fileName = "example.pdf"
pdfTemplate = SimpleDocTemplate(fileName)
story = []

today = datetime.datetime.today().date()
showDate = today + datetime.timedelta(days=1)

todayDate = datetime.datetime.today().date()
tomorrow = todayDate + datetime.timedelta(days=1)
dayAfterTomorrow = tomorrow + datetime.timedelta(days=1)
tomorrowText = tomorrow.strftime('%Y-%m-%d')
dayAfterTomorrowText = dayAfterTomorrow.strftime('%Y-%m-%d')
# 以各行政區一頁,跑迴圈呼叫table
for dataDict in dataDictList:
    story.append(Paragraph("未來鄉鎮天氣預報", style=styleNormalCustomHeader))
    story.append(Spacer(1, 0.15 * inch)) # 給間距
    story.append(Paragraph(dataDict["locationName"], style=styleNormalCustomHeader2))
    story.append(Spacer(1, 0.15 * inch)) # 給間距
    table = getPDFTableDistrict(dataDict, tomorrowText) # 先做明天
    story.append(table)
    story.append(PageBreak())

pdfTemplate.build(story)

結果圖 總共有12頁,隨便拿兩頁看一下,看起來還不錯,就清楚顯示所有資料欄位。


參考資料:

如果有任何寫得不好的地方,請跟我說,謝謝。


上一篇
[Day 14] PDF圖表應用
下一篇
[Day 16] PDF 圖表應用(2)
系列文
用 Python 玩 PDF,結合Django 變成一個網頁系統30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言