diff --git a/docs/source/examples/screenshot.md b/docs/source/examples/screenshot.md new file mode 100644 index 0000000..6fcb4a9 --- /dev/null +++ b/docs/source/examples/screenshot.md @@ -0,0 +1,27 @@ +# Screenshot & Save + + +```python +import pandas as pd +from lightweight_charts import Chart + + +if __name__ == '__main__': + chart = Chart() + df = pd.read_csv('ohlcv.csv') + chart.set(df) + chart.show() + + img = chart.screenshot() + with open('screenshot.png', 'wb') as f: + f.write(img) +``` + +```{important} +The `screenshot` command can only be executed after the chart window is open. Therefore, either `block` must equal `False`, the screenshot should be triggered with a callback, or `async_show` should be used. +``` + +```{important} +This example can only be used with the standard `Chart` object. +``` + diff --git a/docs/source/index.md b/docs/source/index.md index 0ccc926..5e616c1 100644 --- a/docs/source/index.md +++ b/docs/source/index.md @@ -17,6 +17,7 @@ examples/toolbox examples/subchart examples/yfinance examples/events +examples/screenshot examples/gui_examples ``` diff --git a/docs/source/reference/abstract_chart.md b/docs/source/reference/abstract_chart.md index 069c869..a7099eb 100644 --- a/docs/source/reference/abstract_chart.md +++ b/docs/source/reference/abstract_chart.md @@ -364,6 +364,10 @@ Charts are arranged horizontally from left to right. When the available space is [Subchart examples](../examples/subchart.md) +```{important} +Price axis scales vary depending on the precision of the data used, and there is no way to perfectly 'align' two seperate price scales if they contain differing price data. +``` + ```` ````` diff --git a/lightweight_charts/abstract.py b/lightweight_charts/abstract.py index 88f59e4..9af92e6 100644 --- a/lightweight_charts/abstract.py +++ b/lightweight_charts/abstract.py @@ -85,15 +85,17 @@ class Window: return self.scripts.append(script) if not run_last else self.final_scripts.append(script) - def create_table(self, width: NUM, height: NUM, headings: tuple, widths: tuple = None, - alignments: tuple = None, position: FLOAT = 'left', draggable: bool = False, - background_color: str = '#121417', border_color: str = 'rgb(70, 70, 70)', - border_width: int = 1, heading_text_colors: tuple = None, - heading_background_colors: tuple = None, func: callable = None - ) -> 'Table': + def create_table( + self, width: NUM, height: NUM, headings: tuple, widths: tuple = None, + alignments: tuple = None, position: FLOAT = 'left', draggable: bool = False, + background_color: str = '#121417', border_color: str = 'rgb(70, 70, 70)', + border_width: int = 1, heading_text_colors: tuple = None, + heading_background_colors: tuple = None, return_clicked_cells: bool = False, + func: callable = None + ) -> 'Table': return Table(self, width, height, headings, widths, alignments, position, draggable, background_color, border_color, border_width, heading_text_colors, - heading_background_colors, func) + heading_background_colors, return_clicked_cells, func) def create_subchart(self, position: FLOAT = 'left', width: float = 0.5, height: float = 0.5, sync_id: str = None, scale_candles_only: bool = False, toolbox: bool = False @@ -916,14 +918,16 @@ class AbstractChart(Candlestick, Pane): self.win.handlers[f'{modifier_key, keys}'] = func def create_table( - self, width: NUM, height: NUM, headings: tuple, widths: tuple = None, alignments: tuple = None, - position: FLOAT = 'left', draggable: bool = False, background_color: str = '#121417', - border_color: str = 'rgb(70, 70, 70)', border_width: int = 1, heading_text_colors: tuple = None, - heading_background_colors: tuple = None, func: callable = None - ) -> Table: + self, width: NUM, height: NUM, headings: tuple, widths: tuple = None, + alignments: tuple = None, position: FLOAT = 'left', draggable: bool = False, + background_color: str = '#121417', border_color: str = 'rgb(70, 70, 70)', + border_width: int = 1, heading_text_colors: tuple = None, + heading_background_colors: tuple = None, return_clicked_cells: bool = False, + func: callable = None + ) -> Table: return self.win.create_table(width, height, headings, widths, alignments, position, draggable, background_color, border_color, border_width, heading_text_colors, - heading_background_colors, func) + heading_background_colors, return_clicked_cells, func) def screenshot(self) -> bytes: """ diff --git a/lightweight_charts/js/table.js b/lightweight_charts/js/table.js index ab6ceda..6ae05fb 100644 --- a/lightweight_charts/js/table.js +++ b/lightweight_charts/js/table.js @@ -91,23 +91,35 @@ if (!window.Table) { } - newRow(id) { - let row = this.table.insertRow() - row.style.cursor = 'default' - - for (let i = 0; i < this.headings.length; i++) { - row[this.headings[i]] = row.insertCell() - row[this.headings[i]].style.width = this.widths[i]; - row[this.headings[i]].style.textAlign = this.alignments[i]; - row[this.headings[i]].style.border = this.borderWidth+'px solid '+this.borderColor + addRowEventListener(row, id, isCell= false) { + if (isCell) { + id = `${id};;;${isCell}` } row.addEventListener('mouseover', () => row.style.backgroundColor = 'rgba(60, 60, 60, 0.6)') row.addEventListener('mouseout', () => row.style.backgroundColor = 'transparent') row.addEventListener('mousedown', () => row.style.backgroundColor = 'rgba(60, 60, 60)') - row.addEventListener('click', () => window.callbackFunction(`${this.callbackName}_~_${id}`)) row.addEventListener('mouseup', () => row.style.backgroundColor = 'rgba(60, 60, 60, 0.6)') + } + newRow(id, returnClickedCell=false) { + let row = this.table.insertRow() + row.style.cursor = 'default' + + for (let i = 0; i < this.headings.length; i++) { + let cell = row.insertCell() + cell.style.width = this.widths[i]; + cell.style.textAlign = this.alignments[i]; + cell.style.border = this.borderWidth+'px solid '+this.borderColor + + if (returnClickedCell) { + this.addRowEventListener(cell, id, this.headings[i]) + } + row[this.headings[i]] = cell + } + if (!returnClickedCell) { + this.addRowEventListener(row, id, false) + } this.rows[id] = row } diff --git a/lightweight_charts/table.py b/lightweight_charts/table.py index 54973e5..fd08042 100644 --- a/lightweight_charts/table.py +++ b/lightweight_charts/table.py @@ -23,7 +23,7 @@ class Row(dict): self._table = table self.id = id self.meta = {} - self.run_script(f'{self._table.id}.newRow("{self.id}")') + self.run_script(f'{self._table.id}.newRow("{self.id}", {jbool(table.return_clicked_cells)})') for key, val in items.items(): self[key] = val @@ -56,14 +56,20 @@ class Table(Pane, dict): alignments: tuple = None, position='left', draggable: bool = False, background_color: str = '#121417', border_color: str = 'rgb(70, 70, 70)', border_width: int = 1, heading_text_colors: tuple = None, - heading_background_colors: tuple = None, func: callable = None + heading_background_colors: tuple = None, return_clicked_cells: bool = False, + func: callable = None ): dict.__init__(self) Pane.__init__(self, window) self._formatters = {} self.headings = headings self.is_shown = True - self.win.handlers[self.id] = lambda rId: func(self[rId]) + if return_clicked_cells: + self.win.handlers[self.id] = lambda rId, cId: func(self[rId], cId) + else: + self.win.handlers[self.id] = lambda rId: func(self[rId]) + self.return_clicked_cells = return_clicked_cells + headings = list(headings) widths = list(widths) if widths else [] alignments = list(alignments) if alignments else []