diff options
Diffstat (limited to '.venv/lib/python3.12/site-packages/pptx/chart/chart.py')
-rw-r--r-- | .venv/lib/python3.12/site-packages/pptx/chart/chart.py | 280 |
1 files changed, 280 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/pptx/chart/chart.py b/.venv/lib/python3.12/site-packages/pptx/chart/chart.py new file mode 100644 index 00000000..d73aa933 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/pptx/chart/chart.py @@ -0,0 +1,280 @@ +"""Chart-related objects such as Chart and ChartTitle.""" + +from __future__ import annotations + +from collections.abc import Sequence + +from pptx.chart.axis import CategoryAxis, DateAxis, ValueAxis +from pptx.chart.legend import Legend +from pptx.chart.plot import PlotFactory, PlotTypeInspector +from pptx.chart.series import SeriesCollection +from pptx.chart.xmlwriter import SeriesXmlRewriterFactory +from pptx.dml.chtfmt import ChartFormat +from pptx.shared import ElementProxy, PartElementProxy +from pptx.text.text import Font, TextFrame +from pptx.util import lazyproperty + + +class Chart(PartElementProxy): + """A chart object.""" + + def __init__(self, chartSpace, chart_part): + super(Chart, self).__init__(chartSpace, chart_part) + self._chartSpace = chartSpace + + @property + def category_axis(self): + """ + The category axis of this chart. In the case of an XY or Bubble + chart, this is the X axis. Raises |ValueError| if no category + axis is defined (as is the case for a pie chart, for example). + """ + catAx_lst = self._chartSpace.catAx_lst + if catAx_lst: + return CategoryAxis(catAx_lst[0]) + + dateAx_lst = self._chartSpace.dateAx_lst + if dateAx_lst: + return DateAxis(dateAx_lst[0]) + + valAx_lst = self._chartSpace.valAx_lst + if valAx_lst: + return ValueAxis(valAx_lst[0]) + + raise ValueError("chart has no category axis") + + @property + def chart_style(self): + """ + Read/write integer index of chart style used to format this chart. + Range is from 1 to 48. Value is |None| if no explicit style has been + assigned, in which case the default chart style is used. Assigning + |None| causes any explicit setting to be removed. The integer index + corresponds to the style's position in the chart style gallery in the + PowerPoint UI. + """ + style = self._chartSpace.style + if style is None: + return None + return style.val + + @chart_style.setter + def chart_style(self, value): + self._chartSpace._remove_style() + if value is None: + return + self._chartSpace._add_style(val=value) + + @property + def chart_title(self): + """A |ChartTitle| object providing access to title properties. + + Calling this property is destructive in the sense it adds a chart + title element (`c:title`) to the chart XML if one is not already + present. Use :attr:`has_title` to test for presence of a chart title + non-destructively. + """ + return ChartTitle(self._element.get_or_add_title()) + + @property + def chart_type(self): + """Member of :ref:`XlChartType` enumeration specifying type of this chart. + + If the chart has two plots, for example, a line plot overlayed on a bar plot, + the type reported is for the first (back-most) plot. Read-only. + """ + first_plot = self.plots[0] + return PlotTypeInspector.chart_type(first_plot) + + @lazyproperty + def font(self): + """Font object controlling text format defaults for this chart.""" + defRPr = self._chartSpace.get_or_add_txPr().p_lst[0].get_or_add_pPr().get_or_add_defRPr() + return Font(defRPr) + + @property + def has_legend(self): + """ + Read/write boolean, |True| if the chart has a legend. Assigning + |True| causes a legend to be added to the chart if it doesn't already + have one. Assigning False removes any existing legend definition + along with any existing legend settings. + """ + return self._chartSpace.chart.has_legend + + @has_legend.setter + def has_legend(self, value): + self._chartSpace.chart.has_legend = bool(value) + + @property + def has_title(self): + """Read/write boolean, specifying whether this chart has a title. + + Assigning |True| causes a title to be added if not already present. + Assigning |False| removes any existing title along with its text and + settings. + """ + title = self._chartSpace.chart.title + if title is None: + return False + return True + + @has_title.setter + def has_title(self, value): + chart = self._chartSpace.chart + if bool(value) is False: + chart._remove_title() + autoTitleDeleted = chart.get_or_add_autoTitleDeleted() + autoTitleDeleted.val = True + return + chart.get_or_add_title() + + @property + def legend(self): + """ + A |Legend| object providing access to the properties of the legend + for this chart. + """ + legend_elm = self._chartSpace.chart.legend + if legend_elm is None: + return None + return Legend(legend_elm) + + @lazyproperty + def plots(self): + """ + The sequence of plots in this chart. A plot, called a *chart group* + in the Microsoft API, is a distinct sequence of one or more series + depicted in a particular charting type. For example, a chart having + a series plotted as a line overlaid on three series plotted as + columns would have two plots; the first corresponding to the three + column series and the second to the line series. Plots are sequenced + in the order drawn, i.e. back-most to front-most. Supports *len()*, + membership (e.g. ``p in plots``), iteration, slicing, and indexed + access (e.g. ``plot = plots[i]``). + """ + plotArea = self._chartSpace.chart.plotArea + return _Plots(plotArea, self) + + def replace_data(self, chart_data): + """ + Use the categories and series values in the |ChartData| object + *chart_data* to replace those in the XML and Excel worksheet for this + chart. + """ + rewriter = SeriesXmlRewriterFactory(self.chart_type, chart_data) + rewriter.replace_series_data(self._chartSpace) + self._workbook.update_from_xlsx_blob(chart_data.xlsx_blob) + + @lazyproperty + def series(self): + """ + A |SeriesCollection| object containing all the series in this + chart. When the chart has multiple plots, all the series for the + first plot appear before all those for the second, and so on. Series + within a plot have an explicit ordering and appear in that sequence. + """ + return SeriesCollection(self._chartSpace.plotArea) + + @property + def value_axis(self): + """ + The |ValueAxis| object providing access to properties of the value + axis of this chart. Raises |ValueError| if the chart has no value + axis. + """ + valAx_lst = self._chartSpace.valAx_lst + if not valAx_lst: + raise ValueError("chart has no value axis") + + idx = 1 if len(valAx_lst) > 1 else 0 + return ValueAxis(valAx_lst[idx]) + + @property + def _workbook(self): + """ + The |ChartWorkbook| object providing access to the Excel source data + for this chart. + """ + return self.part.chart_workbook + + +class ChartTitle(ElementProxy): + """Provides properties for manipulating a chart title.""" + + # This shares functionality with AxisTitle, which could be factored out + # into a base class, perhaps pptx.chart.shared.BaseTitle. I suspect they + # actually differ in certain fuller behaviors, but at present they're + # essentially identical. + + def __init__(self, title): + super(ChartTitle, self).__init__(title) + self._title = title + + @lazyproperty + def format(self): + """|ChartFormat| object providing access to line and fill formatting. + + Return the |ChartFormat| object providing shape formatting properties + for this chart title, such as its line color and fill. + """ + return ChartFormat(self._title) + + @property + def has_text_frame(self): + """Read/write Boolean specifying whether this title has a text frame. + + Return |True| if this chart title has a text frame, and |False| + otherwise. Assigning |True| causes a text frame to be added if not + already present. Assigning |False| causes any existing text frame to + be removed along with its text and formatting. + """ + if self._title.tx_rich is None: + return False + return True + + @has_text_frame.setter + def has_text_frame(self, value): + if bool(value) is False: + self._title._remove_tx() + return + self._title.get_or_add_tx_rich() + + @property + def text_frame(self): + """|TextFrame| instance for this chart title. + + Return a |TextFrame| instance allowing read/write access to the text + of this chart title and its text formatting properties. Accessing this + property is destructive in the sense it adds a text frame if one is + not present. Use :attr:`has_text_frame` to test for the presence of + a text frame non-destructively. + """ + rich = self._title.get_or_add_tx_rich() + return TextFrame(rich, self) + + +class _Plots(Sequence): + """ + The sequence of plots in a chart, such as a bar plot or a line plot. Most + charts have only a single plot. The concept is necessary when two chart + types are displayed in a single set of axes, like a bar plot with + a superimposed line plot. + """ + + def __init__(self, plotArea, chart): + super(_Plots, self).__init__() + self._plotArea = plotArea + self._chart = chart + + def __getitem__(self, index): + xCharts = self._plotArea.xCharts + if isinstance(index, slice): + plots = [PlotFactory(xChart, self._chart) for xChart in xCharts] + return plots[index] + else: + xChart = xCharts[index] + return PlotFactory(xChart, self._chart) + + def __len__(self): + return len(self._plotArea.xCharts) |