python操作Excel、openpyxl 之圖表,折線圖、餅圖、柱狀圖等


一、准備
  • 需要模塊:
    from openpyxl.workbook import Workbook
    from openpyxl.chart import Series,LineChart, Reference
1.1 建表,畫圖
  • openpyxl支持利用工作表中單元格的數據,創建條形圖、折線圖、散點圖等

  • 步驟:

wb = Workbook()
ws = wb.create_sheet("{0}蒸汽壓力記錄表".format("樣品名稱"), 0)  
  1. 從將表格中涉及的要畫圖的數據使用:Reference 創建一個對象
    比如:我選取 data = Reference(ws, min_col=5, min_row=4, max_col=10, max_row=4)
    參數含義:ws 一個活躍的sheet,數據來源。可以使用ws = wb.active 獲取
    其他的就是指定這個表中的行列數據了:起始行、起始列、終止行、終止列

  2. 通過傳入Reference對象,創建一個Series對象

  3. 創建一個Chart對象

  4. 可選擇的設置Chart對象的長(drawing.height)、寬(drawing.width)、坐標位置(drawing.top、drawing.left)。

  5. 將Chart對象添加到Worksheet對象。

chart = LineChart()  #圖表對象

data = Reference(ws, min_col=5, min_row=4, max_col=10, max_row=4) #涉及數據

seriesObj = Series(data, title='壓力')  #創建series對象

chart.append(seriesObj)  #添加到chart中

ws.add_chart(chart, "A6") #將圖表添加到 sheet中
1.2 其他方式畫圖
  • 一個餅圖
from openpyxl import load_workbook
from openpyxl import Workbook
from openpyxl.chart import BarChart, Reference, Series

wb = load_workbook('e:\\sample.xlsx')
ws1=wb.active

wb = Workbook()
ws = wb.active
for i in range(10):
    ws.append([i])

values = Reference(ws, min_col=1, min_row=1, max_col=1, max_row=10)
chart = BarChart()
chart.add_data(values)
ws.add_chart(chart, "E15")

# Save the file
wb.save("e:\\sample.xlsx")
3.1.2 作者最近一個項目用的到圖,可做參考 畫兩個圖,每個圖30萬數據量
![](https://img2018.cnblogs.com/blog/1226829/202001/1226829-20200108095702489-1680159334.png)
  • 說明:
    enity 參數是我從數據庫,通過sqlalchemy查詢出來的一個實體對象,
    recordList 是我每次試驗產生的數據列,每個數據列30萬數據左右
import sys
import uuid
import string
import json
import time
import random
import os
import base64

from openpyxl.workbook import Workbook
from openpyxl.styles import Font, Alignment, Side, Border
from openpyxl.drawing import image
from openpyxl.chart import Series,LineChart, Reference
from openpyxl.chart.axis import DateAxis

# path = os.path.dirname(os.path.dirname(__file__))
# sys.path.insert(0,path)
from Lib.Utils import Utils

class ExportReport:

    def __init__(self,entity, recordList,**kwargs):
        """

        :param entity: 記錄對象
        :param recordList: 記錄["壓力","電流"]列表
        :param kwargs:
        """
        self.entity = entity
        self.record_list = recordList
        self.status_all = ["未完成", "成功", "<2070kpa"]
        self.data_head = ["start_time","experiment_user_name","material_name", "experiment_type","is_success", "time_cost","test_count"]
        self.base_info_list = ["試驗日期","試驗人", "樣品名稱", "試驗類型", "試驗狀態", "耗費時間","試驗次數"]
        self.wb = Workbook()

        self.ws = self.wb.create_sheet("{0}試驗記錄表".format(self.entity.material_name), 0)
        #生成頭部所含列總數的大寫字母
        self.header_upper_string_list = string.ascii_uppercase[:len(self.base_info_list)]
        # 水平對齊,居中對齊
        self.alignment_style = Alignment(horizontal='center', vertical='center')
        #定義border 邊框樣式
        left, right, top, bottom = [Side(style='thin', color='000000')]*4
        self.border_style = Border(left=left, right=right, top=top, bottom=bottom)
        #定義字體
        self.font_size = Font(size=9)
        for col in self.header_upper_string_list :
            self.ws.column_dimensions[col].width = 25

    #單元格樣式字體調整
    def cell_set(self, cellObj, fontSzie=12, alignmentStyle=None):
        alignmentStyle = alignmentStyle if alignmentStyle else self.alignment_style
        cellObj.alignment = alignmentStyle #對齊方式
        cellObj.font = Font(size=fontSzie, bold=True) #字體

    #單元格樣式字體居中
    def cell_textalign_center(self,cellObj):
        cellObj.alignment = self.alignment_style

    #創建表頭第一行
    def create_row1(self):
        #把1、2行所有列合並
        self.ws.merge_cells(start_row=1, end_row=2, start_column=1, end_column=self.base_info_list.__len__())
        #寫入值
        self.ws.cell(row=1, column=1).value = "{0}試驗記錄表".format(self.entity.material_name)
        self.cell_set(self.ws['A1'], 16)
        self.create_row3_4()
        self.create_row7_8()

    def create_row3_4(self):
        for col in range(1, len(self.base_info_list)+1):
            self.ws.merge_cells(start_row=3, end_row=4, start_column=col, end_column=col)
            col_str = self.header_upper_string_list[col-1]+"3"
            self.ws[col_str] = self.base_info_list[col-1]
            self.cell_set(self.ws[col_str])
        #合並 5 6 兩行單元格
        for col in range(1, len(self.base_info_list)+1):
            self.ws.merge_cells(start_row=5, end_row=6, start_column=col, end_column=col)

    def create_row7_8(self):
        dataNum = ["序號", "壓力", "電流"]
        for col in range(1, 4):
            self.ws.merge_cells(start_row=7, end_row=8, start_column=col, end_column=col)
            col_str = "ABCD"[col-1]+"7"
            self.ws[col_str] = dataNum[col-1]
            self.cell_set(self.ws[col_str])

    def timeStampToUTC8(self,timeStamp):
        return time.strftime("%Y/%m/%d %H:%M:%S",time.localtime(timeStamp/1000))


    def add_data(self):
        #第五行開始寫入數據,所有數據居中對齊,水平居中
        # 字符為A/B,第五行
        for i,v in enumerate(self.data_head):
            cur_v = getattr(self.entity,v)
            if v == "experiment_type":
                cur_v = ["樣品試驗","參考品試驗","時間/壓力試驗"][cur_v]
            if v == "is_success":
                cur_v = ["異常","計時","<2070kPa"][cur_v]
            self.ws[self.header_upper_string_list[i]+"5"] = cur_v
        for i in self.header_upper_string_list:
            col_str = i +"5"
            self.cell_textalign_center(self.ws[col_str])
        for idx, data in enumerate(self.record_list[0]):
            col_str = "A{}".format(9+idx)
            self.ws[col_str] = idx
            self.cell_textalign_center(self.ws[col_str])
            col_str = "B{}".format(9 + idx)
            self.ws[col_str] = data
            self.cell_textalign_center(self.ws[col_str])
            col_str = "C{}".format(9 + idx)
            self.ws[col_str] = self.record_list[1][idx]
            self.cell_textalign_center(self.ws[col_str])
        self.draw_line_chart()

    #畫折線圖
    def draw_line_chart(self):
        self.chart = LineChart()
        self.chart.title = "壓力變化記錄折線圖"
        self.chart.style = 2
        self.chart.width = 36
        self.chart.height = 20
        self.chart.y_axis.title = "壓力kpa"
        # self.chart.y_axis.crossAx = 500
        # self.chart.x_axis = DateAxis(crossAx=100)
        # self.chart.x_axis.number_format = '%H:%M:%S'
        # self.chart.x_axis.majorTimeUnit = "days"
        self.chart.x_axis.title = "序號"
        #選中要畫圖的數據列(Y軸)
        data1 = Reference(
            self.ws,
            min_col=2,
            min_row=8,
            max_col=2,
            max_row=len(self.record_list[0])+8
        )
        seriesObj1 = Series(data1, title='壓力值')
        self.chart.append(seriesObj1)
        # self.chart.add_data(data, titles_from_data=True)
        #指定X軸選取的數據列(還可以有時間-日期格式,這兒作者就不演示了)
        dates = Reference(self.ws, min_col=1, min_row=8, max_row=len(self.record_list[0])+8)
        self.chart.set_categories(dates)
        self.ws.add_chart(self.chart, "D7")

    def draw_electric_cur(self):
        self.chart = LineChart()
        self.chart.title = "電流記錄折線圖"
        self.chart.style = 2
        self.chart.width = 36
        self.chart.height = 20
        self.chart.y_axis.title = "電流A"
        # self.chart.y_axis.crossAx = 500
        # self.chart.x_axis.crossAx = -5
        # self.chart.x_axis = DateAxis(crossAx=100)
        # self.chart.x_axis.number_format = '%H:%M:%S'
        # self.chart.x_axis.majorTimeUnit = "days"
        self.chart.x_axis.title = "序號"
        #設定坐標系內,Y軸最大、最小值
        # self.chart.y_axis.scaling.min = self.min_diff-0.1
        # self.chart.y_axis.scaling.max = self.max_diff+0.1
        data3 = Reference(
            self.ws,
            min_col=3,
            min_row=8,
            max_col=3,
            max_row=len(self.record_list[1])+8
        )
        seriesObj3 = Series(data3, title='電流')
        self.chart.append(seriesObj3)
        dates = Reference(self.ws, min_col=1, min_row=8, max_row=len(self.record_list[1]) + 8)
        self.chart.set_categories(dates)
        self.ws.add_chart(self.chart, "D49")

    def create(self,value=None):
        if value:
            self.ws.cell(row=1, column=1).value = value
        self.create_row1()
        self.add_data()
        self.draw_line_chart()
        if self.entity.experiment_type!=2:
            self.draw_electric_cur()

    def save(self, filename):
        try:
            self.wb.save(filename)
        except Exception as e:
            print(e)
            self.wb.save(filename[:-5] + str('_' + Utils.getFileName()) + filename[-5:])
        # 關閉excel
        self.close()

    def close(self):
        self.wb.close()

class TestObj:

    def __init__(self):
        self.test_list = ["start_time","experiment_user_name","material_name", "experiment_type","is_success", "time_cost","test_count"]

if __name__ == '__main__':
    t = TestObj()
    for idx,para in enumerate(t.test_list):
        t.__setattr__(para,idx)
    record_list = [
        [random.randrange(i,i+10) for i in range(100)],
        [random.random() for j in range(150)]
    ]
    export = ExportReport(t,record_list)
    export.create()
    export.save("127.xlsx")

3.1.3 作者最近工作用的一個圖

import uuid
import string
import json
import time
import os
import base64

from openpyxl.workbook import Workbook
from openpyxl.styles import Font, Alignment, Side, Border
from openpyxl.drawing import image
from openpyxl.chart import Series,LineChart, Reference

from Lib.Utils import Utils

class ExportReport:

    def __init__(self, start_time, water_temp, test_people,
                 sample_name, pressure_value, pressure_list,*args, **kwargs):
        """

        :param start_time: 實驗開始時間
        :param water_temp: 水浴溫度
        :param test_people: 試驗人
        :param sample_name: 樣品名稱
        :param pressure_value: 最終壓力
        :param args: 實驗過程壓力記錄列表
        :param kwargs:
        """
        self.start_time = start_time
        self.water_temp = str(water_temp)+' ℃'
        self.test_people = test_people
        self.sample_name = sample_name
        self.pressure_value = pressure_value
        self.all_col = 5+len(pressure_list) #一共多少列
        self.pressure_record = pressure_list #第六列到最后一列的數據列表
        self.image_path = kwargs.get('imgPath', None)  #圖片路徑
        #所有的數據列
        self.data_list = [
            self.start_time, self.water_temp,
            self.test_people,self.sample_name,
            self.pressure_value
        ]
        self.data_list.extend(self.pressure_record)
        self.col_list = ["開始時間", "水浴溫度", "測試人", "樣品名稱", "最終壓力值"]

        # base64轉化為圖片
        # self.bs64 = bs64
        # self.img_path = Utils.change_base64_as_img(self.bs64)

        self.wb = Workbook()
        #self.wb.remove(self.wb["sheet"])

        self.ws = self.wb.create_sheet("{0}蒸汽壓力記錄表".format(self.sample_name), 0)
        #生成所含列總數的大寫字母
        self.upper_string_list = string.ascii_uppercase[:self.all_col]
        # 水平對齊,居中對齊
        self.alignment_style = Alignment(horizontal='center', vertical='center')
        #定義border 邊框樣式
        left, right, top, bottom = [Side(style='thin', color='000000')]*4
        self.border_style = Border(left=left, right=right, top=top, bottom=bottom)
        #定義字體
        self.font_size = Font(size=9)
        for col in self.upper_string_list:
            self.ws.column_dimensions[col].width = 20

    #單元格樣式字體調整
    def cell_set(self, cellObj, fontSzie=12, alignmentStyle=None):
        alignmentStyle = alignmentStyle if alignmentStyle else self.alignment_style
        cellObj.alignment = alignmentStyle
        cellObj.font = Font(size=fontSzie, bold=True)

    #創建表頭第一行
    def create_row1(self):
        #把所有列合並
        self.ws.merge_cells(start_row=1, end_row=1, start_column=1, end_column=self.all_col)
        #寫入值
        # self.ws.cell(row=1, column=1).value = value
        self.ws.cell(row=1, column=1).value = "{0}蒸汽壓力記錄表".format(self.sample_name)
        # self.ws['A1'].alignment = self.alignment_style
        # self.ws['A1'].font = Font(size=16, bold=True)
        self.cell_set(self.ws['A1'], 16)
        self.create_row2_3()

    def create_row2_3(self):
        #把前五列,二三行單元格合並,並寫入值
        for col in range(1, len(self.col_list)+1):
            self.ws.merge_cells(start_row=2, end_row=3, start_column=col, end_column=col)
            col_str = self.upper_string_list[col-1]+"2"
            self.ws[col_str] = self.col_list[col-1]
            # self.ws[col_str].alignment = self.alignment_style
            # self.ws[col_str].font = Font(size=12, bold=True)
            self.cell_set(self.ws[col_str])

        #把第二行第六列開始到最后列合並
        self.ws.merge_cells(start_row=2, end_row=2, start_column=len(self.col_list)+1, end_column=self.all_col)
        col_str = self.upper_string_list[len(self.col_list)]+"2"
        self.ws[col_str] = "實驗過程壓力記錄"
        # self.ws[col_str].alignment = self.alignment_style
        # self.ws[col_str].font = Font(size=12, bold=True)
        self.cell_set(self.ws[col_str])

        #第三行第六列開始到最后列寫入值
        for index, col_ltr in enumerate(self.upper_string_list[len(self.col_list):]):
            col_str = col_ltr+'3'
            self.ws[col_str] = "第{0}次壓力記錄".format(index+1)
            # self.ws[col_str].alignment = self.alignment_style
            # self.ws[col_str].font = Font(size=12, bold=True)
            self.cell_set(self.ws[col_str])

    def add_data(self):
        #第四行開始寫入數據,所有數據居中對齊,水平居中
        for index, col in enumerate(self.upper_string_list):
            col_str = col+"4"
            self.ws[col_str] = self.data_list[index]
            # self.ws[col_str].alignment = self.alignment_style
            # self.ws[col_str].font = Font(size=12, bold=True)
            self.cell_set(self.ws[col_str])

    #畫折線圖
    def draw_line_chart(self):
        data_col = self.ws["{0}:{1}".format(self.upper_string_list[len(self.col_list)]+"3",self.upper_string_list[-1]+"3" )]
        self.chart = LineChart()
        self.chart.width = 21.2
        self.chart.height = 8
        self.chart.style = 2 ##線條的style,Max value is 48   2 10
        self.chart.title = "壓力記錄圖"
        self.chart.y_axis.title = "壓力值"
        self.chart.x_axis.title = "壓力測量次數"
        #從活動表中關聯壓力記錄次數數據, 第六行到第10行
        data = Reference(
            self.ws,
            min_col=len(self.col_list)+1,
            min_row=4,
            max_col=self.all_col,
            max_row=4
        )
        #將數據添加到系列中
        seriesObj = Series(data, title='壓力')
        format_str = "第{0}次記錄:/n壓力:{1}".format(seriesObj.xVal,seriesObj.yVal)
        # seriesObj.labels
        self.chart.append(seriesObj)
        # self.chart.add_data(data, from_rows=False)
        # style = self.chart.series[0]
        # style.smooth = True
        self.ws.add_chart(self.chart, "A6")

    def create(self,value=None):
        if value:
            self.ws.cell(row=1, column=1).value = value
        self.create_row1()
        self.add_data()
        self.draw_line_chart()

    def save(self, filename):
        try:
            self.wb.save(filename)
        except:
            self.wb.save(filename[:-5] + str('_' + Utils.getFileName()) + filename[-5:])

        # 關閉excel
        self.close()

    def close(self):
        self.wb.close()

if __name__ == '__main__':
    er = ExportReport(1, 2, 3, 4, 5, [17, 15, 19, 13,24])
    er.create()
    er.wb.save('17表.xlsx')



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM