Openpyxl not showing second graph - python

EDIT: Solved, solution in answer below.
I have a graph created with openpyxl that has two y axes sharing a DateAxis. Although the first selection of data is showing on the graph, the second isn't. There's also a strange gray line on the bottom of the graph that wasn't there before. I think it's just a small error I'm missing somewhere, but I can't see where. Especially considering I have my range of cells defined correctly. What could I be doing wrong?
import openpyxl
from openpyxl import Workbook, chart
from openpyxl.chart import LineChart, Reference, Series
from openpyxl.chart.axis import DateAxis
from datetime import date, datetime, timedelta, time
ws2 = wb['sheet2']
dates = chart.Reference(ws2, min_col=1, min_row=2, max_row=sheet.max_row)
vBat = chart.Reference(ws2, min_col=2, min_row=1, max_col=2, max_row=sheet.max_row)
qBat = chart.Reference(ws2, min_col=3, min_row=1, max_col=3)
c1 = chart.LineChart()
c1.title = "SLA Discharge - 5.5A: V_BAT"
c1.style = 12
c1.x_axis.majorTimeUnit = "days"
c1.x_axis = chart.axis.DateAxis()
c1.x_axis.title = "Time"
c1.x_axis.crosses = "min"
c1.x_axis.majorTickMark = "out"
c1.x_axis.number_format = 'd-HH-MM-SS'
c1.add_data(vBat, titles_from_data=True)
c1.set_categories(dates)
c1.y_axis.title = "Battery Voltage"
c1.y_axis.crossAx = 500
c1.y_axis.majorGridlines = None
c2 = chart.LineChart()
c2.x_axis.axId = 500 # same as c1
c2.add_data(qBat, titles_from_data=True, from_rows=True)
c2.set_categories(dates)
c2.y_axis.axId = 200
c2.y_axis.title = "Qbat Percentage"
c2.y_axis.crossAx = 500
c1.y_axis.crosses = "max"
c1 += c2
s1 = c1.series[0]
s1.graphicalProperties.line.solidFill = "BE4B48"
s1.graphicalProperties.line.width = 25000 # width in EMUs.
s1.smooth = True # Make the line smooth
s2 = c2.series[0]
s2.graphicalProperties.line.solidFill = "48BBBE"
s2.graphicalProperties.line.width = 25000 # width in EMUs.
s2.smooth = True # Make the line smooth
ws2.add_chart(c1, "D5")
Interestingly enough,
vBat = chart.Reference(ws2, min_col=2, min_row=1, max_col=2, max_row=sheet.max_row)
is fine. However, doing the same thing to qBat with:
qBat = chart.Reference(ws2, min_col=3, min_row=1, max_col=3, max_row=sheet.max_row)
"corrupts" the workbook and displays an error message upon opening and doesn't print any chart. Removing max_row=sheet.max_row from both lines produces an incorrect DateAxis where there are only two points and they're both the first two values in the time column.

first, in c2.add_data(qBat, titles_from_data=True, from_rows=True), remove from_rows=True.
Then, change qBat to:
qBat = chart.Reference(ws2, min_col=3, min_row=1, max_col=3, max_row=sheet.max_row)

Related

Adding borders to rows and columns with openpyxl

How can I add borders to whole rows and columns with openpyxl?
I tried:
import openpyxl
from openpyxl.styles import borders
from openpyxl.styles.borders import Border
wb = openpyxl.Workbook()
ws = wb.active
border1 = borders.Side(style = None, color = Color(indexed = 0), border_style = 'thin')
border0 = borders.Side(style = None, color = None, border_style = None)
thin = Border(left = border1, right = border0, bottom = border0, top = border 0)
ws.column['C'].border = thin
I then got the Error:
Worksheet object has no attribute column
Is there a possibility to assign the border to whole row/column or do I need to apply it to the cells one by one?
Here an example how to iterate through the cells to aplly the border to each cell. min_col = 3 and max_col = 3 leads to column 'C' and with max_row you can set till which row you want the border.
import openpyxl
from openpyxl.styles import borders
from openpyxl.styles.borders import Border
wb = openpyxl.load_workbook('border.xlsx')
ws = wb.active
border1 = borders.Side(style = None, color = 'FF000000', border_style = 'thin')
border0 = borders.Side(style = None, color = None, border_style = None)
thin = Border(left = border1, right = border0, bottom = border0, top = border0)
for row in ws.iter_rows(min_row=1, min_col=3, max_row=20, max_col=3):
for cell in row:
cell.border = thin
wb.save('border_new.xlsx')

Is it is possible to reference existing data to create a chart using openpyxl?

I have some data that is already in an xlsx sheet. Is it possible to build a chart using openpyxl with this data that already exists in these cells? The data gets updated monthly.
data
category 3/1/2021 3/8/2021
computer 2646 3000
network 117 200
other 316 20
total 3079 3220
Desired:
A chart month by month chart next to the data
Doing:
from datetime import date
from openpyxl import Workbook
from openpyxl.chart import (
LineChart,
Reference,
)
from openpyxl.chart.axis import DateAxis
wb = Workbook()
ws = wb.active
c2 = LineChart()
c2.title = "Date Axis"
c2.style = 12
c2.y_axis.title = "Size"
c2.y_axis.crossAx = 500
c2.x_axis = DateAxis(crossAx=100)
c2.x_axis.number_format = 'd-mmm'
c2.x_axis.majorTimeUnit = "days"
c2.x_axis.title = "Date"
c2.add_data(data, titles_from_data=True)
dates = Reference(ws, min_col=1, min_row=2, max_row=5)
c2.set_categories(dates)
ws.add_chart(c2, "E1")
Any suggestion is appreciated
#pull in your data
wb_obj = load_workbook(path)
sheet_obj = wb_obj.active
c1 = BarChart()
c1.title = "Test"
c1.y_axis.title = "Test1"
c1.x_axis.title = "Test2"
#reference your data
data = Reference(sheet_obj, min_col=2, min_row=2, max_col=3, max_row=5)
c1.add_data(data, titles_from_data=True)
#save the data
sheet_obj.add_chart(c1, "E1")
wb_obj.save("samples.xlsx")

How to add the Data into the existing Chart dynamically using openpyxl

I am trying add the Data into the existing Line Chart dynamically when new data comes in into the excel using openpyxl. Below is the sample code I tried But when else part is encountered there is no changes in the chart.
Thanks
from openpyxl import load_workbook
from openpyxl.chart import (LineChart, Reference)
wb = load_workbook("Hello.xlsx")
sheet = wb.active
exists = 0
chart = LineChart()
if exists == 1:
values = Reference(sheet, min_col=3, min_row=1, max_row=sheet.max_row)
categories = Reference(sheet, min_col=1, min_row=2, max_row=sheet.max_row,max_col=1)
chart.add_data(values, titles_from_data=True)
chart.set_categories(categories)
chart.title = "sample"
chart.x_axis.title = "date"
chart.y_axis.title = "followers"
sheet.add_chart(chart, "F2")
else:
values_update = Reference(sheet, min_col=3, min_row=1, max_row=sheet.max_row)
chart.add_data(values_update)
wb.save("Hello.xlsx")

openpyxl conditional formatting - Rule is in Excel file but not the formatting

My goal is to create an Excel file and change the background color of some cells based on their value using conditional formatting, using openpyxl.
When I open the file created with Excel, I can see that the rule is there, but the rule does not include the formatting to apply (background color set to none). The cells have thus no background color, although the border of the cells respecting the formula are not visible, like when the background is white.
I don't see if I made a mistake, or if there is some trouble with openpyxl.
Here is a MWE:
from openpyxl import Workbook
from openpyxl.styles import PatternFill
from openpyxl.formatting.rule import CellIsRule
wb = Workbook()
ws = wb.active
ws['B2'] = -2
ws['B3'] = -1
ws['B4'] = 0
ws['C2'] = -1
ws['C3'] = 0
ws['C4'] = 1
fill = PatternFill(start_color='538DD5', fill_type='solid')
ws.conditional_formatting.add('B2:C4', CellIsRule(operator='lessThan', formula=[0], fill=fill))
wb.save('mwe.xlsx')
wb.close()
You need to add the parameter end_color like this :
fill = PatternFill(start_color='538DD5',end_color='538DD5',fill_type='solid')
check this link : https://openpyxl.readthedocs.io/en/stable/formatting.html
from openpyxl import Workbook
from openpyxl.styles import PatternFill
from openpyxl.formatting.rule import CellIsRule
wb = Workbook()
ws = wb.active
ws['B2'] = -2
ws['B3'] = -1
ws['B4'] = 0
ws['C2'] = -1
ws['C3'] = 0
ws['C4'] = 1
fill = PatternFill(start_color='538DD5',end_color='538DD5',fill_type='solid')
#print(fill)
ws.conditional_formatting.add('B2:C4', CellIsRule(operator='lessThan', formula=[0], fill=fill))
wb.save('mwe.xlsx')
wb.close()
result :
Following #GiovaniSalazar answer, I did more tests.
The parameters used for the color (start_color, end_color, fgColor, bgColor) do not have the same behaviour with conditional formatting and simple formatting (bug in openpyxl ?).
Here is a comparison of both. The only one working for both formatting is start_color + end_color.
from openpyxl import Workbook
from openpyxl.styles import PatternFill
from openpyxl.formatting.rule import CellIsRule
wb = Workbook()
ws = wb.active
ws['C2'] = -4
ws['C3'] = -3
ws['C4'] = -2
ws['C5'] = -1
ws['D2'] = 4
ws['D3'] = 3
ws['D4'] = 2
ws['D5'] = 1
ws['C1'] = 'Cond. formatting'
ws['F1'] = 'Formatting'
ws['A2'] = 'start+end'
fill = PatternFill(start_color='538DD5', end_color='538DD5', fill_type='solid')
# OK
ws.conditional_formatting.add('C2:D2', CellIsRule(operator='lessThan', formula=[0], fill=fill))
# OK
ws['F2'].fill = fill
ws['A3'] = 'start'
fill = PatternFill(start_color='538DD5', fill_type='solid')
# Problem (white background)
ws.conditional_formatting.add('C3:D3', CellIsRule(operator='lessThan', formula=[0], fill=fill))
# OK
ws['F3'].fill = fill
ws['A4'] = 'fgColor'
fill = PatternFill(fgColor='538DD5', fill_type='solid')
# Problem (white background)
ws.conditional_formatting.add('C4:D4', CellIsRule(operator='lessThan', formula=[0], fill=fill))
# OK
ws['F4'].fill = fill
ws['A5'] = 'bgColor'
fill = PatternFill(bgColor='538DD5', fill_type='solid')
# OK
ws.conditional_formatting.add('C5:D5', CellIsRule(operator='lessThan', formula=[0], fill=fill))
# Problem (black background)
ws['F5'].fill = fill
wb.save('mwe.xlsx')
wb.close()
Output Excel file:
Output Excel file

How to set line color of openpyxl ScatterChart

I am trying to set the line of an openpyxl scatter chart to green:
from openpyxl import *
book = workbook.Workbook()
ws = book.active
xRef = chart.Reference(ws, min_col=1, min_row=2, max_row=22)
yRef = chart.Reference(ws, min_col=2, min_row=2, max_row=22)
chart.Series(yRef, xvalues=xRef, title='test')
lineProp = drawing.line.LineProperties(solidFill = 'green')
series.graphicalProperties.line = lineProp
While this code does not cause any problems, it does not change the line color from the default. What is the correct way to change the line color?
Interestingly I have no problem setting the style to dashed or dotted using:
lineProp = drawing.line.LineProperties(prstDash='dash')
series.graphicalProperties.line = lineProp
As it turns out, the line width can remain default. I got the color change to work by setting solidFill to an instance of openpyxl.drawing.colors.ColorChoice:
lineProp = drawing.line.LineProperties(solidFill = drawing.colors.ColorChoice(prstClr='green'))

Categories