from enum import Enum
from ppc_robot_lib.utils.types import Color
class HiddenDimensionOptions(Enum):
SHOW_ALL = 1
"""Show data from hidden columns and rows."""
SKIP_HIDDEN = 2
"""Skip data in hidden columns and rows."""
class StackType(Enum):
NOT_STACKED = 1
"""The chart is not stacked."""
STACKED = 2
"""Chart is stacked using raw values. Maximum for each X value is determined by sum of values in each series."""
STACKED_PERCENT = 3
"""Chart is stacked using normalized value. Maximum for each X value is always 100%."""
[docs]
class AxisPosition(Enum):
LEFT = 1
"""Left axis."""
RIGHT = 2
"""Right axis."""
[docs]
class LineType(Enum):
SOLID = 1
"""Solid line."""
DOTTED = 2
"""Dotted line."""
MEDIUM_DASHED = 3
"""Dashed line, medium dashes."""
LONG_DASHED = 4
"""Dashed line, long dashes."""
[docs]
class LineStyle:
def __init__(self, width: int, line_type: LineType = LineType.SOLID):
"""
:param width: Line width in pixels.
:param line_type: Line type.
"""
self.width = width
self.line_type = line_type
[docs]
class EmbeddedChart:
"""
Represents a chart that is embedded directly in the sheet.
A chart specification must be set. The used specification determines the type of chart that will be created.
"""
def __init__(self, spec: 'ChartSpec', width: int = 600, height: int = 400, data_sheet_id: int | None = None):
"""
:param spec: Chart type with parameters
:param width: Width in pixels.
:param height: Height in pixels.
:param data_sheet_id: ID of sheet with data that will be used for the graph.
"""
self.spec = spec
self.width = width
self.height = height
self.data_sheet_id = data_sheet_id
class AxisSpec:
"""
Axis description.
"""
def __init__(self, title: str):
"""
:param title: Axis label.
"""
self.title = title
class SeriesSpec:
def __init__(self, column: str, color: Color, line_style: LineStyle = None, axis: AxisPosition = AxisPosition.LEFT):
self.column = column
self.color = color
self.line_style = line_style if line_style is not None else LineStyle(2)
self.axis = axis
[docs]
class ChartSpec:
"""
Represents specification of a chart type. Do not use directly, but use any of the sub-classes:
* :py:class:`ppc_robot_lib.output.charts.LineChart`
"""
def __init__(
self,
title: str,
subtitle: str = '',
hidden_dimensions: HiddenDimensionOptions = HiddenDimensionOptions.SHOW_ALL,
):
self.title = title
self.subtitle = subtitle
self.hidden_dimensions = hidden_dimensions
[docs]
class LineChart(ChartSpec):
"""
Represents a line chart.
"""
def __init__(
self,
title: str,
subtitle: str,
domain_column: str,
bottom_axis_title: str = '',
left_axis_title: str = '',
right_axis_title: str | None = None,
hidden_dimensions: HiddenDimensionOptions = HiddenDimensionOptions.SHOW_ALL,
line_smoothing: bool = False,
stacked: StackType = StackType.NOT_STACKED,
use_column_headers: bool = True,
):
"""
:param title: Chart title.
:param subtitle: Chart subtitle.
:param domain_column: Name of the column that will be used as the label of the X axis.
:param bottom_axis_title: Description of the X axis.
:param left_axis_title: Description of the main Y axis on the left.
:param right_axis_title: Optional description of the secondary Y axis on the right. If not given, right Y axis
is not created.
:param hidden_dimensions: How to handle hidden columns and rows.
:param line_smoothing: Enable line-smoothing?
:param use_column_headers: Use column names as series labels?
"""
super().__init__(title, subtitle, hidden_dimensions)
self.domain_column = domain_column
self.bottom_axis = AxisSpec(bottom_axis_title)
self.left_axis = AxisSpec(left_axis_title)
self.right_axis = AxisSpec(right_axis_title) if right_axis_title is not None else None
self.series: list[SeriesSpec] = []
self.line_smoothing = line_smoothing
self.stacked = stacked
self.use_column_headers = use_column_headers
[docs]
def add_series(
self, column: str, color: Color, line_style: LineStyle = None, axis: AxisPosition = AxisPosition.LEFT
) -> 'LineChart':
"""
:param column: Name of the column that should be used as data for the series.
:param color: Line color.
:param line_style: Line style, if not given, solid line is used.
:param axis: What axis to use to plot the data.
"""
self.series.append(SeriesSpec(column, color, line_style, axis))
return self