Ability to save drawings
- Added `toolbox` to the common methods. - `toolbox.save_drawings_under` can save drawings under a specific `topbar` widget. eg `chart.toolbox.save_drawings_under(chart.topbar[’symbol’]`) - `toolbox.load_drawings` will load and display drawings stored under the tag/string given. - `toolbox.export_drawings` will export all currently saved drawings to the given file path. - `toolbox.import_drawings` will import the drawings stored at the given file path. Fixes/Enhancements: - `update` methods are no longer case sensitive. - HorizontalLines no longer throw cyclic structure errors in the web console. - `API` methods can now be normal methods or coroutines.
This commit is contained in:
@ -1,3 +1,4 @@
|
||||
import json
|
||||
import os
|
||||
from datetime import timedelta, datetime
|
||||
from base64 import b64decode
|
||||
@ -59,23 +60,35 @@ class SeriesCommon:
|
||||
}}
|
||||
''')
|
||||
|
||||
@staticmethod
|
||||
def _rename(data, mapper, is_dataframe):
|
||||
if is_dataframe:
|
||||
data.columns = [mapper[key] if key in mapper else key for key in data.columns]
|
||||
else:
|
||||
data.index = [mapper[key] if key in mapper else key for key in data.index]
|
||||
|
||||
def _df_datetime_format(self, df: pd.DataFrame, exclude_lowercase=None):
|
||||
df = df.copy()
|
||||
df.columns = df.columns.str.lower()
|
||||
if exclude_lowercase:
|
||||
df[exclude_lowercase] = df[exclude_lowercase.lower()]
|
||||
if 'date' not in df.columns and 'time' not in df.columns:
|
||||
df.columns = df.columns.str.lower()
|
||||
if exclude_lowercase:
|
||||
df[exclude_lowercase] = df[exclude_lowercase.lower()]
|
||||
if 'date' in df.columns:
|
||||
df = df.rename(columns={'date': 'time'})
|
||||
self._rename(df, {'date': 'time'}, True)
|
||||
elif 'time' not in df.columns:
|
||||
df['time'] = df.index
|
||||
self._set_interval(df)
|
||||
df['time'] = self._datetime_format(df['time'])
|
||||
return df
|
||||
|
||||
def _series_datetime_format(self, series):
|
||||
def _series_datetime_format(self, series: pd.Series, exclude_lowercase=None):
|
||||
series = series.copy()
|
||||
if 'date' in series.keys():
|
||||
series = series.rename({'date': 'time'})
|
||||
if 'date' not in series.index and 'time' not in series.index:
|
||||
series.index = series.index.str.lower()
|
||||
if exclude_lowercase:
|
||||
self._rename(series, {exclude_lowercase.lower(): exclude_lowercase}, False)
|
||||
if 'date' in series.index:
|
||||
self._rename(series, {'date': 'time'}, False)
|
||||
series['time'] = self._datetime_format(series['time'])
|
||||
return series
|
||||
|
||||
@ -353,6 +366,47 @@ class TopBar:
|
||||
return widget
|
||||
|
||||
|
||||
class ToolBox:
|
||||
def __init__(self, chart):
|
||||
self.run_script = chart.run_script
|
||||
self.id = chart.id
|
||||
self._return_q = chart._return_q
|
||||
|
||||
self._saved_drawings = {}
|
||||
|
||||
def save_drawings_under(self, widget: Widget):
|
||||
"""
|
||||
Drawings made on charts will be saved under the widget given. eg `chart.toolbox.save_drawings_under(chart.topbar['symbol'])`.
|
||||
"""
|
||||
self._save_under = widget
|
||||
|
||||
def load_drawings(self, tag: str):
|
||||
"""
|
||||
Loads and displays the drawings on the chart stored under the tag given.
|
||||
"""
|
||||
if not self._saved_drawings.get(tag):
|
||||
return
|
||||
self.run_script(f'if ("toolBox" in {self.id}) {self.id}.toolBox.loadDrawings({json.dumps(self._saved_drawings[tag])})')
|
||||
|
||||
def import_drawings(self, file_path):
|
||||
"""
|
||||
Imports a list of drawings stored at the given file path.
|
||||
"""
|
||||
with open(file_path, 'r') as f:
|
||||
json_data = json.load(f)
|
||||
self._saved_drawings = json_data
|
||||
|
||||
def export_drawings(self, file_path):
|
||||
"""
|
||||
Exports the current list of drawings to the given file path.
|
||||
"""
|
||||
with open(file_path, 'w+') as f:
|
||||
json.dump(self._saved_drawings, f)
|
||||
|
||||
def _save_drawings(self, drawings):
|
||||
self._saved_drawings[self._save_under.value] = json.loads(drawings)
|
||||
|
||||
|
||||
class LWC(SeriesCommon):
|
||||
def __init__(self, volume_enabled: bool = True, inner_width: float = 1.0, inner_height: float = 1.0, dynamic_loading: bool = False,
|
||||
scale_candles_only: bool = False, topbar: bool = False, searchbox: bool = False, toolbox: bool = False,
|
||||
@ -394,6 +448,7 @@ class LWC(SeriesCommon):
|
||||
if toolbox:
|
||||
self.run_script(JS['toolbox'])
|
||||
self.run_script(f'{self.id}.toolBox = new ToolBox({self.id})')
|
||||
self.toolbox: ToolBox = ToolBox(self)
|
||||
if not topbar and not searchbox:
|
||||
return
|
||||
self.run_script(JS['callback'])
|
||||
|
||||
Reference in New Issue
Block a user