问题
I've been assigned a "simple" task of collecting series of data columns to a results workbook. The results workbook contains necessary formulas and charts to analyze the results. The data is generated by an image analysis application I've written in python as series of excel workbooks.
Now the problem is that openpyxl drops any existing charts in excel workbooks. I've spent the day figuring out how to use openpyxl charts for which there is some documentation and chart errorbars for which there are no examples whatsoever. There is the source which has terse comments..
Using win32com extension would allow interacting with Excel directly but that obviously won't work except in windows and if Excel is installed. This may not be the case. Also trying to figure out how interact with Excel that way might take a while instead of doing it from a VBA macro.
..
For setting chart styles there is relatively nice method that works somewhat like this:
valuewidth=openpyxl.utils.units.points_to_pixels(2.25)
valuewidth=openpyxl.utils.units.pixels_to_EMU(valuewidth)
redcolor=openpyxl.drawing.colors.ColorChoice(prstClr="red")
bluecolor=openpyxl.drawing.colors.ColorChoice(prstClr="blue")
xvalues = openpyxl.chart.Reference(exceldata.sheetrep, min_col=exceldata.seriesx['column'], min_row=exceldata.seriesx['row'], max_row=exceldata.seriesx['row']+exceldata.seriesx['rows'])
values = openpyxl.chart.Reference(exceldata.sheetrep, min_col=exceldata.seriesy['column'], min_row=exceldata.seriesy['row'], max_row=exceldata.seriesy['row']+exceldata.seriesy['rows'])
series = openpyxl.chart.Series(values, xvalues, title_from_data=True)
series.graphicalProperties.line.width=valuewidth
series.graphicalProperties.line.solidFill=bluecolor
chart.series.append(series)
Now to work with error bars, they have to be defined and created like this:
errorwidth=openpyxl.utils.units.points_to_pixels(1)
errorwidth=openpyxl.utils.units.pixels_to_EMU(errorwidth)
errorlinetype=openpyxl.drawing.line.LineProperties(w=errorwidth, solidFill=redcolor)
errorline=openpyxl.chart.shapes.GraphicalProperties(ln=errorlinetype)
values = openpyxl.chart.Reference(exceldata.sheetrep, min_col=exceldata.lowerlim['column'], min_row=exceldata.lowerlim['row'])
xvalues = openpyxl.chart.Reference(exceldata.sheetrep, min_col=exceldata.lower['column'], min_row=exceldata.lower['row'])
chart.title="LL"
errorbar=openpyxl.chart.error_bar.ErrorBars(errBarType="minus",errValType="percentage",val=100.0, spPr=errorline)
errorbar.NumDataRef="LL"
series = openpyxl.chart.Series(values, xvalues, title=None, title_from_data=False)
series.errBars=errorbar
chart.series.append(series)
Now I'm wondering if there's a way to skip building that spPr object by first defining those LineProperties used to create GraphicalProperties object which is then fed to the ErrorBars method during instantiation.
That NumDataRef does not seem to do anything. It's not documented.
EDIT That call to NumDataRef is probably wrong in any case. plus and minus parameters expect NumDataSource of which NumDataRef is part of. Proper syntax would be likely again a two-step process of 1st creating the
foo = openpyxl.chart.data_source.NumRef(f="bar")
and then follow up by
minus = openpyxl.chart.data_source.NumDataSource(numRef="foo")
I'm not sure what the numRef actually refers to, if it's a cell, series name or something else. If anyone can contribute what the "plus", "minus" and "val" parameters do, it'd be helpful.
回答1:
It seems NumVal
, NumData
and NumDataSource
are needed to create ErrorBars
from scratch:
# References for X and Y
xvalues = Reference(<worksheet>, min_col=<xcol>, min_row=<min>, max_row=<max>)
yvalues = Reference(<worksheet>, min_col=<ycol>, min_row=<min>, max_row=<max>)
plus = [<list of error values for plus>]
minus = [<list of error values for minus>]
# Convert lists of error values to ErrorBars object
errorbars = list2errorbars(plus, minus, errDir='y')
# Create series data and set error bar
series = SeriesFactory(yvalues, xvalues, title="y direction error")
series.errBars = errorbars
def list2errorbars(plus, minus, errDir='y', errValType='cust'):
"Returns ErrorBar from lists of error values"
#Convert to list of NumVal
numvals_plus = [NumVal(i, None, v=x) for i,x in enumerate(plus)]
numvals_minus = [NumVal(i, None, v=x) for i,x in enumerate(minus)]
# Convert to NumData
nd_plus = NumData(pt=numvals_plus)
nd_minus = NumData(pt=numvals_minus)
# Convert to NumDataSource
nds_plus = NumDataSource(numLit=nd_plus)
nds_minus = NumDataSource(numLit=nd_minus)
return ErrorBars(plus=nds_plus, minus=nds_minus, errDir=errDir, errValType=errValType)
Full example code: https://github.com/uskysd/openpyxl-errorbar
Since I couldn't find good documentation either, I figured out from source code. Let me know if there are any easier ways to do this.
来源:https://stackoverflow.com/questions/36018934/openpyxl-chart-error-bar-styles