diff options
author | zeph <zeph.chai@ymail.com> | 2024-02-05 20:03:14 -0800 |
---|---|---|
committer | Hossein <hossein@libreoffice.org> | 2024-02-27 23:41:18 +0100 |
commit | 7c78d2b29e04228481c0e4bfa9e3eaf6ccbd575b (patch) | |
tree | 7a023050c0bacaab7f72c39411d6fba146a20ba2 /odk/examples/DevelopersGuide/Charts/python | |
parent | 487ce28057656e752dc9bb7eddea5befb446ad0a (diff) |
Add python code for ChartInCalc
Change-Id: Ia7f4cbd539919e88f735c13bdd1dae3533b1163a
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/163037
Tested-by: Jenkins
Reviewed-by: Hossein <hossein@libreoffice.org>
Diffstat (limited to 'odk/examples/DevelopersGuide/Charts/python')
-rw-r--r-- | odk/examples/DevelopersGuide/Charts/python/CalcHelper.py | 189 | ||||
-rw-r--r-- | odk/examples/DevelopersGuide/Charts/python/ChartInCalc.py | 225 | ||||
-rw-r--r-- | odk/examples/DevelopersGuide/Charts/python/Helper.py | 44 | ||||
-rw-r--r-- | odk/examples/DevelopersGuide/Charts/python/bullet.gif | bin | 0 -> 335 bytes |
4 files changed, 458 insertions, 0 deletions
diff --git a/odk/examples/DevelopersGuide/Charts/python/CalcHelper.py b/odk/examples/DevelopersGuide/Charts/python/CalcHelper.py new file mode 100644 index 000000000000..dcbb0b8e8740 --- /dev/null +++ b/odk/examples/DevelopersGuide/Charts/python/CalcHelper.py @@ -0,0 +1,189 @@ +import math +import random +import sys +import traceback + +from com.sun.star.awt import Rectangle +from com.sun.star.container import NoSuchElementException + + +class CalcHelper: + + _data_sheet_name = "Data" + _chart_sheet_name = "Chart" + + def __init__(self, doc): + self.spread_sheet_doc = doc + self._init_spread_sheet() + + def get_chart_sheet(self): + sheets = self.spread_sheet_doc.Sheets + try: + sheet = sheets.getByName(self._chart_sheet_name) + except NoSuchElementException as err: + print(f"Couldn't find sheet with name {self._chart_sheet_name}: {err}") + traceback.print_exc() + except Exception as err: + print(err) + traceback.print_exc() + return sheet + + def get_data_sheet(self): + sheets = self.spread_sheet_doc.Sheets + try: + sheet = sheets.getByName(self._data_sheet_name) + except NoSuchElementException as err: + print(f"Couldn't find sheet with name {self._data_sheet_name}: {err}") + traceback.print_exc() + except Exception as err: + print(err) + traceback.print_exc() + return sheet + + def insert_chart(self, chart_name, range_, upper_left, extent, chart_service_name): + """Insert a chart using the given name as name of the OLE object and the range as corresponding + range of data to be used for rendering. The chart is placed in the sheet for charts at + position upper_left extending as large as given in extent. + + The service name must be the name of a diagram service that can be instantiated via the + factory of the chart document + + Args: + chart_name (str): _description_ + range_ (com.sun.star.table.CellRangeAddress): _description_ + upper_left (Point): _description_ + extent (Size): _description_ + chart_service_name (str): _description_ + """ + result = None + try: + sheet = self.get_chart_sheet() + except Exception as err: + print(f"Sheet not found {err}") + traceback.print_exc() + return + + chart_collection = sheet.getCharts() + + if not chart_collection.hasByName(chart_name): + rect = Rectangle(upper_left.X, upper_left.Y, extent.Width, extent.Height) + addresses = [] + addresses.append(range_) + + # first bool: ColumnHeaders + # second bool: RowHeaders + chart_collection.addNewByName(chart_name, rect, addresses, True, False) + + try: + table_chart = chart_collection.getByName(chart_name) + + # the table chart is an embedded object which contains the chart document + result = table_chart.getEmbeddedObject() + + # create a diagram via the factory and set this as new diagram + result.setDiagram(result.createInstance(chart_service_name)) + + except NoSuchElementException as err: + print(f"Couldn't find chart with name {chart_name}: {err}") + traceback.print_exc() + return + + except Exception as err: + print(err) + traceback.print_exc() + return + + return result + + def insert_random_range(self, column_count, row_count): + """Fill a rectangular range with random numbers. + The first column has increasing values + + Args: + column_count (int): _description_ + row_count (int): _description_ + + Return: + (com.sun.star.table.XCellRange) + """ + cell_range = None + try: + # get the sheet to insert the chart + sheet = self.get_data_sheet() + cell_range = sheet[0:row_count, 0:column_count] + + base = 0.0 + float_range = 10.0 + + for col in range(column_count): + if col == 0: + sheet[0, col].Formula = "X" + else: + sheet[0, col].Formula = f"Random {col}" + + for row in range(1, row_count): + if col == 0: + value = row + random.random() + else: + value = base + random.gauss(0.0, 1.0) * float_range + + # put value into cell + sheet[row, col].Value = value + + except Exception as err: + print(f"Sheet not found {err}") + traceback.print_exc() + + return cell_range + + def insert_formula_range(self, column_count, row_count): + try: + # get the sheet to insert the chart + sheet = self.get_data_sheet() + cell_range = sheet[0 : row_count - 1, 0 : column_count - 1] + factor = 2.0 * math.pi / (row_count - 1) + + factor_col = column_count = 2 + sheet[0, factor_col - 1].Value = 0.2 + sheet[1, factor_col - 1].String = "Change the factor above and\nwatch the changes in the chart" + + for col in range(column_count): + for row in range(row_count): + if col == 0: + # x values: ascending numbers + value = row * factor + sheet[row, col].Value = value + else: + formula = "=" + if col % 2 == 0: + formula += "SIN" + else: + formula += "COS" + + formula += f"(INDIRECT(ADDRESS({row + 1};1)))+RAND()*INDIRECT(ADDRESS(1;{factor_col}))" + sheet[row, col].Formula = formula + + except Exception as err: + print(f"Sheet not found {err}") + traceback.print_exc() + + return cell_range + + def raise_chart_sheet(self): + """Bring the sheet containing charts visually to the foreground""" + self.spread_sheet_doc.getCurrentController().setActiveSheet(self.get_chart_sheet()) + + def _init_spread_sheet(self): + """create two sheets, one for data and one for charts in the document""" + if self.spread_sheet_doc is not None: + sheets = self.spread_sheet_doc.Sheets + if sheets: + for i in range(len(sheets) - 1, 0, -1): + sheets.removeByName(sheets.getByIndex(i).getName()) + try: + first_sheet = sheets[0] + first_sheet.setName(self._data_sheet_name) + sheets.insertNewByName(self._chart_sheet_name, 1) + except Exception as e: + print(f"Couldn't initialize Spreadsheet Document: {e}", file=sys.stderr) + traceback.print_exc() diff --git a/odk/examples/DevelopersGuide/Charts/python/ChartInCalc.py b/odk/examples/DevelopersGuide/Charts/python/ChartInCalc.py new file mode 100644 index 000000000000..787cc2274020 --- /dev/null +++ b/odk/examples/DevelopersGuide/Charts/python/ChartInCalc.py @@ -0,0 +1,225 @@ +# -*- tab-width: 4; indent-tabs-mode: nil; py-indent-offset: 4 -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +import os + +import Helper +import CalcHelper + +from com.sun.star.awt import FontWeight, Point, Size +from com.sun.star.chart import ChartSymbolType, ChartDataCaption +from com.sun.star.drawing import LineDash +from com.sun.star.drawing.DashStyle import ROUND +from com.sun.star.drawing.FillStyle import SOLID +from com.sun.star.drawing.LineStyle import DASH +from com.sun.star.lang import IndexOutOfBoundsException, Locale + + +class ChartInCalc(object): + def __init__(self, chart_doc): + super(ChartInCalc, self).__init__() + self._chart_document = chart_doc + self._diagram = self._chart_document.getDiagram() + + def lock_controllers(self): + self._chart_document.lockControllers() + + def unlock_controllers(self): + self._chart_document.unlockControllers() + + def test_diagram(self): + dia_prop = self._diagram + + if dia_prop is not None: + # change chart type + dia_prop.setPropertyValue("Lines", True) + # change attributes for all series + # set line width to 0.5mm + dia_prop.setPropertyValue("LineWidth", 50) + + def test_data_row_properties(self): + # change properties of the data series + try: + for i in range(4): + series_prop = self._diagram.getDataRowProperties(i) + series_prop.setPropertyValue("LineColor", int(0x400000 * i + 0x005000 * i + 0x0000FF - 0x40 * i)) + + if i == 1: + source_file = "bullet.gif" + url = os.path.abspath(source_file).replace("\\", "/") + + if os.path.exists(url): + url = "file:///" + url + else: + url = "http://graphics.openoffice.org/chart/bullet1.gif" + + series_prop.setPropertyValue("SymbolType", int(ChartSymbolType.BITMAPURL)) + series_prop.setPropertyValue("SymbolBitmapURL", url) + else: + series_prop.setPropertyValue("SymbolType", int(ChartSymbolType.SYMBOL1)) + series_prop.setPropertyValue("SymbolSize", Size(250, 250)) + + except IndexOutOfBoundsException as err: + print(f"Oops, there not enough series for setting properties: {err}") + + def test_data_point_properties(self): + # set properties for a single data point + try: + # determine the maximum value of the first series + data_array = self._chart_document.getData() + data = data_array.getData() + max_value = max([data[i][1] for i in range(len(data))]) + + # first parameter is the index of the point, the second one is the series + point_prop = self._diagram.getDataPointProperties(0, 1) + + # set a different, larger symbol + point_prop.setPropertyValue("SymbolType", int(ChartSymbolType.SYMBOL6)) + point_prop.setPropertyValue("SymbolSize", Size(600, 600)) + + # add a label text with bold font, bordeaux red 14pt + point_prop.setPropertyValue("DataCaption", int(ChartDataCaption.VALUE)) + point_prop.setPropertyValue("CharHeight", 14.0) + point_prop.setPropertyValue("CharColor", int(0x993366)) + point_prop.setPropertyValue("CharWeight", FontWeight.BOLD) + + except IndexOutOfBoundsException as err: + print(f"Oops, there not enough series for setting properties: {err}") + + def test_area(self): + area = self._chart_document.getArea() + if area is not None: + # change background color of entire chart + area.setPropertyValue("FillStyle", SOLID) + area.setPropertyValue("FillColor", int(0xEEEEEE)) + + def test_wall(self): + wall = self._diagram.getWall() + + # change background color of area + wall.setPropertyValue("FillStyle", SOLID) + wall.setPropertyValue("FillColor", int(0xCCCCCC)) + + def test_title(self): + # change main title + doc_prop = self._chart_document + doc_prop.setPropertyValue("HasMainTitle", True) + + title = self._chart_document.getTitle() + + # set new text + if title is not None: + title.setPropertyValue("String", "Random Scatter Chart") + title.setPropertyValue("CharHeight", 14.0) + + # align title with y axis + axis = self._diagram.getYAxis() + + if axis is not None and title is not None: + pos = title.getPosition() + pos.X = axis.getPosition().X + title.setPosition(pos) + + def test_axis(self): + # x axis + axis = self._diagram.getXAxis() + + if axis is not None: + axis.setPropertyValue("Max", 24) + axis.setPropertyValue("StepMain", 3) + + # change number format for y axis + axis = self._diagram.getYAxis() + + # add a new custom number format and get the new key + new_number_format = 0 + num_fmt_supp = self._chart_document + + if num_fmt_supp is not None: + formats = num_fmt_supp.getNumberFormats() + locale = Locale("de", "DE", "de") + + format_str = formats.generateFormat(new_number_format, locale, True, True, 3, 1) + new_number_format = formats.addNew(format_str, locale) + + if axis is not None: + axis.setPropertyValue("NumberFormat", int(new_number_format)) + + def test_grid(self): + # y major grid + grid = self._diagram.getYMainGrid() + + if grid is not None: + dash = LineDash() + dash.Style = ROUND + dash.Dots = 2 + dash.DotLen = 10 + dash.Dashes = 1 + dash.DashLen = 200 + dash.Distance = 100 + + grid.setPropertyValue("LineColor", int(0x999999)) + grid.setPropertyValue("LineStyle", DASH) + grid.setPropertyValue("LineDash", dash) + grid.setPropertyValue("LineWidth", 30) + + +def main(): + # Create a spreadsheet add some data and add a chart + helper = Helper.Helper() + + calc_helper = CalcHelper.CalcHelper(helper.create_spreadsheet_document()) + + # insert a cell range with 4 columns and 24 rows filled with random numbers + cell_range = calc_helper.insert_random_range(4, 24) + range_address = cell_range.RangeAddress + + # change view to sheet containing the chart + calc_helper.raise_chart_sheet() + + # the unit for measures is 1/100th of a millimeter + # position at (1cm, 1cm) + pos = Point(1000, 1000) + + # size of the chart is 15cm x 9.271cm + extent = Size(15000, 9271) + + # insert a new chart into the "Chart" sheet of the spreadsheet document + chart_doc = calc_helper.insert_chart("ScatterChart", range_address, pos, extent, "com.sun.star.chart.XYDiagram") + + test = ChartInCalc(chart_doc) + + try: + test.lock_controllers() + + test.test_diagram() + test.test_area() + test.test_wall() + test.test_title() + test.test_axis() + test.test_grid() + + # show an intermediate state, ... + test.unlock_controllers() + test.lock_controllers() + + # ..., because the following takes a while: + # an internet URL has to be resolved + test.test_data_row_properties() + test.test_data_point_properties() + + test.unlock_controllers() + + except Exception as err: + print(f"UNO Exception caught: {err}") + + +# Main entry point +if __name__ == "__main__": + main() diff --git a/odk/examples/DevelopersGuide/Charts/python/Helper.py b/odk/examples/DevelopersGuide/Charts/python/Helper.py new file mode 100644 index 000000000000..f3d2c154ba23 --- /dev/null +++ b/odk/examples/DevelopersGuide/Charts/python/Helper.py @@ -0,0 +1,44 @@ +import sys +import traceback + +import officehelper + + +class Helper(object): + def __init__(self): + # connect to a running office and get the ServiceManager + try: + # get the remote office component context + self._context = officehelper.bootstrap() + print("Connected to a running office ...") + # get the remote office service manager + self._factory = self._context.getServiceManager() + + except Exception as err: + print(f"Couldn't get ServiceManager: {err}") + traceback.print_exc() + sys.exit(1) + + def create_spreadsheet_document(self): + return self._create_document("scalc") + + def create_drawing_document(self): + return self._create_document("sdraw") + + def create_text_document(self): + return self._create_document("swriter") + + def _create_document(self, doc_type): + result = None + try: + desktop = self._factory.createInstanceWithContext("com.sun.star.frame.Desktop", self._context) + result = desktop.loadComponentFromURL(f"private:factory/{doc_type}", "_blank", 0, tuple()) + except Exception as err: + print(f"Couldn't create Document of type {doc_type}: {err}") + traceback.print_exc() + return + + return result + + def get_componentContext(self): + return self._context diff --git a/odk/examples/DevelopersGuide/Charts/python/bullet.gif b/odk/examples/DevelopersGuide/Charts/python/bullet.gif Binary files differnew file mode 100644 index 000000000000..0f8efd140b98 --- /dev/null +++ b/odk/examples/DevelopersGuide/Charts/python/bullet.gif |