summaryrefslogtreecommitdiff
path: root/odk/examples/DevelopersGuide/Charts/python
diff options
context:
space:
mode:
authorzeph <zeph.chai@ymail.com>2024-02-05 20:03:14 -0800
committerHossein <hossein@libreoffice.org>2024-02-27 23:41:18 +0100
commit7c78d2b29e04228481c0e4bfa9e3eaf6ccbd575b (patch)
tree7a023050c0bacaab7f72c39411d6fba146a20ba2 /odk/examples/DevelopersGuide/Charts/python
parent487ce28057656e752dc9bb7eddea5befb446ad0a (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.py189
-rw-r--r--odk/examples/DevelopersGuide/Charts/python/ChartInCalc.py225
-rw-r--r--odk/examples/DevelopersGuide/Charts/python/Helper.py44
-rw-r--r--odk/examples/DevelopersGuide/Charts/python/bullet.gifbin0 -> 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
new file mode 100644
index 000000000000..0f8efd140b98
--- /dev/null
+++ b/odk/examples/DevelopersGuide/Charts/python/bullet.gif
Binary files differ