| """Chart and style helpers for Plotly.""" |
|
|
| |
| import json |
| from pathlib import Path |
| from typing import Any, Dict, List, Optional |
|
|
| from rich.console import Console |
|
|
| from openbb_cli.config.constants import STYLES_DIRECTORY |
|
|
| console = Console() |
|
|
|
|
| class Style: |
| """The class that helps with handling of style configurations. |
| |
| It serves styles for 2 libraries. For `Plotly` this class serves absolute paths |
| to the .pltstyle files. For `Plotly` and `Rich` this class serves custom |
| styles as python dictionaries. |
| """ |
|
|
| STYLES_REPO = STYLES_DIRECTORY |
|
|
| console_styles_available: Dict[str, Path] = {} |
| console_style: Dict[str, Any] = {} |
|
|
| line_color: str = "" |
| up_color: str = "" |
| down_color: str = "" |
| up_colorway: List[str] = [] |
| down_colorway: List[str] = [] |
| up_color_transparent: str = "" |
| down_color_transparent: str = "" |
|
|
| line_width: float = 1.5 |
|
|
| def __init__( |
| self, |
| style: Optional[str] = "", |
| directory: Optional[Path] = None, |
| ): |
| """Initialize the class.""" |
| self._load(directory) |
| self.apply(style, directory) |
|
|
| def apply( |
| self, style: Optional[str] = None, directory: Optional[Path] = None |
| ) -> None: |
| """Apply the style to the console.""" |
| if style: |
| if style in self.console_styles_available: |
| json_path: Optional[Path] = self.console_styles_available[style] |
| else: |
| self._load(directory) |
| if style in self.console_styles_available: |
| json_path = self.console_styles_available[style] |
| else: |
| console.print(f"\nInvalid console style '{style}', using default.") |
| json_path = self.console_styles_available.get("dark", None) |
|
|
| if json_path: |
| self.console_style = self._from_json(json_path) |
| else: |
| console.print("Error loading default.") |
|
|
| def _from_directory(self, folder: Optional[Path]) -> None: |
| """Load custom styles from folder. |
| |
| Parses the styles/default and styles/user folders and loads style files. |
| To be recognized files need to follow a naming convention: |
| *.pltstyle - plotly stylesheets |
| *.richstyle.json - rich stylesheets |
| |
| Parameters |
| ---------- |
| folder : str |
| Path to the folder containing the stylesheets |
| """ |
| if not folder or not folder.exists(): |
| return |
|
|
| for attr, ext in zip( |
| ["console_styles_available"], |
| [".richstyle.json"], |
| ): |
| for file in folder.rglob(f"*{ext}"): |
| getattr(self, attr)[file.name.replace(ext, "")] = file |
|
|
| def _load(self, directory: Optional[Path] = None) -> None: |
| """Load custom styles from default and user folders.""" |
| self._from_directory(self.STYLES_REPO) |
| self._from_directory(directory) |
|
|
| def _from_json(self, file: Path) -> Dict[str, Any]: |
| """Load style from json file.""" |
| with open(file) as f: |
| json_style: dict = json.load(f) |
| for key, value in json_style.items(): |
| json_style[key] = value.replace( |
| " ", "" |
| ) |
| return json_style |
|
|
| @property |
| def available_styles(self) -> List[str]: |
| """Return available styles.""" |
| return list(self.console_styles_available.keys()) |
|
|