Ошибка Python win32com PivotCache.CreatePivotChart(): «Произошло исключение»

Есть еще один вопрос от сентября 2017 года, который решает эту же проблему, но не имеет ответа: создать сводную диаграмму с помощью python win32com

Я пробовал несколько подходов, чтобы заставить это работать, поэтому я хочу объяснить их и, надеюсь, получить от кого-то некоторое представление о том, как заставить это работать. Это не похоже на хорошо проторенный путь, поэтому у меня нет больших надежд.

Детали среды:

  • Windows 10
  • Офис 2013
  • Анаконда 3.6

я использую

win32com.client.gencache.EnsureDispatch('Excel.Application') 

но я также могу использовать

win32com.client.DispatchEx('Excel.Application') 

or

win32com.client.dynamic.Dispatch('Excel.Application')

Каждый возвращает этот CLSID win32com.gen_py.00020813-0000-0000-C000-000000000046x0x1x8

У всех одна и та же ошибка.

Я также выполнил эту команду в соответствии с документацией здесь:

C:\Users\home_dir>python AppData\Local\Continuum\anaconda3\pkgs\pywin32-223-py36hfa6e2cd_1\Lib\site-packages\win32com\client\makepy.py -i "Microsoft Excel 15.0 Object Library"
Output generated from makepy.py:
Microsoft Excel 15.0 Object Library {00020813-0000-0000-C000-000000000046}, lcid=0, major=1, minor=8
 >>> # Use these commands in Python code to auto generate .py support
 >>> from win32com.client import gencache
 >>> gencache.EnsureModule('{00020813-0000-0000-C000-000000000046}', 0, 1, 8)

Эта версия gencache не работала успешно:

Excel = win32com.client.gencache.EnsureModule('{00020813-0000-0000-C000-000000000046}', 0, 1, 8)

Исходные данные В кадре данных Pandas есть 100 строк и 18 столбцов, которые я записываю в Excel с помощью ExcelWriter.

ew = pd.ExcelWriter('c:\devworkspace\SQL-Pandas-Excel\SampleData.xlsx')
sample_data_df.to_excel(ew, sheet_name='Source Data')
ew.save()
ew.close()

Excel = win32com.client.gencache.EnsureDispatch('Excel.Application') 
win32c = win32com.client.constants
wb = Excel.Workbooks.Open('c:\devworkspace\SQL-Pandas-Excel\SampleData.xlsx')
src_sheet = wb.Worksheets('Source Data')

rng_row = 100
rng_col = 18
rng_beg = src_sheet.Cells(1,2)
rng_end = src_sheet.Cells(rng_row,rng_col)
pvt_src_rng = src_sheet.Range(rng_beg, rng_end)
pvt_src_rng.Select()
pvt_src = "%s!R1C2:R%dC%d"%(src_sheet.Name,rng_row+1,rng_col+1) #add 1 for header and df index

Сводной кэш Я использую PivotCaches().Create(), а не .Add(), поэтому я могу указать Version=win32c.xlPivotTableVersion15, которая является правильной версией для Office 2013. В противном случае по умолчанию используется версия 11.

pc = wb.PivotCaches().Create(SourceType=win32c.xlDatabase, SourceData=pvt_src, Version=win32c.xlPivotTableVersion15)

Это изменение переместило циферблат, но не решило мою проблему — я все еще получаю сообщение об ошибке, и диаграмма не создается:

  • Когда я применил это изменение, форматирование в сводной таблице улучшилось.
  • Код основной ошибки изменился с -2147024809, что означает "Неверный параметр", на код основной ошибки -2146827284.

Что он не может перевести в удобочитаемое сообщение:

print(win32api.FormatMessage(error.excepinfo[5]))
error: (317, 'FormatMessageW', 'The system cannot find message text for message number 0x%1 in the message file for %2.')

При поиске этого кода ошибки 2146827284 обсуждения, похоже, связаны с тем, что объект excel занят. Но для Excel.Visible установлено значение 0 — также значение по умолчанию — поэтому он работает в автономном режиме.

Добавление листов, создание сводной таблицы, добавление полей выполнено успешно. Все они заключены в try, за исключением фактического кода, который удален для краткости.

pvt_sheet = wb.Sheets.Add(After=src_sheet)
pvt_sheet.Name = 'Pivot Sheet'

pvt_rng_beg = pvt_sheet.Cells(2,2)
pvt_rng_end = pvt_sheet.Cells(2,2)
pvt_dest_rng = pvt_sheet.Range(pvt_rng_beg, pvt_rng_end)


pt = pc.CreatePivotTable(TableDestination=pvt_dest_rng,TableName='PivotTable1')
pt.AddFields(RowFields="claimant_type_desc" , ColumnFields="claim_cause_desc" )
pt.AddDataField(Field=pt.PivotFields("total_direct_payment"), Caption="Total Incurred")

Я могу добавить лист или диаграмму в качестве «ChartDestination», но ни один из вариантов не изменит результат. Я могу подтвердить, что объект успешно добавляется.

#chrt_sheet = wb.Charts.Add(After=pvt_sheet)
chrt_sheet = wb.Sheets.Add(After=pvt_sheet)
chrt_sheet.Name = 'Pivot Chart'

Аргумент ChartDestination является единственным обязательным аргументом, остальные аргументы являются необязательными: XlChartType, Left, Top, Width, Height.

Документы здесь:

Основываясь на примерах, я передаю имя объекта листа или диаграммы в виде строки «Сводной лист». Это должно сработать.

pch = pc.CreatePivotChart(ChartDestination='Pivot Chart')

Поскольку параметр определен как Variant, я явно назначаю строку объекту Variant. Я пробовал разные типы вариантов, но это не дало другого результата.

chrt_sheet_name_variant = win32com.client.VARIANT(pythoncom.VT_BYREF | pythoncom.VT_BSTR, chrt_sheet.Name)
print(chrt_sheet_name_variant.value)
print(chrt_sheet_name_variant.varianttype)
print(chrt_sheet_name_variant.__class__)
print(type(chrt_sheet_name_variant))
pch = pc.CreatePivotChart(ChartDestination=chrt_sheet_name_variant)

#Output:    
#Pivot Chart
#16392
#<class 'win32com.client.VARIANT'>
#<class 'win32com.client.VARIANT'>

Сгенерирована следующая ошибка:

File "C:\Users\xxxxxx\AppData\Local\Temp\gen_py\3.6\00020813-0000-0000-C000-000000000046x0x1x8\PivotCache.py", line 36, in CreatePivotChart
, XlChartType, Left, Top, Width, Height

com_error: (-2147352567, 'Exception occurred.', (0, None, None, None, 0, -2146827284), None)

person Threadid    schedule 21.08.2018    source источник


Ответы (1)


Спасибо Boussif за то, что нашли способ.

Вот мое рабочее решение:

Создайте сводную диаграмму из сводной таблицы

Используя объект Workbook, который мы создали ранее, мы можем «вставить» диаграмму в нашу книгу и присвоить имя нашей диаграмме — имя появится на вкладке.

Поскольку сводная таблица является объектом в кэше сводных данных, который является объектом в рабочей книге, объект диаграммы добавляется как сводная диаграмма и использует сводную таблицу в качестве данных.

Прочтите соответствующую документацию здесь:

https://docs.microsoft.com/en-us/office/vba/api/excel.workbook.charts

https://docs.microsoft.com/en-us/office/vba/api/excel.chart(object)

chrt_sheet = wb.Charts.Add()
chrt_sheet.Name = 'Pivot Chart'

Укажите тип диаграммы

Тип диаграммы соответствует тем же типам диаграмм, которые доступны в программе Excel.

Выберите из списка перечисленных типов.

Например, трехмерная столбчатая диаграмма имеет значение xl3DColumn, закодированное следующим образом:

win32c.xl3DColumn

Используйте объект win32c, определенный ранее, для ссылки на все постоянные значения, включая перечисляемые списки.

Задокументировано здесь:

https://docs.microsoft.com/en-us/office/vba/api/excel.chart.charttype

https://docs.microsoft.com/en-us/office/vba/api/excel.xlcharttype

chrt_sheet.ChartType =  win32c.xl3DColumn

Задайте заголовок диаграммы

Объект листа не будет иметь свойство ChartTitle, пока для свойства HasTitle не будет установлено значение True.

chrt_sheet.HasTitle = True
chrt_sheet.ChartTitle.Text = "Chart Title"

Установите цветовую схему

Значения ChartColor 10–26 соответствуют меню «Изменить цвета» на вкладке «ДИЗАЙН» ленты «ИНСТРУМЕНТЫ ДИАГРАММЫ».

chrt_sheet.ChartColor = 13

Укажите макет диаграммы

Макет является необязательным

Макеты аналогичны списку макетов для выбора в программе Excel.

В этом случае они не предоставляются в виде пронумерованного списка. Таким образом, вы должны предоставить номер для макета. Обычно это будет от 1 до 10. Макеты различаются в зависимости от соответствующего типа диаграммы. Чтобы узнать, какой макет выбрать, вам нужно будет запустить программу Excel и попробовать каждый из них. Если вы наведете указатель мыши на параметр «Макет», отобразится «Подсказка» с названием макета. Например: «Макет 7». Вы должны указать номер, связанный с вашим соответствующим макетом.

вы используете метод ApplyLayout для выбора макета:

ApplyLayout(Layout, Chart Type)

Задокументировано здесь:

https://docs.microsoft.com/en-us/office/vba/api/excel.chart.applylayout

chrt_sheet.ApplyLayout(7, win32c.xl3DColumn)

Укажите стиль диаграммы

Стиль не является обязательным

В документации указано, что от 1 до 48 являются допустимыми значениями. Однако правильный диапазон зависит от того, какой тип диаграммы выбран.

В зависимости от типа диаграммы также допустимы значения от 201 до 352.

Чтобы получить числовые значения, соответствующие выбранным стилям, доступным для вашего типа диаграммы:

  1. На вкладке «Разработчик» — запустить макрос
  2. На вкладке «Дизайн диаграммы» выберите все стили.
  3. На вкладке «Разработчик» — остановить запуск макроса.
  4. На вкладке «Разработчик» — отредактируйте макрос

Это покажет правильные значения для вашего случая

Для столбчатой ​​трехмерной диаграммы диапазон составляет от 286 до 297.

Соответствующая документация здесь:

https://docs.microsoft.com/en-us/office/vba/api/excel.chart.chartstyle

xlChartStyle = 294
chrt_sheet.ClearToMatchStyle
chrt_sheet.ChartStyle = xlChartStyle

Эксперимент со стилем диаграммы

Если вам любопытно и вы хотите увидеть, как выглядит каждый из них, запустите этот код

подсказка: удалить комментарии '#'

#import time
#from time import sleep
​
#for xlChartStyle in range(286, 297):
#    try:
#        chrt_sheet.ClearToMatchStyle
#        chrt_sheet.ChartStyle = xlChartStyle
#        chrt_sheet.ChartTitle.Text = "Chart Style = "+str(xlChartStyle)
#        sleep(1)
#    except pythoncom.com_error as error:
#        print("Chart Style = %s" % str(xlChartStyle))

Форматировать метки осей

Существует три измерения оси, указанные перечислением XlAxisType.

  • Ось X = xlCategory
  • Ось Y = xlValue
  • Ось Z = xlSeriesAxis (только для трехмерных диаграмм)

В этом примере мы также удаляем метки деления оси Z.

chrt_sheet.Axes(win32c.xlCategory).AxisTitle.Text = "X Axis Title"
chrt_sheet.Axes(win32c.xlSeries).TickLabelPosition = win32c.xlNone
chrt_sheet.Axes(win32c.xlSeries).HasTitle = True
chrt_sheet.Axes(win32c.xlSeries).AxisTitle.Text = "Z Axis Title"
chrt_sheet.Axes(win32c.xlValue).AxisTitle.Text = "Y Axis Title"
person Threadid    schedule 18.10.2018