Получение значений x_values ​​из графика XY Scatter в python-pptx - PullRequest
0 голосов
/ 01 октября 2019

Я пытаюсь использовать python-pptx для извлечения данных разброса XY для особых случаев, когда нет справочной таблицы Excel и мой существующий код VBA не может прочитать данные. Я могу получить все значения y_, но я не смог понять, как получить x_values. Из документации я понимаю, что у XY Scatter нет «категорий», как на других графиках. Тем не менее, я не вижу ни метода, ни объекта на графике или chart.plots[0], которые бы дали мне доступ к x_values. Я вижу только "categories" и, конечно, он пуст для XY Scatter.

    def get_chart_data():
    for sld in prs.slides:
        for shape in sld.shapes:
            if shape.has_chart:
                chart = shape.chart
                series_data=[]
                for series in chart.series:
                    y_val = []
                    for value in series.values:
                        y_val.append(value)

Ответы [ 2 ]

0 голосов
/ 05 октября 2019

Я хотел опубликовать окончательный код, основанный на ответе от @scanny. Моя цель в этом заключалась в том, чтобы иметь возможность циклически просматривать слайды Power Point и извлекать данные из графиков XY Scatter, которые больше не имели связанных листов Excel.

from pptx import Presentation
from pptx.chart.series import XySeries
import numpy as np

def get_chart_data(prs):
    for sld in prs.slides:
        for shape in sld.shapes:
            if shape.has_chart:
                chart = shape.chart
                series_data = {}
                series_data[shape.name] = {}
                if isinstance(chart.series[0], XySeries): #check if XY Series
                    for series in chart.series:
                        x_values, y_values = read_xy(series)

                        #create dictionary with Chart name and series names
                        series_data[shape.name][series.name] = np.array([x_values, y_values])
                    for c in series_data.keys(): #get chart keys
                        for s in series_data[c].keys(): # get series keys
                            data_final = series_data[c][s].T #retrieve XY data for given chart and series
                            np.savetxt(f'{shape.name}_{s}.csv', data_final, delimiter=',')

def read_xy(series):
    xVal = {}
    yVal = {}
    ser = series._ser
    x_pts = ser.xpath(".//c:xVal//c:pt") # get all xVals from xml with xpath query
    y_pts = ser.xpath(".//c:yVal//c:pt") # get all yVals from xml with xpath query
    for i in range(len(x_pts)): #loop through all xVals
        x_value = get_pt_val(x_pts[i]) #call function to get each x value
        y_value = get_pt_val(y_pts[i]) #call function to get each y value
        xVal[x_pts[i].idx] = x_value #store x value in dictionary
        yVal[y_pts[i].idx] = y_value # store y value in dictionary

    # in case x & y idx don't have matching pairs return keys that are common to both x & y
    key = set.intersection(*tuple(set(d.keys()) for d in [xVal, yVal]))
    xVal = [xVal[x] for x in key] #create xVal list
    yVal = [yVal[x] for x in key] #create yVal list
    return xVal, yVal

def get_pt_val(pt):
    str_value = pt.xpath("./c:v")[0].text #retrieve point value
    value = float(str_value)
    return value

if __name__ == '__main__':
    prs = Presentation('Test.pptx')
    get_chart_data(prs)

0 голосов
/ 01 октября 2019

Для этого пока нет поддержки API, поэтому, если вы хотите, чтобы это было достаточно плохо, вам придется погрузиться до вызовов уровня lxml, чтобы получить его.

Пример XML для XY-Точечная диаграмма показана в этом python-pptx аналитическом документе: https://python -pptx.readthedocs.io / en / latest / dev / analysis / cht-xy-chart.html # xml-specimen . Вот частичный фрагмент:

<c:chart>
    <c:scatterChart>
      <c:ser>
        ...
        <c:xVal>
          <c:numRef>
            <c:f>Sheet1!$A$2:$A$7</c:f>
            <c:numCache>
              <c:formatCode>General</c:formatCode>
              <c:ptCount val="6"/>
              <c:pt idx="0">
                <c:v>0.7</c:v>
              </c:pt>
              <c:pt idx="1">
                <c:v>1.8</c:v>
              </c:pt>
              <c:pt idx="2">
                <c:v>2.6</c:v>
              </c:pt>
            </c:numCache>
          </c:numRef>
        </c:xVal>
        <c:yVal>
          <c:numRef>
            <c:f>Sheet1!$B$2:$B$7</c:f>
            <c:numCache>
              <c:formatCode>General</c:formatCode>
              <c:ptCount val="6"/>
              <c:pt idx="0">
                <c:v>2.7</c:v>
              </c:pt>
              <c:pt idx="1">
                <c:v>3.2</c:v>
              </c:pt>
              <c:pt idx="2">
                <c:v>0.8</c:v>
              </c:pt>
            </c:numCache>
          </c:numRef>
        </c:yVal>
      </c:ser>
      ...
    <c:scatterChart>
    ...
<c:chart>

Данные о точках разделены между элементом c:xVal и c:yVal. Вы можете использовать вызовы XPath и lxml.etree._Element, чтобы получить его:

for series in chart.series:
    ser = series._ser
    x_pts = ser.xpath(".//c:xVal//c:pt")
    for pt in x_pts:
        print("pt.idx == %s", pt.get("idx"))
        str_value = pt.xpath("./c:v")[0].text
        value = float(str_value)
        print("value == %s" % value)

Вам необходимо расширить этот общий подход, чтобы также получать значения Y, сопоставляя их по парам (x, y) на основепри сопоставлении idx (не полагайтесь на порядок документов), возможно, отбрасывая любые, которые не образуют полные наборы;Я смутно помню, что это может произойти.

...