Source code for kappa_sdk.plot_channel

from typing import Union, List, Tuple, Optional
from .vector import Vector
from .data import Data
from .datetime_utils import datetime_to_str
from ._private._well_dto import EmbeddedChannelDto, TimeSeriesReferenceChannelDto, ChannelAspectDto, ChannelType, DoubleValuesDto, TimeValuesDto, CrossReferenceChannelDto
from .plots_enum import PlotDataTypesEnum, SymbolAspectEnum, LineAspectEnum, PlotProperties, DrawingStyle
from .measure_enum import MeasureEnum
from .field_data_types_catalog import FieldDataTypesCatalog
from pydantic import ValidationError


[docs] class PlotChannel: """ Build a PlotChannel dto for the :class:`Plot` object. .. note:: Should not be instantiated directly. """ def __init__(self, field_id: str, data_types_catalog: FieldDataTypesCatalog, pane_name: Optional[str] = None): self.__field_id: str = field_id self.__data_types_catalog: FieldDataTypesCatalog = data_types_catalog self.__dto: Optional[Union[EmbeddedChannelDto, TimeSeriesReferenceChannelDto, CrossReferenceChannelDto]] = None self.__pane_name: Optional[str] = pane_name def build_time_series(self, well_id: str, data: Data, properties: Optional[PlotProperties] = None) -> None: """ Build plot channel from a time series Parameters ---------- well_id: Id of the well data: :class:`Data` object to be plotted properties: Properties of the channel """ if properties is None: properties = PlotProperties() aspect_dto = self.__build_aspect_dto(properties, data.data_type) is_y_log = properties.is_y_log hide_in_legend = properties.hide_in_legend is_raw = properties.is_raw self.__dto = TimeSeriesReferenceChannelDto(type=ChannelType.TimeSeriesReference, xyVectorId=data.vector_id, isRaw=is_raw, aspect=aspect_dto, name=data.name, isYLog=is_y_log, wellId=well_id, hideInLegend=hide_in_legend) def build_embedded(self, well_id: str, data: Union[Vector, Tuple[List[float], List[float]]], data_type: Optional[Union[PlotDataTypesEnum, str]] = None, properties: Optional[PlotProperties] = None) -> None: """ Build plot channel from embedded data Parameters ---------- well_id: Id of the well data: Data to build the channel could be either a Vector or a Tuple of lists data_type: Data type of the data properties: Properties of the channel """ if properties is None: properties = PlotProperties() if properties.y_measure is None: y_measure = MeasureEnum.no_unit else: y_measure = properties.y_measure x_values: Union[DoubleValuesDto, TimeValuesDto] y_values: DoubleValuesDto if type(data) is tuple: if len(data[0]) != len(data[1]): raise ValueError("X inputs and Y inputs have different lengths") if properties.x_measure is None: x_measure = MeasureEnum.no_unit else: x_measure = properties.x_measure try: x_values = DoubleValuesDto.model_validate({"type": "Double", "values": data[0], "dimension": str(x_measure.value)}) except ValidationError: raise ValueError("X inputs are not of type Double. If you are trying to use datetime objects as X values you must create and use a Vector object as data input instead") y_values = DoubleValuesDto.model_validate({"type": "Double", "values": data[1], "dimension": str(y_measure.value)}) if isinstance(data, Vector): if properties.use_elapsed: x_values = DoubleValuesDto.model_validate({"type": "Double", "values": data.elapsed_times, "dimension": "Time"}) else: x_values = TimeValuesDto.model_validate({"type": "Time", "values": [datetime_to_str(dt) for dt in data.dates]}) y_values = DoubleValuesDto.model_validate({"type": "Double", "values": data.values, "dimension": str(y_measure.value)}) aspect_dto = self.__build_aspect_dto(properties, data_type) name = properties.channel_name if name is None: name = "Channel #1" is_y_log = properties.is_y_log is_by_step = properties.is_by_step first_x = properties.first_x hide_in_legend = properties.hide_in_legend self.__dto = EmbeddedChannelDto(type=ChannelType.Embedded, aspect=aspect_dto, name=name, isYLog=is_y_log, xValues=x_values, yValues=y_values, isByStep=is_by_step, firstX=first_x, hideInLegend=hide_in_legend, wellId=well_id) def build_cross_plot_channel(self, well_id: str, x_vector_id: str, y_vector_id: str, data_type: Optional[Union[PlotDataTypesEnum, str]] = None, properties: Optional[PlotProperties] = None) -> None: """ Build plot channel from embedded data Parameters ---------- well_id: Id of the well data: Data to build the channel could be either a Vector or a Tuple of lists data_type: Data type of the data properties: Properties of the channel """ if properties is None: properties = PlotProperties() name = properties.channel_name if name is None: name = "Channel #1" aspect_dto = self.__build_aspect_dto(properties, data_type) self.__dto = CrossReferenceChannelDto(type=ChannelType.CrossReference, aspect=aspect_dto, name=name, isYLog=properties.is_y_log, xVectorId=x_vector_id, yVectorId=y_vector_id, hideInLegend=properties.hide_in_legend, wellId=well_id) def __build_aspect_dto(self, properties: PlotProperties, data_type: Optional[Union[str, PlotDataTypesEnum]]) -> ChannelAspectDto: aspect_dto = self.__get_default_aspect(data_type) is_by_step = properties.is_by_step show_symbols = properties.show_symbols if data_type == PlotDataTypesEnum.shutin or data_type == PlotDataTypesEnum.shutin.value: aspect_dto.drawingStyle = DrawingStyle.as_vertical_line show_symbols = False if aspect_dto.band is not None: aspect_dto.band.opacity = 80 if (is_by_step and show_symbols is None) or show_symbols is False: aspect_dto.symbol = None if not properties.show_lines: aspect_dto.line = None return aspect_dto.__deepcopy__() def __get_default_aspect(self, data_type: Optional[Union[str, PlotDataTypesEnum]]) -> ChannelAspectDto: if data_type is None: data_type = PlotDataTypesEnum.oil_rate_surface.value if type(data_type) is PlotDataTypesEnum: data_type = data_type.value for data_types in self.__data_types_catalog: if data_types.alias == data_type or data_types.name == data_type: channnel_aspect_dto = data_types.channel_aspect_dto if channnel_aspect_dto is None: raise ValueError("Missing Aspect dto for channel {}".format(data_types.name)) return channnel_aspect_dto.__deepcopy__() else: raise ValueError("This data type does not exist") def set_lines_aspect(self, color: Optional[str] = None, width: Optional[int] = None, style: Optional[LineAspectEnum] = None) -> None: """ Set up the line's aspect of the :class:`ChannelsModel` Parameters ---------- color: Line color width: Line width style: Line style """ if self.__dto is not None and self.__dto.aspect.line is not None: if color is not None: self.__dto.aspect.line.color = color if width is not None: self.__dto.aspect.line.width = width if style is not None: self.__dto.aspect.line.style = style if self.__dto.aspect.line is None: raise KeyError("Show line is set up at False, you cannot change lines properties") else: raise KeyError("The dto is empty, call the build_embedded or build_time_series method before changing properties") def set_band_aspect(self, color: Optional[str] = None, opacity: Optional[int] = None) -> None: """ Set up the band's aspect of the :class:`ChannelsModel` Parameters ---------- color: Band color opacity: Band opacity between 0 and 100 """ if self.__dto is not None and self.__dto.aspect.band is not None: if color is not None: self.__dto.aspect.band.color = color if opacity is not None: self.__dto.aspect.band.opacity = opacity else: raise KeyError("The dto is empty, call the build_embedded or the build_time_series method before changing properties") def set_symbols_aspect(self, color: Optional[str] = None, size: Optional[int] = None, filled: Optional[bool] = None, symbol_type: Optional[SymbolAspectEnum] = None) -> None: """ Set up the symbols' aspect of the :class:`ChannelsModel` Parameters ---------- color: Symbols' color size: Symbols' size filled: Symbols' filled symbol_type: Symbol's type """ if self.__dto is not None and self.__dto.aspect.symbol is not None: if color is not None: self.__dto.aspect.symbol.color = color if size is not None: self.__dto.aspect.symbol.size = size if filled is not None: self.__dto.aspect.symbol.filled = filled if symbol_type is not None: self.__dto.aspect.symbol.type = symbol_type if self.__dto.aspect.symbol is None: raise KeyError("Show symbols is set up at False, you cannot change symbols properties") else: raise KeyError("The dto is empty, call the build_dto method before changing properties") def set_channel_aspect(self, drawing_style: Optional[DrawingStyle] = None, is_y_log: Optional[bool] = None, hide_in_legend: Optional[bool] = None, is_raw: Optional[bool] = None) -> None: """ Set up some aspect of the :class:`ChannelsModel` Parameters ---------- drawing_style is_y_log hide_in_legend is_raw """ if self.__dto is not None: if drawing_style is not None: self.__dto.aspect.drawingStyle = drawing_style if is_y_log is not None: self.__dto.isYLog = is_y_log if hide_in_legend is not None: self.__dto.hideInLegend = hide_in_legend if is_raw is not None: if type(self.__dto) is not TimeSeriesReferenceChannelDto: raise ValueError("The dto is not a time series") else: self.__dto.isRaw = is_raw else: raise KeyError("The dto is empty, call the build_dto method before changing properties") @property def pane_name(self) -> Optional[str]: """ Get associated pane name of the :class: PlotChannel """ return self.__pane_name @property def dto(self) -> Optional[Union[EmbeddedChannelDto, TimeSeriesReferenceChannelDto, CrossReferenceChannelDto]]: """ Get associated dto of the :class: PlotChannel """ return self.__dto