diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index 891c617..0000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,27 +0,0 @@ ---- -name: Bug report -about: Create a report to help us improve -title: '' -labels: '' -assignees: '' - ---- - -**Describe the bug** -A clear and concise description of what the bug is. - -**To Reproduce** -Steps to reproduce the behavior: -1. Go to '...' -2. Click on '....' -3. Scroll down to '....' -4. See error - -**Expected behavior** -A clear and concise description of what you expected to happen. - -**Screenshots** -If applicable, add screenshots to help explain your problem. - -**Additional context** -Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index bbcbbe7..0000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -name: Feature request -about: Suggest an idea for this project -title: '' -labels: '' -assignees: '' - ---- - -**Is your feature request related to a problem? Please describe.** -A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] - -**Describe the solution you'd like** -A clear and concise description of what you want to happen. - -**Describe alternatives you've considered** -A clear and concise description of any alternative solutions or features you've considered. - -**Additional context** -Add any other context or screenshots about the feature request here. diff --git a/CHANGES_en.md b/CHANGES_en.md deleted file mode 100644 index 772d13a..0000000 --- a/CHANGES_en.md +++ /dev/null @@ -1,66 +0,0 @@ -## v2.1.5 - -- ### New Method Added to CTkLineChart Object - | Method Name | Description | Parameters | Return Type | - |------------------|------------------------------------------------------------|----------------|-------------| - | `clear_data` | Clears the data for all lines within the chart, ensuring that only the most recent visible data points are retained. If the total data points exceed the maximum visible points, the older data is removed from each line's data. This method ensures that the chart displays only the relevant portion of data based on the maximum visible range. | - | `None` | - -- ### New Method Added to CTkLine Object - | Method Name | Description | Parameters | Return Type | - |------------------|------------------------------------------------------------|----------------|-------------| - | `clear_data` | Clears the data for a specific line, ensuring that only the most recent visible data points are retained. If the line's data exceeds the maximum visible points, the older data is trimmed. This method allows each line to independently clean its data, ensuring it remains within the visible range. | - | `None` | - ---- - -## v2.1.4 - -- ### New Method Added to CTkLineChart Object - | Method Name | Description | Parameters | Return Type | - |------------------|------------------------------------------------------------|----------------|-------------| - | `get_line_area` | Get the are of specific line | line: `ctkchart.CTkLine` | `float` | - | `get_lines_area` | Get the are of all lines | - | `float` | - ---- - -## v2.1.3 - -- ### New Method Added to CTkLineChart Object - | Method Name | Description | Parameters | Return Type | - |------------------|------------------------------------------------------------|----------------|-------------| - | `destroy` | Destroy the line chart, along with its lines | - | `None` | - -- ### New Method Added to CTkLine Object - | Method Name | Description | Parameters | Return Type | - |------------------|------------------------------------------------------------|----------------|-------------| - | `destroy` | Destroy the line object | - | `None` | - ---- - -## v2.1.2 - -- ### New Method Added to CTkLine Object - - | Method Name | Description | Parameters | Return Type | - |------------------|------------------------------------------------|------------------------------------------|-------------| - | `cget` | Get the value of the specified parameter | attribute_name: `str \| "__all__"` | `any` | - | `set_visible` | Change the visibility of the line | state: `bool` | `None` | - | `get_visibility` | Get the visibility of the line | - | `bool` | - -- ### New Methods Added to CTkLineChart Object - - | Method Name | Description | Parameters | Return Type | - |------------------------|------------------------------------------------|--------------------------------------------------|-------------| - | `set_lines_visibility` | Change the visibility of all the lines | state: `bool` | `None` | - | `set_line_visibility` | Change the visibility of a specific line | line: `ctkchart.CTkLine`
state: `bool` | `None` | - | `get_line_visibility` | Get the visibility of a specific line | line: `ctkchart.CTkLine` | `bool` | - | `cget` | Get the value of the specified parameter | attribute_name: `str \| "__all__"` | `any` | - | `place_info` | Get info about place | attribute_name: `str \| "__all__"` | `any` | - | `pack_info` | Get info about pack | attribute_name: `str \| "__all__"` | `any` | - | `grid_info` | Get info about grid | attribute_name: `str \| "__all__"` | `any` | - -- ### Removed Methods in CTkLineChart Object - - | Method Name | Description | Parameters | Return Type | - |-------------|----------------------|----------------------------------------------|-------------| - | hide_all | Hide all the lines | state: `bool` | None | - | hide | hide a specific line | line: `ctkchart.CTkLine`
state: `bool` | None | \ No newline at end of file diff --git a/CHANGES_zh.md b/CHANGES_zh.md deleted file mode 100644 index 3175306..0000000 --- a/CHANGES_zh.md +++ /dev/null @@ -1,66 +0,0 @@ -## v2.1.5 - -- ### 新增方法到 `CTkLineChart` 对象 - | 方法名称 | 描述 | 参数 | 返回类型 | - |------------------|------------------------------------------------------------|----------------|-------------| - | `clear_data` | 清除图表中所有线的数据,确保只保留最新的可见数据点。如果数据点总数超过最大可见点,则会从每条线的数据中移除旧数据。此方法确保图表仅显示基于最大可见范围的相关数据部分。 | - | `None` | - -- ### 新增方法到 `CTkLine` 对象 - | 方法名称 | 描述 | 参数 | 返回类型 | - |------------------|------------------------------------------------------------|----------------|-------------| - | `clear_data` | 清除特定线的数据,确保只保留最新的可见数据点。如果线的数据超过最大可见点,则会修剪旧数据。此方法允许每条线独立清除其数据,确保它始终保持在可见范围内。 | - | `None` | - ---- - -## v2.1.4 - -- ### 新增方法到 `CTkLineChart` 对象 - | 方法名称 | 描述 | 参数 | 返回类型 | - |------------------|------------------------------------------------------------|----------------|-------------| - | `get_line_area` | 获取特定线的区域大小 | line: `ctkchart.CTkLine` | `float` | - | `get_lines_area` | 获取所有线的区域大小 | - | `float` | - ---- - -## v2.1.3 - -- ### 新增方法到 `CTkLineChart` 对象 - | 方法名称 | 描述 | 参数 | 返回类型 | - |------------------|------------------------------------------------------------|----------------|-------------| - | `destroy` | 销毁线图及其所有线 | - | `None` | - -- ### 新增方法到 `CTkLine` 对象 - | 方法名称 | 描述 | 参数 | 返回类型 | - |------------------|------------------------------------------------------------|----------------|-------------| - | `destroy` | 销毁线对象 | - | `None` | - ---- - -## v2.1.2 - -- ### 新增方法到 `CTkLine` 对象 - - | 方法名称 | 描述 | 参数 | 返回类型 | - |------------------|------------------------------------------------|------------------------------------------|-------------| - | `cget` | 获取指定参数的值 | attribute_name: `str \| "__all__"` | `any` | - | `set_visible` | 更改线的可见性 | state: `bool` | `None` | - | `get_visibility` | 获取线的可见性 | - | `bool` | - -- ### 新增方法到 `CTkLineChart` 对象 - - | 方法名称 | 描述 | 参数 | 返回类型 | - |------------------------|------------------------------------------------|--------------------------------------------------|-------------| - | `set_lines_visibility` | 更改所有线的可见性 | state: `bool` | `None` | - | `set_line_visibility` | 更改特定线的可见性 | line: `ctkchart.CTkLine`
state: `bool` | `None` | - | `get_line_visibility` | 获取特定线的可见性 | line: `ctkchart.CTkLine` | `bool` | - | `cget` | 获取指定参数的值 | attribute_name: `str \| "__all__"` | `any` | - | `place_info` | 获取位置相关信息 | attribute_name: `str \| "__all__"` | `any` | - | `pack_info` | 获取打包相关信息 | attribute_name: `str \| "__all__"` | `any` | - | `grid_info` | 获取网格相关信息 | attribute_name: `str \| "__all__"` | `any` | - -- ### 移除 `CTkLineChart` 对象的方法 - - | 方法名称 | 描述 | 参数 | 返回类型 | - |-------------|----------------------|----------------------------------------------|-------------| - | hide_all | 隐藏所有的线 | state: `bool` | None | - | hide | 隐藏特定的线 | line: `ctkchart.CTkLine`
state: `bool` | None | diff --git a/PULL_REQUEST_TEMPLATE.md b/PULL_REQUEST_TEMPLATE.md deleted file mode 100644 index 6933ff5..0000000 --- a/PULL_REQUEST_TEMPLATE.md +++ /dev/null @@ -1,9 +0,0 @@ -## Pull Request Checklist - -- [ ] Have you tested your changes? -- [ ] Have you updated the documentation? -- [ ] ... - -## Description - -Briefly describe the changes introduced by this pull request. diff --git a/README.md b/README.md index 5e3c180..d2aced3 100644 --- a/README.md +++ b/README.md @@ -1,386 +1,360 @@ -
+
-[![ctkchart](https://snyk.io/advisor/python/ctkchart/badge.svg)](https://snyk.io/advisor/python/ctkchart) +### Contributing to ctkchart -# ctkchart +# ctkchart - 0.0.1 (beta) -### `v 2.1.6` +https://github.com/Thisal-D/ctkchart/assets/93121062/05d01144-ad3e-4d7c-aa61-df79acf2e1c7 -[![Downloads](https://static.pepy.tech/badge/ctkchart)](https://pepy.tech/project/ctkchart) [![Downloads](https://static.pepy.tech/badge/ctkchart/month)](https://pepy.tech/project/ctkchart) [![Downloads](https://static.pepy.tech/badge/ctkchart/week)](https://pepy.tech/project/ctkchart) +https://github.com/Thisal-D/ctkchart/assets/93121062/6fb3cba4-909b-46bc-a259-17db5279a1e1 -
- -**
  • ctkchart is a Python library for creating live updating line charts in customtkinter.
  • ** +###
  • ctkchart Library is a Python library that simplifies the process of creating line charts in tkinter and customtkinter GUI applications.
  • ---- +
    -### Features +## ctkchart - 0.0.1 (beta) -- **Live Update**: Display live data with line charts. -- **Multiple Lines**: Support for plotting multiple lines on the same chart for easy comparison. -- **Color Customization**: Customize colors to match your application's design or data representation. -- **Dynamic Color Change**: Dynamic Color Change for Dark & Light. -- **Font Customization**: Adjust fonts for text elements to enhance readability. -- **Dimension Customization**: Customize chart dimensions to fit various display sizes and layouts. +### You need to install & import package first +* installation + * ``` + pip install ctkchart + ``` ---- +* importing + * ``` + import ctkchart + ``` -### Importing & Installation -* **Installation** - ``` - pip install ctkchart - ``` +## objects +* CTkLineChart +* CTkLine -* **Importing** - ``` python - import ctkchart - ``` ---- +## To display data using CTkLineChart you need to do 3 main tasks +1. Creating a CTkLineChart +2. Creating a CTkLine +3. Display of data +
    +
    -### Simple Guide -- **import package** - ``` python - import tkchart - ``` +# 1 . Creating a CTkLineChart + +``` +linechart = ctkchart.CTkLineChart() +``` +- ## Attributes & Types & Values + ## Master Configuration + - master : ``tkinter | customtkinter (Frame | Canvas | Tk)`` + + ## Dimensions + - width : ``int`` + - height : ``int`` + - axis_size : ``int`` + - x_space : ``int`` + - y_space : ``int`` + - line_width : ``int | str`` + - "auto" + - 10 + - pointer_size : ``int`` + + ## Value Configuration + - x_axis_section_count : ``int`` + - y_axis_section_count : ``int`` + - x_axis_label_count : ``int`` + - y_axis_label_count : ``int`` + - x_axis_display_values_indices : ``tuple[int, ...]`` + - x_axis_data : ``any`` + - y_axis_data : ``any`` + - x_axis_values : ``tuple(any, ...)`` + - ("2020 Year", "2021 Year", "2022 Year", "2023 Year", "2024 Year") + - (0.1, 0.2, 0.3, 0.4, 0.5) + - y_axis_values : ``tuple(int | float, int | float)`` + - (0 ,1000) + - (-1000, 1000) + - y_axis_precision : ``int`` + - pointing_values_precision : ``int`` + - ~~y_axis_max_value~~ : Deprecated + + ## Color Configuration + - bg_color : ``tuple[str, str] | str`` + - fg_color : ``tuple[str, str] | str`` + - axis_color : ``tuple[str, str] | str`` + - x_axis_font_color : ``tuple[str, str] | str`` + - "#ffffff" + - "white" + - y_axis_font_color : ``tuple[str, str] | str`` + - x_axis_data_font_color : ``tuple[str, str] | str`` + - y_axis_data_font_color : ``tuple[str, str] | str`` + - y_axis_section_color : ``tuple[str, str] | str`` + - x_axis_section_color : ``tuple[str, str] | str`` + - pointer_color : ``tuple[str, str] | str`` + - ~~section_color~~ : Deprecated -- **Create Line Chart and place the chart** - ``` python - chart = ctkchart.CTkLineChart( - master=root, - x_axis_values=("a", "b", "c", "d", "e", "f"), - y_axis_values=(100, 900) - ) - chart.place(x=10, y=10) - ``` - -- **Create Line** - ``` python - line = ctkchart.CTkLine(master=chart) - ``` - -- **Display Data** - display data using a loop - ``` python - def loop(): - while True: - random_data = random.choice(range(100, 900)) - chart.show_data(line=line, data=[random_data]) - time.sleep(1) + ## Font Configuration + - data_font_style : ``tuple[str, int, str]`` + - ("arial", 10, "bold") + - ("arial", 20, "normal") + - axis_font_style : ``tuple`` + + ## Style Configuration + - x_axis_data_position : ``str`` + - "top" + - "side" + - y_axis_data_position : ``str`` + - x_axis_section_style : ``str`` + - "normal" + - "dashed" + - y_axis_section_style : ``str`` + - x_axis_section_style_type : ``tuple(int, int)`` + - (50, 10) + - (10, 10) + - y_axis_section_style_type : ``tuple(int, int)`` + + ## Data Retrieval Configuration + - pointing_callback_function : ``function`` + - function_name(*args) + - function_name(x ,y) + - pointer_state : ``str`` + - "enabled" + - "disabled" + - pointer_lock : ``str`` + - "enabled" + - "disabled" - #call the loop as thead - theading.Thread(target=loop).start() - ``` + ## Recent Changes + - ~~y_axis_max_value : ``int | float``~~ Deprecated + - replaced with y_axis_values : ``tuple(int | float, int | float)`` + + **_The y_axis_values parameter is a tuple where the value at index 0 represents the starting value of the Y-axis, and the value at index 1 represents the ending value of the Y-axis._** + + - ~~section_color : ``tuple[str, str] | str``~~ Deprecated + - replaced with x_axis_section_color : ``tuple[str, str] | str`` + - replaced with y_axis_section_color : ``tuple[str, str] | str`` + +- ## Methods + + - ### configure : ``use to change CTkLineChart attributes`` + Support parameters + - width + - height + - axis_size + - x_space + - y_space + - line_width + - pointer_size + - x_axis_section_count + - y_axis_section_count + - x_axis_label_count + - y_axis_label_count + - x_axis_display_values_indices + - x_axis_data + - y_axis_data + - x_axis_values + - y_axis_values + - y_axis_precision + - pointing_values_precision + - bg_color + - fg_color + - axis_color + - x_axis_font_color + - y_axis_font_color + - x_axis_data_font_color + - y_axis_data_font_color + - y_axis_section_color + - x_axis_section_color + - pointer_color + - data_font_style + - axis_font_style + - x_axis_data_position + - y_axis_data_position + - x_axis_section_style + - y_axis_section_style + - x_axis_section_style_type + - y_axis_section_style_type + - pointing_callback_function + - pointer_state + - pointer_lock + - ~~y_axis_max_value~~ : Removed + - ~~section_color~~ : Removed ---- -### Links + + - ### show_data : ``use to display data`` + Support parameters + - data : ``tuple`` + - line : ``ctkchart.CTkLine`` + + - ### place : ``use to place LineChart`` + Support parameters + - x + - y + - rely + - relx + - anchor + + - ### pack : ``use to pack LineChart`` + Support parameters + - pady + - padx + - before + - after + - side + - anchor + + - ### grid : ``use to grid LineChart`` + Support parameters + - column + - columnspan + - padx + - pady + - row + - rowspan + - sticky + + - ### place_forget : ``use to place forget the chart`` + - ### pack_forget : ``use to pack forget the chart`` + - ### grid_forget : ``use to grid forget the chart`` + - ### place_back : ``use to place chart in the old location after place forget`` + - ### pack_back : ``use to pack chart in the old location after pack forget`` + - ### grid_back : ``use to grid chart in the old location after grid forget`` + - ### hide_all : ``use to hide all the lines`` + Support parameters + - state : ``bool`` + + - ### hide : ``use to hide a specific line`` + Support parameters + - line : ``ctkchart.CTkLine`` + - state : ``bool`` + - ### reset : ``use to reset chart`` -- **Documentation :** [Documents](documentation) - - [English doc.](documentation/DOCUMENTATION_en.md) - - [Chinese doc.](documentation/DOCUMENTATION_zh.md) -- **Python official :** [ctkchart](https://pypi.org/project/ctkchart/) + ---- +# 2 . Creating a CTkLine -### What You Can Accomplish +``` +line = ctkchart.CTkLine() +``` -- **Simple** +- ## Attributes & Types & Values + - master : ``ctkchart.CTkLineChart`` + - color : ``tuple[str, str] | str`` + - "white" + - "#10f0f0" + - size : ``int`` + - style : ``str`` + - "normal" + - "dashed" + - "dotted" + - style_type : ``tuple(int, int)`` + - (5,10) + - (10,5) + - point_highlight: ``str`` + - "disabled" + - "enabled" + - point_highlight_size: ``int`` + - point_highlight_color: ``tuple[str, str] | str`` - https://github.com/Thisal-D/ctkchart/assets/93121062/6f1e844f-d51c-467a-a3dc-ee03fea78fc9 - - ``` python - import customtkinter as ctk # Importing the customtkinter library as ctk - import ctkchart # Importing the ctkchart module for chart creation - import random # Importing the random module for generating random data - import threading # Importing the threading module for running tasks concurrently - import time # Importing the time module for adding delays - - # Create the root window and configure - root = ctk.CTk() - root.configure(fg_color="#0d1117") - root.geometry("720x430+200+200") - - # Create a line chart widget - line_chart = ctkchart.CTkLineChart( - master=root, # Set the master as the root window - x_axis_values=("01-01", "01-02", "01-03", "01-04", "01-05", "01-06", "01-07", "01-08", "01-09", "01-10"), # X-axis values - y_axis_values=(0, 1000) # Y-axis values (range) - ) - - line_chart.pack(pady=15) # Pack the line chart widget into the root - - # Create a line for the line chart - line = ctkchart.CTkLine(master=line_chart) # Set the master as the line chart - - def display_data(): - """Function to continuously display random data on the line chart.""" - while True: - random_data = [random.choice(range(0, 1000))] # Generate random data between 0 and 1000 - line_chart.show_data(line=line, data=random_data) # Display the random data on the line chart - time.sleep(0.5) # Pause for 0.5 seconds before the next iteration - - # Call the display_data function as a separate thread - threading.Thread(target=display_data).start() - - # Start the main event loop - root.mainloop() - ``` - --- - -- **Simple style** - - https://github.com/Thisal-D/ctkchart/assets/93121062/afe56452-68c3-44f0-9c67-2ab6f6910f6e - - ``` python - import customtkinter as ctk # Importing the customtkinter library as ctk - import ctkchart # Importing the ctkchart module for chart creation - import random # Importing the random module for generating random data - import threading # Importing the threading module for running tasks concurrently - import time # Importing the time module for adding delays - - # Create the root window and configure - root = ctk.CTk() - root.configure(fg_color="#0d1117") - root.geometry("720x430+200+200") - - # Create a line chart widget - line_chart = ctkchart.CTkLineChart( - master=root, # Set the master as the root window - x_axis_values=("01-01", "01-02", "01-03", "01-04", "01-05", "01-06", "01-07", "01-08", "01-09", "01-10"), # X-axis values - y_axis_values=(0, 1000), # Y-axis values (range) - y_axis_label_count=10, # set y axis labels count to 10 - ) - - line_chart.pack(pady=15) # Pack the line chart widget into the root - - # Create a line for the line chart - line = ctkchart.CTkLine( - master=line_chart, # Set the master as the line chart - size=2, # Set the line size to 2 - fill="enabled" # enable line fill - ) - - def display_data(): - """Function to continuously display random data on the line chart.""" - while True: - random_data = [random.choice(range(0, 1000))] # Generate random data between 0 and 1000 - line_chart.show_data(line=line, data=random_data) # Display the random data on the line chart - time.sleep(0.5) # Pause for 0.5 seconds before the next iteration - - # Call the display_data function as a separate thread - threading.Thread(target=display_data).start() - - # Start the main event loop - root.mainloop() - ``` - --- - -- **2 lines with different line styles** - - https://github.com/Thisal-D/ctkchart/assets/93121062/9bc35a39-a8ca-4942-9fc7-a1c89d1bd1bc - - ``` python - import customtkinter as ctk # Importing the customtkinter library as ctk - import ctkchart # Importing the ctkchart module for chart creation - import random # Importing the random module for generating random data - import threading # Importing the threading module for running tasks concurrently - import time # Importing the time module for adding delays - - # Create the root window and configure - root = ctk.CTk() - root.configure(fg_color=("#ffffff", "#0d1117")) - root.geometry("720x430+200+200") - - # Create a line chart widget - line_chart = ctkchart.CTkLineChart( - master=root, # Set the master as the root window - x_axis_values=("01-01", "01-02", "01-03", "01-04", "01-05", "01-06", "01-07", "01-08", "01-09", "01-10"), # X-axis values - y_axis_values=(0, 1000), # Y-axis values (range) - y_axis_label_count=10, # set y axis labels count to 10 - ) - - line_chart.pack(pady=15) # Pack the line chart widget into the root - - line1 = ctkchart.CTkLine( - master=line_chart, # Set the master as the line chart - color=("#5dffb6","#5dffb6"), # index 0 for light and 1 for dark theme - size=2, # Set the line size to 2 - style="dashed", # style change to dashed - style_type=(10, 5), #index 0 for dash width and 1 for space between dashes - ) - - line2 = ctkchart.CTkLine( - master=line_chart, # Set the master as the line chart - color=("#FFBAD2", "#FFBAD2"), # index 0 for light and 1 for dark theme - size=2, # Set the line size to 2 - point_highlight="enabled", # enable point highlight - point_highlight_color=("#FFBAD2", "#FFBAD2"), # enable point highlight - ) - - def display_data(): - """Function to continuously display random data on the line chart.""" - while True: - random_data = [random.choice(range(0, 1000))] # Generate random data between 0 and 1000 - line_chart.show_data(line=line1, data=random_data) # Display the random data on the line 1 on chart - random_data = [random.choice(range(0, 1000))] # Generate random data between 0 and 1000 - line_chart.show_data(line=line2, data=random_data) # Display the random data on the line 2 on chart - time.sleep(0.5) # Pause for 0.5 seconds before the next iteration - - # Call the display_data function as a separate thread - threading.Thread(target=display_data).start() - - # Start the main event loop - root.mainloop() - ``` - --- - -- **3 lines with different line styles** - - https://github.com/Thisal-D/ctkchart/assets/93121062/6d568b70-2ceb-42d0-b93c-0096f2745134 - - ``` python - import customtkinter as ctk # Importing the customtkinter library as ctk - import ctkchart # Importing the ctkchart module for chart creation - import random # Importing the random module for generating random data - import threading # Importing the threading module for running tasks concurrently - import time # Importing the time module for adding delays - - # Create the root window and configure - root = ctk.CTk() - root.configure(fg_color=("#ffffff", "#0d1117")) - root.geometry("720x430+200+200") - - # Create a line chart widget - line_chart = ctkchart.CTkLineChart( - master=root, # Set the master as the root window - x_axis_values=("01-01", "01-02", "01-03", "01-04", "01-05", "01-06", "01-07", "01-08", "01-09", "01-10"), # X-axis values - y_axis_values=(0, 1000), # Y-axis values (range) - y_axis_label_count=10, # set y axis labels count to 10 - ) - - line_chart.pack(pady=15) # Pack the line chart widget into the root - - # Create a line 1 for the line chart - line1 = ctkchart.CTkLine( - master=line_chart, # Set the master as the line chart - size=2, # Set the line size to 2 - fill="enabled" # enable line fill - ) - - line2 = ctkchart.CTkLine( - master=line_chart, # Set the master as the line chart - color=("#5dffb6","#5dffb6"), # index 0 for light and 1 for dark theme - size=2, # Set the line size to 2 - style="dashed", # style change to dashed - style_type=(10, 5), #index 0 for dash width and 1 for space between dashes - ) - - line3 = ctkchart.CTkLine( - master=line_chart, # Set the master as the line chart - color=("#FFBAD2", "#FFBAD2"), # index 0 for light and 1 for dark theme - size=2, # Set the line size to 2 - point_highlight="enabled", # enable point highlight - point_highlight_color=("#FFBAD2", "#FFBAD2"), # enable point highlight - ) - - def display_data(): - """Function to continuously display random data on the line chart.""" - while True: - random_data = [random.choice(range(0, 1000))] # Generate random data between 0 and 1000 - line_chart.show_data(line=line1, data=random_data) # Display the random data on the line 1 on chart - random_data = [random.choice(range(0, 1000))] # Generate random data between 0 and 1000 - line_chart.show_data(line=line2, data=random_data) # Display the random data on the line 2 on chart - random_data = [random.choice(range(0, 1000))] # Generate random data between 0 and 1000 - line_chart.show_data(line=line3, data=random_data) # Display the random data on the line 3 on chart - time.sleep(0.5) # Pause for 0.5 seconds before the next iteration - - # Call the display_data function as a separate thread - threading.Thread(target=display_data).start() - - # Start the main event loop - root.mainloop() - ``` - --- - -- **Advance** (Actually not, Just Two More Attributes Added) + +- ## Methods + - #### configure : ``use to change CTkLine attributes`` + Support parameters + - size + - color + - style + - style_type + - point_highlight + - point_highlight_size + - point_highlight_color + +``` +line = ctkchart.CTkLine(master=linechart, + color="lightblue", + size=2, + style="dashed", + style_type=(4,10)) + +``` + + +# 3 . Display of Data +``` +import ctkchart +import customtkinter as ctk +from random import choices + +root = ctk.CTk() + + + +chart = ctkchart.CTkLineChart(master=root, pointer_state="enabled", width=900, x_axis_values=tuple([x for x in range(20)]), + pointer_lock="enabled", pointer_size=1) + +chart.place(x=10,y=10) + +line = ctkchart.CTkLine(master=chart) + +chart.show_data(line=line, data=[0,1,2,3,4,5,6,7,8,9,10]) + + +def loop(): + chart.show_data(line=line, data=tuple(choices((range(0,11)),k=1))) + root.after(1000, loop) +loop() + + +root.mainloop() +``` + + +
    + +
    - https://github.com/Thisal-D/ctkchart/assets/93121062/c2838fd6-3a0f-45be-bb39-9953d007067d - - ``` python - import customtkinter as ctk # Importing the customtkinter library as ctk - import ctkchart # Importing the ctkchart module for chart creation - import random # Importing the random module for generating random data - import threading # Importing the threading module for running tasks concurrently - import time # Importing the time module for adding delays - - # Create the root window and configure - root = ctk.CTk() - root.configure(fg_color=("#ffffff", "#0d1117")) - root.geometry("720x430+200+200") - - # Create a line chart widget - line_chart = ctkchart.CTkLineChart( - master=root, # Set the master as the root window - x_axis_values=("01-01", "01-02", "01-03", "01-04", "01-05", "01-06", "01-07", "01-08", "01-09", "01-10"), # X-axis values - y_axis_values=(0, 1000), # Y-axis values (range) - y_axis_label_count=10, # set y axis labels count to 1 - y_axis_section_count=10, - x_axis_section_count=10, - ) - - line_chart.pack(pady=15) # Pack the line chart widget into the root - - line1 = ctkchart.CTkLine( - master=line_chart, # Set the master as the line chart - color=("#5dffb6","#5dffb6"), # index 0 for light and 1 for dark theme - size=2, # Set the line size to 2 - style="dashed", # style change to dashed - style_type=(10, 5), #index 0 for dash width and 1 for space between dashes - ) - - line2 = ctkchart.CTkLine( - master=line_chart, # Set the master as the line chart - color=("#FFBAD2", "#FFBAD2"), # index 0 for light and 1 for dark theme - size=2, # Set the line size to 2 - point_highlight="enabled", # enable point highlight - point_highlight_color=("#FFBAD2", "#FFBAD2"), # enable point highlight - ) - - def display_data(): - """Function to continuously display random data on the line chart.""" - while True: - random_data = [random.choice(range(0, 1000))] # Generate random data between 0 and 1000 - line_chart.show_data(line=line1, data=random_data) # Display the random data on the line 1 on chart - random_data = [random.choice(range(0, 1000))] # Generate random data between 0 and 1000 - line_chart.show_data(line=line2, data=random_data) # Display the random data on the line 2 on chart - time.sleep(0.5) # Pause for 0.5 seconds before the next iteration - - # Call the display_data function as a separate thread - threading.Thread(target=display_data).start() - - # Start the main event loop - root.mainloop() - ``` ---- - -- #### Light and Dark theme - - **For every parameter that involves color in ctkchart, you can provide either**: - - A single string representing the color. - - A tuple of two strings where the first string represents the color for the light theme and the second string represents the color for the dark theme. - - https://github.com/user-attachments/assets/9fed4b83-5b03-4ea0-82a0-36029dfc93dd - ---- - -**Explore customizable features such as colors, fonts, and more in the documentation.** - -#### Please refer to the full documentation -- [**English doc.**](documentation/DOCUMENTATION_en.md) -- [**Chinese doc.**](documentation/DOCUMENTATION_zh.md) - ---- - -#### Contributors -- [](https://github.com/childeyouyu) [youyu](https://github.com/childeyouyu) +
    + +### Go to top + +# Contributing to ctkchart + +Thank you for considering contributing to ctkchart! Please follow these guidelines to contribute effectively. + +## Getting Started + +1. Fork the repository. +2. Clone your forked repository: `git clone https://github.com/Thisal-D/ctkchart.git` +3. Create a new branch for your changes: `git checkout -b feature-branch` + +## Making Changes + +1. Make your changes and ensure they follow the project's coding standards. +2. Test your changes locally. +3. Commit your changes: `git commit -m "Brief description of your changes"` + +## Submitting Changes + +1. Push your changes to your forked repository: `git push origin feature-branch` +2. Create a pull request on the main repository. + +## Code of Conduct + +Please adhere to the [Code of Conduct](CODE_OF_CONDUCT.md) to maintain a respectful and inclusive community. + +## Issues and Discussions + +If you encounter issues or have questions, please check the [issue tracker](https://github.com/Thisal-D/ctkchart/issues) or start a discussion in the [GitHub Discussions](https://github.com/Thisal-D/ctkchart/discussions) section. + +## License + +By contributing, you agree that your contributions will be licensed under the project's [LICENSE](LICENSE). + +Thank you for your contribution! + +
    + + +### go to PyPi +- # PyPi.org : ctkchart + +### go to GitHub +- # GitHub.com : ctkchart + diff --git a/SECURITY.md b/SECURITY.md deleted file mode 100644 index 9862d01..0000000 --- a/SECURITY.md +++ /dev/null @@ -1 +0,0 @@ -# Security Policy diff --git a/Tests/test.py b/Tests/test.py new file mode 100644 index 0000000..d68523d --- /dev/null +++ b/Tests/test.py @@ -0,0 +1,24 @@ +import ctkchart +import customtkinter as ctk +from random import choices + +root = ctk.CTk() + +chart = ctkchart.CTkLineChart(master=root, pointer_state="enabled", width=900, x_axis_values=tuple([x for x in range(20)]), + pointer_lock="enabled", pointer_size=1) +chart.pack() + +line = ctkchart.CTkLine(master=chart) + +chart.show_data(line=line, data=[0,1,2,3,4,5,6,7,8,9,10]) + +def loop(): + chart.show_data(line=line, data=tuple(choices((range(0,11)),k=1))) + root.after(1000, loop) + +loop() + +ctk.CTkButton(master=root ,text="Dark", command=lambda:ctk.set_appearance_mode("dark")).pack(pady=10) +ctk.CTkButton(master=root ,text="Light", command=lambda:ctk.set_appearance_mode("light")).pack() + +root.mainloop() diff --git a/documentation/DOCUMENTATION_en.md b/documentation/DOCUMENTATION_en.md deleted file mode 100644 index 5fa0be1..0000000 --- a/documentation/DOCUMENTATION_en.md +++ /dev/null @@ -1,807 +0,0 @@ -
    - -[中文说明 Documentation](DOCUMENTATION_zh.md) | [Chinese Documentation](DOCUMENTATION_zh.md) - -
    - ---- - -
    - -**Usage Guide** | **Examples** | **Parameter Explanation** | **Whats New ?** - -### Importing & Installation -* Installation - ``` - pip install ctkchart - ``` - -* Importing - ``` python - import ctkchart - ``` ---- -
    - -### Parameter Overview - -
    - - - - - - -
    -
    - ---- - -### To display data using ctkchart you need to do 3 main tasks -1. **Creating a Line Chart** -2. **Creating a Line** -3. **Display of data** - ---- - -
    - -## 1 . Creating a LineChart -**Creating a Line** | **Display of data** - -``` python -linechart = ctkchart.CTkLineChart() -``` - -### Parameters - -| Parameter | Required / Optional | Description | Types | Example Value(s) | -|-------------------------------------------------|---------------------|--------------------------------------------|---------------------------------|-------------------------------------| -| master | ***Required*** | Master Widget for LineChart | ``widget`` | widget | -| [y_axis_values](#x_y_axis_values) | ***Required*** | Minimum and maximum values for y-axis | ``tuple[int \| float]`` | (-1000, 1000), ... | -| [x_axis_values](#x_y_axis_values) | ***Required*** | Values for x-axis | ``tuple[any]`` | (1, 2, 3, 4, 5), ... | -| width | ***Optional*** | Width of the chart | ``int`` | 300, ... | -| height | ***Optional*** | Height of the chart | ``int`` | 100, ... | -| [axis_size](#parameter_img) | ***Optional*** | Size of the axis | ``int`` | 1<= | -| [axis_color](#parameter_img) | ***Optional*** | Color of the axis | ``tuple[str, str]`` \| ``str`` | ("#FF0000", "#00FF00"), ... | -| [bg_color](#parameter_img) | ***Optional*** | Background color of the chart | ``tuple[str, str]`` \| ``str`` | ("#FF0000", "#00FF00"), ... | -| [fg_color](#parameter_img) | ***Optional*** | Foreground color of the chart | ``tuple[str, str]`` \| ``str`` | ("#FF0000", "#00FF00"), ... | -| [data_font_style](#x_y_data) | ***Optional*** | Font style for data labels | ``tuple[str, int, str]`` | ("arial", 9, "bold"), ... | -| [axis_font_style](#x_y_font_style) | ***Optional*** | Font style for axis labels | ``tuple[str, int, str]`` | ("arial", 8, "normal"), ... | -| [x_axis_data](#x_y_data) | ***Optional*** | Data label for x-axis | ``str`` | "X", ... | -| [y_axis_data](#x_y_data) | ***Optional*** | Value for y-axi data label | ``any`` | "Y", ... | -| [x_axis_data_font_color](#x_y_data) | ***Optional*** | Font color for x-axis data label | ``tuple[str, str]`` \| ``str`` | ("#FF0000", "#00FF00"), ... | -| [y_axis_data_font_color](#x_y_data) | ***Optional*** | Font color for y-axis data label | ``tuple[str, str]`` \| ``str`` | ("#FF0000", "#00FF00"), ... | -| [x_axis_data_position](#data_position) | ***Optional*** | Position of x-axis data label | ``str`` ("top", "side") | "top" | -| [y_axis_data_position](#data_position) | ***Optional*** | Position of y-axis data label | ``str`` ("top", "side") | "top" | -| [x_axis_section_count](#x_y_section) | ***Optional*** | Number of sections on the x-axis | ``int`` | 0<= | -| [y_axis_section_count](#x_y_section) | ***Optional*** | Number of sections on the y-axis | ``int`` | 0<= | -| [x_axis_label_count](#x_y_label_count) | ***Optional*** | Number of x-axis labels | ``int`` | 0<= | -| [y_axis_label_count](#x_y_label_count) | ***Optional*** | Number of y-axis labels | ``int`` | 1<= | -| [x_axis_font_color](#x_y_font_style) | ***Optional*** | Font color for x-axis labels | ``tuple[str, str]`` \| ``str`` | ("#FF0000", "#00FF00"), ... | -| [y_axis_font_color](#x_y_font_style) | ***Optional*** | Font color for y-axis labels | ``tuple[str, str]`` \| ``str`` | ("#FF0000", "#00FF00"), ... | -| [x_axis_section_style](#x_y_section_style) | ***Optional*** | Style of sections on the x-axis | ``str`` ("normal", "dashed") | "normal" | -| [y_axis_section_style](#x_y_section_style) | ***Optional*** | Style of sections on the y-axis | ``str`` ("normal", "dashed") | "normal" | -| [x_axis_section_style_type](#x_y_section_style) | ***Optional*** | Style type for sections on the x-axis | ``tuple[int, int]`` | (100, 50), ... | -| [y_axis_section_style_type](#x_y_section_style) | ***Optional*** | Style type for sections on the y-axis | ``tuple[int, int]`` | (100, 50) | -| [x_axis_section_color](#x_y_section) | ***Optional*** | Color of sections on the x-axis | ``tuple[str, str]`` \| ``str`` | ("#FF0000", "#00FF00"), ... | -| [y_axis_section_color](#x_y_section) | ***Optional*** | Color of sections on the y-axis | ``tuple[str, str]`` \| ``str`` | ("#FF0000", "#00FF00"), ... | -| [y_axis_precision](#y_precision) | ***Optional*** | Precision for y-axis values | ``int`` | 0<= | -| [x_axis_display_values_indices](#indices_view) | ***Optional*** | Indices of values to display on the x-axis | ``tuple[int, ...]`` | (0, 1, 2, 3, 4, 5), ... | -| [x_axis_point_spacing](#x_axis_point_spacing) | ***Optional*** | Width of lines | ``int`` \| ``str`` "auto" | "auto"
    1<= | -| [x_space](#parameter_img) | ***Optional*** | Space between x-axis and chart area | ``int`` | 0<= | -| [y_space](#parameter_img) | ***Optional*** | Space between y-axis and chart area | ``int`` | 0<= | -| pointer_state | ***Optional*** | State of the pointer | ``str`` ("enabled", "disabled") | "disabled" | -| pointing_callback_function | ***Optional*** | Callback function for pointer | ``callable`` | function(*args)
    function(x, y) | -| pointer_color | ***Optional*** | Color of the pointer | ``tuple[str, str]`` \| ``str`` | ("#FF0000", "#00FF00"), ... | -| pointing_values_precision | ***Optional*** | Precision for pointing values | ``int`` | 0<= | -| pointer_lock | ***Optional*** | State of pointer lock | ``str`` ("enabled", "disabled") | "enabled" | -| pointer_size | ***Optional*** | Size of the pointer | ``int`` | 1<= | - - ---- - -### Methods - -| Method | Description | Supported / Required Parameters | Return Type | -|----------------------------|------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------|-------------| -| configure | Change LineChart attributes | All attributes except for master | ``None`` | -| [show_data](#display-data) | Display data | data: ``list``
    line: ``ctkchart.CTkLine`` | ``None`` | -| place | Place LineChart | x: ``int``
    y: ``int``
    rely: ``float or int``
    relx: ``float or int``
    anchor: ``str`` | ``None`` | -| pack | Pack LineChart | pady: ``int``
    padx: ``int``
    before: ``widget``
    after: ``widget``
    side: ``str``
    anchor: ``str`` | ``None`` | -| grid | Grid LineChart | column: ``int``
    columnspan: ``int``
    padx: ``int``
    pady: ``int``
    row: ``int``
    rowspan: ``int``
    sticky: ``str`` | ``None`` | -| place_forget | Place forget the chart | - | ``None`` | -| pack_forget | Pack forget the chart | - | ``None`` | -| grid_forget | Grid forget the chart | - | ``None`` | -| set_lines_visibility | Change the visibility of all the lines | state: ``bool`` | ``None`` | -| set_line_visibility | Change the visibility of a specific line | line: ``ctkchart.CTkLine``
    state: ``bool`` | ``None`` | -| get_line_visibility | Get the visibility of a specific line | line: ``ctkchart.CTkLine`` | ``bool`` | -| reset | Reset line chart | - | ``None`` | -| cget | Get the value of the specified parameter | attribute_name: ``str`` \| "\_\_all\_\_" | ``any`` | -| place_info | Get info about place | attribute_name: ``str`` \| "\_\_all\_\_" | ``any`` | -| pack_info | Get info about pack | attribute_name: ``str`` \| "\_\_all\_\_" | ``any`` | -| grid_info | Get info about grid | attribute_name: ``str`` \| "\_\_all\_\_" | ``any`` | -| get_line_area | Get the are of specific line | line: `ctkchart.CTkLine` | ``float`` | -| get_lines_area | Get the are of all lines | - | ``float`` | -| destroy | Destroy the chart | - | ``None`` | - - - -
    - ---- - -
    - -## 2 . Creating a Line - -**Creating a LineChart** | **Display of data** - -``` python -line = ctkchart.CTkLine() -``` - -### Parameters - -| Parameter Name | Required / Optional | Description | Types | Example Value(s) | -|-------------------------------------------|---------------------|--------------------------------|----------------------------------------|------------------| -| master | Required | Master of the line | ``ctkchart.CTkLine`` | LineChart obj | -| [color](#line_color_size) | Optional | Color of the line | ``tuple[str, str]`` \| ``str`` | "#768df1" | -| [size](#line_color_size) | Optional | Size of the line | ``int`` | 1<= | -| [style](#line_style) | Optional | Style of the line | ``str`` ("normal", "dashed", "dotted") | "normal" | -| [style_type](#line_style_type) | Optional | Style type for the line | ``tuple[int, int]`` | (10, 5),... | -| [point_highlight](#point_highlight) m | Optional | State of point highlighting | ``str`` ("enabled", "disabled") | "disabled" | -| [point_highlight_size](#point_highlight) | Optional | Size of the highlighted point | ``int`` | 1<= | -| [point_highlight_color](#point_highlight) | Optional | Color of the highlighted point | ``tuple[str, str]`` \| ``str`` | "#768df1" | -| [fill](#fill) | Optional | State of filling | ``str`` ("enabled", "disabled") | "disabled" | -| [fill_color](#fill) | Optional | Color of the fill | ``tuple[str, str]`` \| ``str`` | "#5d6db6" | - - ---- - -### Methods - -| Method | Description | Supported Parameters | Return Type | -|----------------|------------------------------------------|--------------------------------------------|-------------| -| configure | Change LineChart attributes | All attributes except for master | ``None`` | -| cget | Get the value of the specified parameter | attribute_name: ``str`` \| "\_\_all\_\_" | ``any`` | -| reset | reset line object | - | ``None`` | -| set_visible | change the visibility of the line | state: ``bool`` | ``None`` | -| get_visibility | get the visibility of the line | - | ``bool`` | -| destroy | Destroy the line | - | ``None`` | - -
    - ---- - -
    - -## 3 . Display of Data - -**Creating a LineChart** | **Creating a Line** - -``` python -import tkinter as tk -import ctkchart -import random - -#root -root = tk.Tk() -root.configure(bg="#151515") - -#creating a chart -chart = ctkchart.CTkLineChart( - master=root, - x_axis_values = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10), - y_axis_values = (-100,100) -) -chart.pack() - -#creating a line -line = ctkchart.CTkLine(master=chart) - -data = [x for x in range(-100,101)] #values -100 to 100 -#dipslay data (random) -def loop(): - chart.show_data(line=line, data=random.choices(data, k=1)) - root.after(500, loop) -loop() - -root.mainloop() -``` - -
    - -https://github.com/Thisal-D/tkchart/assets/93121062/64440c23-63e6-4093-b027-21b00a6f5518 - -
    - ---- - -
    - - -
    - -**Back to the Top** | **Usage Guide** | **Examples** | **Whats New ?** - -## Parameter Explanation - -
    - -### CTkLineChart - -- #### y_axis_values - y_axis_values is a tuple that containing two numeric values for the y-axis. The first value (index 0) represents the starting value of the y-axis, and the second value (index 1) represents the end value of the y-axis. This tuple defines the range of values displayed along the y-axis on chart. - -- #### x_axis_values - x_axis_values is a collection of values that can include any data type. These values are assigned to the x-axis, starting from index 0 and continuing to the last index of the x_axis_values tuple. Each value in the tuple corresponds to a point along the x-axis in chart. - - - - - - - ``` python - chart = ctkchart.CTkLineChart( - master=any_widget - x_axis_values=(2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025), - y_axis_values=(-100, 100) - ) - ``` ---- -
    - -
    - -- #### x_axis_data - refers to the value type displayed in the x-axis of a chart. - **Note: "X" is the default value.** - -- #### y_axis_data - refers to the value type displayed in the y-axis of a chart. - **Note: "Y" is the default value.** - -- #### x_axis_data_font_color - refers to the font color applied to the label representing the data type on x-axis of a chart. - -- #### y_axis_data_font_color - refers to the font color applied to the label representing the data type on y-axis of a chart. - -- #### data_font_style - refers to the font style applied to the labels representing the data types on both the x-axis and y-axis of a chart. - - - - - - - ``` python - chart = ctkchart.CTkLineChart( - master=any_widget, - x_axis_values=(2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025), - y_axis_values=(-100, 100), - y_axis_data="Y data" , - x_axis_data="X data", - x_axis_data_font_color="#ff0000", - y_axis_data_font_color="#00ff00", - data_font_style=("arial", 15, "underline") - ) - ``` - ---- - -
    - -
    - -- #### x_axis_label_count - When you have a set of x-axis labels, such as years from 2018 to 2025, normally all these labels are shown. But sometimes you might want to show only a few of them for better clarity.
    - For instance, if you set the x_axis_label_count to 4, it means you want to display only 4 labels instead of all 8. So, the chart will automatically skip some labels to fit your specified count.
    - **Note: len(x_axis_values) is the default value.**
    - In other words, adjusting the x_axis_label_count allows you to control how many labels appear on the x-axis, making your visualization cleaner and easier to understand. -
    - - **if there are 9 labels you can limit it to : 3, 1, 0.** - - **if there are 20 labels you can limit it to : 10, 5, 4, 2, 1, 0.** - - **if there are 15 labels you can limit it to : 5, 3, 1, 0.** - - ##### In some cases, using the x_axis_label_count parameter might not be sufficient for your needs. In such situations, you can utilize the x_axis_display_values_indices parameter to precisely control which values are displayed on the x-axis. - -- #### y_axis_label_count - By default, if you set the y-axis values to range from -100 to 100, only the extreme values (-100 and 100) will be displayed on the y-axis. However, you have the option to adjust the number of labels displayed using the y_axis_label_count parameter.
    - For example, if you set y_axis_label_count to 3, the system will divide the y-axis range (-100 to 100) into equal intervals and display labels at those intervals. So, for this case, with a label count of 3, you might see labels at -100, 0, and 100.
    - In summary, adjusting the y_axis_label_count parameter allows you to control the number of labels displayed on the y-axis, providing flexibility in customizing the visualization based on your preferences and requirements. - - - - - - - - ``` python - chart = ctkchart.CTkLineChart( - master=any_widget, - x_axis_values=(2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025), - y_axis_values=(-100, 100), - x_axis_label_count=4, - y_axis_label_count=10, - ) - ``` - ---- - -
    - -
    - -- #### x_axis_display_values_indices - - Let's say you have a set of x-axis values representing years from 2018 to 2025: (2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025). Normally, all these values would be displayed on the x-axis.
    - However, there might be cases where you only want to display specific years rather than all of them. In such situations, you can use the x_axis_display_values_indices parameter to control which values are shown on the x-axis.
    - For example, if you only want to display the years 2019, 2022, and 2025, you can specify their indices in the x_axis_display_values_indices parameter. So, if the index of 2919 is 1, 2022 is 4, and 2025 is 7 (assuming 0-based indexing), you would set x_axis_display_values_indices to (1, 4, 7).
    - This way, by setting the indices of the values you want to display, you have precise control over which values appear on the x-axis in your visualization, allowing you to tailor it according to your specific requirements. - - - - - - - ``` python - chart = ctkchart.CTkLineChart( - master=any_widget, - x_axis_values=(2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025), - y_axis_values=(-100, 100), - x_axis_display_values_indices=(1, 4, 7) - ) - ``` - ---- - -
    - -
    - -- #### x_axis_data_position - The x_axis_data_position parameter determines the position of the x data label. It has two - - supported values: - - "top" - - "side" - - **Note: "top" is the default position** - -- #### y_axis_data_position - The y_axis_data_position parameter determines the position of the x data label. It has two - - supported values: - - "top" - - "side" - - **Note: "top" is the default position** - - Choosing between "top" and "side" determines whether the data labels are placed horizontally above the data points or vertically beside them, respectively. This parameter allows you to customize the layout of your chart according to your preferences and available space. - - - - - - - ``` python - chart = ctkchart.CTkLineChart( - master=any_widget, - x_axis_values=(2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025), - y_axis_values=(-100, 100), - x_axis_data_position="side", - y_axis_data_position="top" - ) - ``` - ---- - -
    - -
    - -- #### y_axis_precision - - The y_axis_precision parameter controls the number of decimal places displayed for the values on the y-axis.
    - **Note: 1 is the deafault precion**
    - For example: - - If you set y_axis_precision to 0, the values on the y-axis will be displayed as whole numbers.
    - - If you set y_axis_precision to 1, the values on the y-axis will be displayed with one decimal place.
    - - If you set y_axis_precision to 2, the values on the y-axis will be displayed with two decimal places. -
    - - And so on : - - **Adjusting the y_axis_precision parameter allows you to control the level of precision for the y-axis values in your chart. This parameter is particularly useful when dealing with data that requires specific precision or when you want to improve the readability of the chart by reducing the number of decimal places displayed.** - - - - - - - ``` python - chart = ctkchart.CTkLineChart( - master=any_widget, - x_axis_values=(2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025), - y_axis_values=(-100, 100), - y_axis_label_count=12, - y_axis_precision=4, - ) - ``` - ---- - -
    - -
    - -- #### axis_font_style - refers to font style of the x and y axis values - -- #### x_axis_font_color - refers to color of x axis values - -- #### y_axis_font_color - refers to color of y axis values - - - - - - - ``` python - chart = ctkchart.CTkLineChart( - master=any_widget, - x_axis_values=(2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025), - y_axis_values=(-100, 100), - x_axis_font_color="#00FF00", - y_axis_font_color="#FF0000", - axis_font_style=("arial", 13, "bold") - ) - ``` - ---- - -
    - -
    - -
    - -- #### x_axis_section_count - The x_axis_section_count parameter defines the number of sections or intervals into which the x-axis range will be divided in a chart.
    - **Here's a clearer breakdown :** - - Let's say you have a range of values on the x-axis, such as years from 2018 to 2025. By default, this range might be represented as a continuous line without any specific sections or intervals marked. - - However, if you set x_axis_section_count to a value, such as 8, it means you want to divide this x-axis range into equally spaced sections or intervals. Each section will represent a subset of the total x-axis range. - - Adjusting the x_axis_section_count parameter allows you to control the granularity of the x-axis in your chart, making it easier for viewers to interpret the data and identify trends within specific intervals. - -
    - -- #### y_axis_section_count - The y_axis_section_count parameter defines the number of sections or intervals into which the y-axis range will be divided in a chart.
    - **refer : x_axis_section_count** for more... - -- #### x_axis_section_color - refers to color of y axis sections - -- #### y_axis_section_color - refers to color of x axis sections - - - - - - - ``` python - chart = ctkchart.CTkLineChart( - master=any_widget, - x_axis_section_count=8, - y_axis_section_count=5, - x_axis_section_color="#2C2C2C", - y_axis_section_color="#2C2C2C" - ) - ``` - ---- - -
    - -
    - -
    - -- #### x_axis_section_style - x_axis_section_style parameter allows you to define the visual style of the sections along the x-axis in a chart. - - - Supported styles: - - "dashed": When you set x_axis_section_style to "dashed", the sections along the x-axis are displayed using dashed lines. - - "normal": Conversely, when x_axis_section_style is set to "normal", the sections along the x-axis are displayed using solid lines.

    - - **Note: "normal" is default style.** - -
    - -- #### y_axis_section_style - working same as x_axis_section_style, - refer x_axis_section_style for more - -
    - -- #### x_axis_section_style_type - The x_axis_section_style_type parameter is a tuple that contains two integer values, specifying the style of the dashes used when the x_axis_section_style is set to "dashed".
    - For example:
    - - If you set x_axis_section_style_type to (20, 10), it means : - - The width of each dash is 20 pixels. - - The spacing between dashes is 10 pixels. -
    - - These values determine the visual appearance of the dashed lines or markers used to represent the sections along the x-axis. Adjusting these values allows you to customize the appearance of the dashed sections according to your preferences or the requirements of your visualization. - -
    - -- #### y_axis_section_style_type - working same as x_axis_section_style_type, - refer x_axis_section_style_type for more - - - - - - - ``` python - chart = ctkchart.CTkLineChart( - master=any_widget, - x_axis_section_count=8, - y_axis_section_count=5, - x_axis_section_style="dashed", - x_axis_section_style_type=(20,10), - y_axis_section_style="dashed", - y_axis_section_style_type=(20,10), - ) - ``` - ---- - -
    - -
    - -- #### x_axis_point_spacing - The x_axis_point_spacing parameter allows your to manually set the spacing between points on the x-axis, typically measured in pixels. However, if you do not manually set this parameter, it is automatically calculated based on the length of x_axis_values.
    - **Note: "auto" is the default value.** -
    - - - after configure specific value to x_axis_point_spacing, you can reset value by configure it as "auto" for set default value. -
    - ``` python - chart.configure(x_axis_point_spacing = "auto") - ``` - - - - - - - ``` python - chart = ctkchart.CTkLineChart( - master=any_widget, - x_axis_point_spacing="auto" - ) - ``` - - The x_axis_point_spacing parameter is automatically calculated based on the length of the x_axis_values tuple. This means that the spacing between points on the x-axis is determined by dividing the width of the chart by the length of the x_axis_values list. - - - - - - - When you set the x_axis_point_spacing parameter to a specific value, such as 40, it means that you have manually specified the spacing between points on the x-axis to be 40 units (e.g., pixels). In this case, the chart will use the user-defined spacing of 40 units between each point on the x-axis, regardless of the length of the x_axis_values tuple. - - ``` python - chart = ctkchart.CTkLineChart( - master=any_widget, - x_axis_point_spacing=40 - ) - ``` - ---- - -
    - -### CTkLine - -
    - -- #### color - refers to color of line. - -- #### size - refers to size(thickness) of line.
    - **Note: 1 is the deafault size** -
    - - - - - - - ``` python - line = ctkchart.CTkLine( - master=chart, - color="#30ACC7", - size=5 - ) - ``` - -
    - -
    - -- #### style - style parameter allows you to define the visual style of the line. -
    - - supported styles: - - "dashed": When you set style to "dashed", the line is displayed as dashed line. - - "dotted": When you set style to "dotted", the line is displayed as dotted line. - - "normal": When you set style to "normal", the line is displayed as solid line. -
    - **Note: "normal" is the default style.** - - - - - - - ``` python - line = ctkchart.CTkLine( - master=chart, - line_style="dashed" - ) - ``` - ---- - -
    - -
    - -- #### style_type - The style_type parameter is a tuple that contains two integer values, specifying the style of the dashes and dots used when the style is set to "dashed" or "dotted". - - For example: - - If you set style_type to (20, 10), it means: - - The width of each dash or size of each dot is 20 pixels. - - The spacing between dashes or dots is 10 pixels. - - **Note: In the "dotted" style, the size parameter is irrelevant as the dots are of fixed size determined by the style_type tuple.**
    - **Note: In the "normal" style, the style_type parameter is do nothing.** - - - - - - - ``` python - line = ctkchart.CTkLine( - master=chart, - line_style="dashed", - line_style_type=(10,2) - ) - ``` - ---- - -
    - -
    - -- #### point_highlight - The point_highlight parameter is used to control point highlight, enabling or disabling it. -
    - - Supported values: - - "enabled": Enable point highlight. - - "disabled": Disable point highlight. - -- #### point_highlight_size - The point_highlight_size is used to set size of the highlight. - -- #### point_highlight_color - The point_highlight_color used to control color of highlight. - - - - - - - ``` python - line = ctkchart.CTkLine( - master=chart, - point_highlight="enabled", - point_highlight_color="#80CCFF", - point_highlight_size=8 - ) - ``` - ---- - -
    - -
    - -- #### fill - The fill parameter is utilized to control whether line fill is enabled or disabled. -
    - - Supported Values: - - "enabled": Enable line fill. - - "disabled": Disable line fill. - -- #### fill_color - The fill_color parameter is used to specify the color for the fill. - - - - - - - ``` python - line = ctkchart.CTkLine( - master=chart, - fill="enabled", - fill_color="#5D6DB6" - ) - ``` - ---- - -
    - -
    - -
    - -## Dynamic Color Change - -***For every parameter that involves color in ctkchart, you can provide either***: - -- A single string representing the color. -- A tuple of two strings where the first string represents the color for the light theme and the second string represents the color for the dark theme. - -
    - ---- - -
    - -**Back to the Top** | **Usage Guide** | **Parameter Explanation** | **Whats New ?** - -## [Examples](https://github.com/Thisal-D/ctkchart/tree/main/template(s)) - -
    - - - - - - - - - - - - - - - -
    - -
    - ---- - -## Links - -**PyPi.org** : ctkchart - -**GitHub.com** : ctkchart \ No newline at end of file diff --git a/documentation/DOCUMENTATION_zh.md b/documentation/DOCUMENTATION_zh.md deleted file mode 100644 index ce4c25a..0000000 --- a/documentation/DOCUMENTATION_zh.md +++ /dev/null @@ -1,824 +0,0 @@ -
    - -[English README](DOCUMENTATION_en.md) - ---- - -**如何使用** | **例子** | **参数说明** | **查看新功能** - -
    - -### 安装和使用 -* 安装 - ``` - pip install ctkchart - ``` - -* 使用 - ``` python - import ctkchart - ``` ---- - -
    - -### 参数概述 - -
    - - - - - - ---- - -
    - -
    - -### 要使用 ctkchart 显示数据,您需要执行以下三步: -1. **创建折线图** -2. **创建一条线** -3. **数据显示** - ---- - -
    - -## 1 . 创建折线图 -**创建一条线** | **数据显示** - -``` python -linechart = ctkchart.CTkLineChart() -``` - -### 参数 - -| 参数 | 必备参数 / 可选参数 | 描述 | 数据类型 | 示例值 | -|-------------------------------------------------|-------------|--------------------|---------------------------------|----------------------------------------| -| master | ***必须*** | 折线图主体 | ``widget`` | widget | -| [y_axis_values](#x_y_axis_values) | ***必须*** | y 轴的最小值和最大值 | ``tuple[int \| float], ...`` | (-1000, 1000), ... | -| [x_axis_values](#x_y_axis_values) | ***必须*** | x 轴的值 | ``tuple[any, ...]`` | (1, 2, 3, 4, 5), ... | -| width | ***可选*** | 折线图的宽度 | ``int`` | 300, ... | -| height | ***可选*** | 折线图的高度 | ``int`` | 100, ... | -| [axis_size](#parameter_img) | ***可选*** | 坐标轴宽度 | ``int`` | 1<= | -| [axis_color](#parameter_img) | ***可选*** | 坐标轴轴颜色 | ``tuple[str, str]`` \| ``str`` | ("#FF0000", "#00FF00"), ... | -| [bg_color](#parameter_img) | ***可选*** | 折线图的背景色 | ``tuple[str, str]`` \| ``str`` | ("#FF0000", "#00FF00"), ... | -| [fg_color](#parameter_img) | ***可选*** | 折线图的前景色 | ``tuple[str, str]`` \| ``str`` | ("#FF0000", "#00FF00"), ... | -| [data_font_style](#x_y_data) | ***可选*** | 坐标轴名称的字体样式 | ``tuple[str, int, str]`` | ("arial", 9, "bold"), ... | -| [axis_font_style](#x_y_font_style) | ***可选*** | 坐标轴文字的字体样式 | ``tuple[str, int, str]`` | ("arial", 8, "normal"), ... | -| [x_axis_data](#x_y_data) | ***可选*** | x_data 的值(x 坐标轴名称) | ``str`` | "X", ... | -| [y_axis_data](#x_y_data) | ***可选*** | y_data 的值(y 坐标轴名称) | ``any`` | "Y", ... | -| [x_axis_data_font_color](#x_y_data) | ***可选*** | x_data 的字体颜色 | ``tuple[str, str]`` \| ``str`` | ("#FF0000", "#00FF00"), "#707070", ... | -| [y_axis_data_font_color](#x_y_data) | ***可选*** | y_data 的字体颜色 | ``tuple[str, str]`` \| ``str`` | ("#FF0000", "#00FF00"), "#707070", ... | -| [x_axis_data_position](#data_position) | ***可选*** | x_data 的排布方式 | ``str`` | "top" | -| [y_axis_data_position](#data_position) | ***可选*** | y_data 的排布方式 | ``str`` | "top" | -| [x_axis_section_count](#x_y_section) | ***可选*** | x 轴上的网格线数 | ``int`` | 0<= | -| [y_axis_section_count](#x_y_section) | ***可选*** | y 轴上的网格线数 | ``int`` | 0<= | -| [x_axis_label_count](#x_y_label_count) | ***可选*** | x 轴标签数量 | ``int`` | 0<= | -| [y_axis_label_count](#x_y_label_count) | ***可选*** | y 轴标签数量 | ``int`` | 1<= | -| [x_axis_font_color](#x_y_font_style) | ***可选*** | x 轴标签的字体颜色 | ``tuple[str, str]`` \| ``str`` | ("#FF0000", "#00FF00"), "#606060", ... | -| [y_axis_font_color](#x_y_font_style) | ***可选*** | y 轴标签的字体颜色 | ``tuple[str, str]`` \| ``str`` | ("#FF0000", "#00FF00"), "#606060", ... | -| [x_axis_section_style](#x_y_section_style) | ***可选*** | x 轴上的网格线样式 | ``str`` | "normal" | -| [y_axis_section_style](#x_y_section_style) | ***可选*** | y 轴上的网格线样式 | ``str`` | "normal" | -| [x_axis_section_style_type](#x_y_section_style) | ***可选*** | x 轴上网格线的实线与空白的尺寸 | ``tuple[int, int]`` | (100, 50) , (50,50), ... | -| [y_axis_section_style_type](#x_y_section_style) | ***可选*** | y 轴上网格线的实线与空白的尺寸 | ``tuple[int, int]`` | (100, 50) | -| [x_axis_section_color](#x_y_section) | ***可选*** | x 轴上网格线的颜色 | ``tuple[str, str]`` \| ``str`` | ("#FF0000", "#00FF00"), "#2C2C2C", ... | -| [y_axis_section_color](#x_y_section) | ***可选*** | y 轴上网格线的颜色 | ``tuple[str, str]`` \| ``str`` | ("#FF0000", "#00FF00"), "#2C2C2C" | -| [y_axis_precision](#y_precision) | ***可选*** | y 轴值的精度 | ``int`` | 0<= | -| [x_axis_display_values_indices](#indices_view) | ***可选*** | 显示在 x 轴上的坐标值的索引 | ``tuple[int, ...]`` | (0, 1, 2, 3, 4, 5), ... | -| [x_axis_point_spacing](#x_axis_point_spacing) | ***可选*** | 线条宽度 | ``int`` \| ``str`` "auto" | "auto"
    1<= | -| [x_space](#parameter_img) | ***可选*** | x 轴和图表区域之间的空间 | ``int`` | 0<= | -| [y_space](#parameter_img) | ***可选*** | y 轴和图表区域之间的空间 | ``int`` | 0<= | -| pointer_state | ***可选*** | 鼠标状态 | ``str`` ("enabled", "disabled") | "disabled" | -| pointing_callback_function | ***可选*** | 鼠标的回调函数 | ``callable`` | function(*args)
    function(x, y) | -| pointer_color | ***可选*** | 鼠标颜色 | ``tuple[str, str]`` \| ``str`` | ("#FF0000", "#00FF00"), "#606060", ... | -| pointing_values_precision | ***可选*** | 指向值的精度 | ``int`` | 0<= | -| pointer_lock | ***可选*** | 鼠标锁状态 | ``str`` ("enabled", "disabled") | "enabled" | -| pointer_size | ***可选*** | 鼠标显示线的宽度 | ``int`` | 1<= | - ---- - -### 方法 - -| 方法 | 描述 | 支持的参数 / 必须的参数 | 返回类型 | -|----------------------------|---------------------|----------------------------------------------------------------------------------------------------------------------------------|----------| -| configure | 更改 LineChart(折线图)属性 | 所有属性,除了 master | ``None`` | -| [show_data](#display-data) | 显示数据 | data: ``list``
    line: ``ctkchart.CTkLine`` | ``None`` | -| place | 放置 (place) 折线图 | x: ``int``
    y: ``int``
    rely: ``float or int``
    relx: ``float or int``
    anchor: ``str`` | ``None`` | -| pack | 放置 (pack) 折线图 | pady: ``int``
    padx: ``int``
    before: ``widget``
    after: ``widget``
    side: ``str``
    anchor: ``str`` | ``None`` | -| grid | 放置 (grid) 折线图 | column: ``int``
    columnspan: ``int``
    padx: ``int``
    pady: ``int``
    row: ``int``
    rowspan: ``int``
    sticky: ``str`` | ``None`` | -| place_forget | Place 忘编号 | - | ``None`` | -| pack_forget | Pack 忘编号 | - | ``None`` | -| grid_forget | Grid 忘编号 | - | ``None`` | -| set_lines_visibility | 更改所有线条的可见性 | state: ``bool`` | ``None`` | -| set_line_visibility | 更改特定行的可见性 | line: ``ctkchart.CTkLine``
    state: ``bool`` | ``None`` | -| get_line_visibility | 获取特定生产线的可见性 | line: ``ctkchart.CTkLine`` | ``bool`` | -| reset | 重置折线图 | - | ``None`` | -| cget | 获取指定参数的值。 | attribute_name: ``str`` \| "\_\_all\_\_" | ``any`` | -| place_info | 获取地点信息 | attribute_name: ``str`` \| "\_\_all\_\_" | ``any`` | -| pack_info | 获取有关包装的信息 | attribute_name: ``str`` \| "\_\_all\_\_" | ``any`` | -| grid_info | 获取网格信息 | attribute_name: ``str`` \| "\_\_all\_\_" | ``any`` | -| get_line_area | 获取特定线的面积 | line: `ctkchart.CTkLine` | `float` | -| get_lines_area | 获取所有线的面积 | - | `float` | -| clear_data | Clears the data for all lines within the chart, ensuring that only the most recent visible data points are retained. If the total data points exceed the maximum visible points, the older data is removed from each line's data. This method ensures that the chart displays only the relevant portion of data based on the maximum visible range. | - | ``None`` | -| destroy | 销毁图表 | - | ``None`` | -
    - -
    - ---- - -## 2 . 创建一条线 - -**创建折线图** | **数据显示** - -``` python -line = ctkchart.CTkLine() -``` - -### 参数 - -| 参数名称 | 必备参数 / 可选参数 | 描述 | 数据类型 | 示例值 | -|-------------------------------------------|-------------|------------------|----------------------------------------|---------------| -| master | 必须 | Master | ``ctkchart.CTkLine`` | LineChart obj | -| [color](#line_color_size) | 可选 | 折线的颜色 | ``str`` | "#768df1" | -| [size](#line_color_size) | 可选 | Size of the line | ``int`` | 1<= | -| [style](#line_style) | 可选 | 折线风格(直线、虚线、点线) | ``str`` ("normal", "dashed", "dotted") | "normal" | -| [style_type](#line_style_type) | 可选 | 实线与虚线的尺寸 | ``tuple[int, int]`` | (10, 5),... | -| [point_highlight](#point_highlight) | 可选 | 端点高亮状态 | ``str`` ("enabled", "disabled") | "disabled" | -| [point_highlight_size](#point_highlight) | 可选 | 高亮点的大小 | ``int`` | 1<= | -| [point_highlight_color](#point_highlight) | 可选 | 高亮点的颜色 | ``str`` | "#768df1" | -| [fill](#fill) | 可选 | 是否启用填充 | ``str`` ("enabled", "disabled") | "disabled" | -| [fill_color](#fill) | 可选 | 填充部分的颜​​色 | ``str`` | "#5d6db6" | - ---- - -### 方法 - -| 方法 | 描述 | 支持的参数 | 返回类型 | -|----------------|----------|------------------------------------------|----------| -| configure | 更改折线图属性 | 所有属性,除了 master | ``None`` | -| cget | 获取指定参数的值 | attribute_name: ``str`` \| "\_\_all\_\_" | ``any`` | -| reset | 重置线对象 | - | ``None`` | -| set_visible | 改变线条的可见度 | state: ``bool`` | ``None`` | -| get_visibility | 获得线路的可见度 | - | ``bool`` | -| clear_data | Clears the data for a specific line, ensuring that only the most recent visible data points are retained. If the line's data exceeds the maximum visible points, the older data is trimmed. This method allows each line to independently clean its data, ensuring it remains within the visible range. | - | ``None`` | -| destroy | 破坏线 | - | ``None`` | - -
    - -
    - ---- - -
    - -## 3 . 数据显示 - -**创建折线图** | **创建一条折线** - - -``` python -import tkinter as tk -import ctkchart -import random - -## root -root = tk.Tk() -root.configure(bg="#151515") - -## 创建折线图 -chart = ctkchart.CTkLineChart( - master=root, - x_axis_values = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10), - y_axis_values = (-100,100) -) -chart.pack() - -## 创建一条折线 -line = ctkchart.CTkLine(master=chart) - -data = [x for x in range(-100,101)] #values -100 to 100 -## 显示数据(随机) -def loop(): - chart.show_data(line=line, data=random.choices(data, k=1)) - root.after(500, loop) -loop() - -root.mainloop() -``` - -
    - -https://github.com/Thisal-D/tkchart/assets/93121062/64440c23-63e6-4093-b027-21b00a6f5518 - ---- - -
    - -
    - - -
    - -**返回顶部** | **使用指南** | **例子** | **查看新功能** - -## 参数说明 - -
    - -### CTkLineChart - -- #### y_axis_values - y_axis_values 是一个包含两个数值的元组。第一个值(索引 0)表示 y 轴的起始值,第二个值(索引 1)表示 y 轴的结束值。该元组定义了折线图上沿 y 轴显示的值的范围。 - -- #### x_axis_values - x_axis_values 是可以包含任何数据类型的值的集合。这些值被分配给 x 轴,从索引 0 开始一直到 x_axis_values 元组的最后一个索引。元组中的每个值对应于折线图中 x 轴上的一个点。 - - - - - - - ``` python - chart = ctkchart.CTkLineChart( - master=any_widget, - x_axis_values=(2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025), - y_axis_values=(-100, 100) - ) - ``` - ---- - -
    - -
    - -- #### x_axis_data - 指折线图 x 轴上显示的值类型。 - **注意:"X"为默认值。** - -- #### y_axis_data - 指折线图 y 轴上显示的值类型。 - **注意:"Y" 是默认值。** - -- #### x_axis_data_font_color - 指应用于表示折线图 x_axis_data 的标签的字体颜色。 - -- #### y_axis_data_font_color - 指应用于表示折线图 y_axis_data 的标签的字体颜色。 - -- #### data_font_style - 指应用于代表折线图 x_axis_data 和 y_axis_data 的标签的字体样式。 - - - - - - - ``` python - chart = ctkchart.CTkLineChart( - master=any_widget, - x_axis_values=(2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025), - y_axis_values=(-100, 100), - y_axis_data="Y data" , - x_axis_data="X data", - x_axis_data_font_color="#ff0000", - y_axis_data_font_color="#00ff00", - data_font_style=("arial", 15, "underline") - ) - ``` - ---- - -
    - -
    - -- #### x_axis_label_count - 当您有一组 x_value(例如从 2018 年到 2025 年)时,通常会显示所有这些标签。但有时为了更清晰起见,您可能只想显示其中的几个。
    - 例如,如果您将 x_axis_label_count 设置为 4,则意味着您只想显示 4 个标签,而不是全部 8 个。因此,折线图将自动跳过一些标签以适合您指定的数量。
    - **注意:len(x_axis_values) 是默认值。**
    - 换句话说,调整 x_axis_label_count 可以让您控制 x 轴上显示的标签数量,使您的可视化更清晰、更易于理解。 -
    - -**如果有 9 个标签,您可以将其限制为:3、1。** - -**如果有 20 个标签,您可以将其限制为:10, 5, 4, 2, 1。** - -**如果有 15 个标签,您可以将其限制为:5、3、1。** - - #### 在某些情况下,使用 x_axis_label_count 参数可能不足以满足您的需求。在这种情况下,您可以利用 x_axis_display_values_indices 参数来精确控制 x 轴上显示的值。 - -- #### y_axis_label_count - 默认情况下,如果将 y 轴值设置为 -100 到 100 范围,则 y 轴上将仅显示极值(-100 和 100 两个数字)。但是,您可以选择使用 y_axis_label_count 参数调整显示的标签数量。
    - 例如,如果将 y_axis_label_count 设置为 3,系统会将 y 轴范围(-100 到 100)划分为相等的间隔,并按这些间隔显示标签。因此,对于本例,标签计数为 3,您可能会看到 -100、0 和 100 处的标签。
    - 总之,调整 y_axis_label_count 参数允许您控制 y 轴上显示的标签数量,从而可以根据您的偏好和要求灵活地自定义可视化效果。 - - - - - - - ``` python - chart = ctkchart.CTkLineChart( - master=any_widget, - x_axis_values=(2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025), - y_axis_values=(-100, 100), - x_axis_label_count=4, - y_axis_label_count=10 - ) - ``` - ---- - -
    - -
    - -- #### x_axis_display_values_indices - 假设您有一组代表从 2018 年到 2025 年的 x 轴值:(2018、2019、2020、2021、2022、2023、2024、2025)。通常,所有这些值都会显示在 x 轴上。
    - 但是,在某些情况下,您可能只想显示特定年份而不是全部。在这种情况下,您可以使用 x_axis_display_values_indices 参数来控制在 x 轴上显示哪些值。
    - 例如,如果您只想显示 2019 年、2022 年和 2025 年,则可以在 x_axis_display_values_indices 参数中指定它们的索引。因此,如果 2019 年的索引为 1、2022 年为 4、2025 年为 7(假设基于 0 的索引),则您可以将 x_axis_display_values_indices 设置为 (1, 4, 7)。
    - 这样,通过设置要显示的值的索引,您可以精确控制可视化中 X 轴上显示的值,从而允许您根据您的特定要求对其进行定制。 - - - - - - - ``` python - chart = ctkchart.CTkLineChart( - master=any_widget, - x_axis_values=(2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025), - y_axis_values=(-100, 100), - x_axis_display_values_indices=(1, 4, 7) - ) - ``` - ---- - -
    - -
    - -- #### x_axis_data_position - x_axis_data_position 参数确定 x_axis_data 的文字布局。 - - 它有两个支持的值: - - "top" - - "side" - - **注意:“top”是默认位置** - -- #### y_axis_data_position - y_axis_data_position 参数确定 y_axis_data 的文字布局。 - - 它有两个支持的值: - - "top" - - "side" - - **注意:“top”是默认位置** - -
    - - 在"top"、"side"之间进行选择分别确定 x/y_axis_data 是水平放置在数据点上方还是垂直放置在数据点旁边。此参数允许您根据您的喜好和可用空间自定义折线图的布局。 - - - - - - - ``` python - chart = ctkchart.CTkLineChart( - master=any_widget, - x_axis_values=(2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025), - y_axis_values=(-100, 100), - x_axis_data_position="side", - y_axis_data_position="top" - ) - ``` - ---- - -
    - -
    - -- #### y_axis_precision - y_axis_ precision 参数控制 y 轴上的值显示的小数位数。
    - **注意:1 是默认精度**
    - 例如: - - 如果将 y_axis_precision 设置为 0,则 y 轴上的值将显示为整数。
    - - 如果将 y_axis_precision 设置为 1,则 y 轴上的值将显示一位小数。
    - - 如果将 y_axis_precision 设置为 2,则 y 轴上的值将显示两位小数。 -
    - - 此外 : - - **调整 y_axis_ precision 参数允许您控制折线图中 y 轴值的精度级别。当处理需要特定精度的数据或当您想要通过减少显示的小数位数来提高折线图的可读性时,此参数特别有用。** - - - - - - - ``` python - chart = ctkchart.CTkLineChart( - master=any_widget, - x_axis_values=(2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025), - y_axis_values=(-100, 100), - y_axis_label_count=12, - y_axis_precision=4, - ) - ``` - ---- - -
    - -
    - -- #### axis_font_style - 指 x 和 y 轴值的字体样式 - -- #### x_axis_font_color - 指 x 轴值的颜色 - -- #### y_axis_font_color - 指 y 轴值的颜色 - - - - - - - ``` python - chart = ctkchart.CTkLineChart( - master=any_widget, - x_axis_values=(2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025), - y_axis_values=(-100, 100), - x_axis_font_color="#00FF00", - y_axis_font_color="#FF0000", - axis_font_style=("arial", 13, "bold") - ) - ``` - ---- - -
    - -
    - -
    - -- #### x_axis_section_count - x_axis_section_count 参数定义折线图中 x 轴范围将划分为的部分或间隔的数量。
    - **这里有更清晰的细分:** - - 假设 x 轴上有一系列值,例如从 2018 年到 2025 年。默认情况下,此范围可能表示为连续线,没有标记任何特定部分或间隔。 - - 但是,如果将 x_axis_section_count 设置为一个值,例如 8,则意味着您想要将此 x 轴范围划分为等间距的部分或间隔。每个部分将代表总 x 轴范围的一个子集。 - - 调整 x_axis_section_count 参数允许您控制折线图中 x 轴的粒度,使查看者更容易解释数据并识别特定间隔内的趋势。 - -
    - -- #### y_axis_section_count - y_axis_section_count 参数定义折线图中 y 轴范围将划分为的部分或间隔的数量。
    - **请参阅:x_axis_section_count** 了解更多... - -- #### x_axis_section_color - 指 y 轴网格线的颜色 - -- #### y_axis_section_color - 指 x 轴网格线的颜色 - - - - - - - ``` python - chart = ctkchart.CTkLineChart( - master=any_widget, - x_axis_section_count=8, - y_axis_section_count=5, - x_axis_section_color="#2C2C2C", - y_axis_section_color="#2C2C2C" - ) - ``` - ---- - -
    - -
    - -
    - -- #### x_axis_section_style - x_axis_section_style 参数允许您定义折线图中沿 x 轴的部分的视觉样式。 - - - 支持的样式: - - "dashed": 当您将 x_axis_section_style 设置为“dashed”时,沿 x 轴的剖面将使用虚线显示。 - - "normal": 相反,当 x_axis_section_style 设置为“正常”时,沿 x 轴的截面将使用实线显示。 -
    - - **注意:"normal"是默认样式。** - -
    - -- #### y_axis_section_style - 与 x_axis_section_style 工作方式相同, - 有关更多信息,请参阅 x_axis_section_style - -
    - -- #### x_axis_section_style_type - x_axis_section_style_type 参数是一个包含两个整数值的元组,指定当 x_axis_section_style 设置为“dashed”时使用的破折号样式。
    - 例如:
    - - 如果将 x_axis_section_style_type 设置为 (20, 10),则意味着: - - 每个破折号的宽度为 20 像素。 - - 破折号之间的间距为 10 -
    - - - 这些值确定用于表示沿 x 轴的部分的虚线或标记的视觉外观。通过调整这些值,您可以根据您的偏好或可视化要求自定义虚线部分的外观。 - -
    - -- #### y_axis_section_style_type - 与 x_axis_section_style_type 工作相同, - 请参阅 x_axis_section_style_type 了解更多信息 - - - - - - - ``` python - chart = ctkchart.CTkLineChart( - master=any_widget, - x_axis_section_count=8, - y_axis_section_count=5, - x_axis_section_style="dashed", - x_axis_section_style_type=(20,10), - y_axis_section_style="dashed", - y_axis_section_style_type=(20,10), - ) - ``` - ---- - -
    - - -
    - -- #### x_axis_point_spacing - x_axis_point_spacing 参数允许您手动设置 x 轴上点之间的间距,通常以像素为单位测量。但是,如果您不手动设置该参数,则会根据 x_axis_values 的长度自动计算。 -
    - **注意:"auto"是默认值。** -
    - - - 将特定值配置为 x_axis_point_spacing 后,您可以通过将其配置为"auto"来重置值以设置默认值。 -
    - ``` python - chart.configure( - x_axis_point_spacing="auto" - ) - ``` - - - - - - - ``` python - chart = ctkchart.CTkLineChart( - master=any_widget, - x_axis_point_spacing="auto" - ) - ``` - - x_axis_point_spacing 参数是根据 x_axis_values 元组的长度自动计算的。这意味着 x 轴上点之间的间距是通过将折线图的宽度除以 x_axis_values 列表的长度来确定的。 - - - - - - - 当您将 x_axis_point_spacing 参数设置为特定值(例如 40)时,这意味着您已手动将 x 轴上的点之间的间距指定为 40 个单位(例如像素)。在这种情况下,无论 x_axis_values 元组的长度如何,折线图都将在 x 轴上的每个点之间使用用户定义的 40 个单位的间距。 - - ``` python - chart = ctkchart.CTkLineChart( - master=any_widget, - x_axis_point_spacing=40 - ) - ``` - ---- - -
    - -### CTkLine - -
    - -- #### color - 指的是线条的颜色。 - -- #### size - 指线条的尺寸(粗细)。
    - **注:1 为默认尺寸** -
    - - - - - - - ``` python - line = ctkchart.CTkLine( - master=chart, - color="#30ACC7", - size=5 - ) - ``` - ---- - -
    - -
    - -- #### style - style 参数允许您定义线条的视觉样式。 -
    - - 支持的样式: - - "dashed": 当样式设置为"dashed"时,折线条显示为虚线。 - - "dotted": 当样式设置为"dotted"时,折线显示为点虚线。 - - "normal": 当样式设置为"normal"时,线条显示为实线。 -
    - **注意:"normal"是默认样式。** - - - - - - - ``` python - line = ctkchart.CTkLine( - master=chart, - line_style="dashed" - ) - ``` - ---- - -
    - -
    - -- #### style_type - style_type 参数是一个包含两个整数值的元组,指定样式设置为"dashed"或"dotted"时使用的破折号和点的样式。 - - 例如: - - 如果将 style_type 设置为 (20, 10),则意味着: - - 每个破折号的宽度或每个点的大小为 20 像素。 - - 破折号或点之间的间距为 10 个像素。 - - **注意 在"dotted"风格下 , size 参数无关紧要,因为点的大小是由 style_type 元组确定的固定大小。**
    - **注意 在"normal"风格下,style_type 参数无效。** - - - - - - - ``` python - line = ctkchart.CTkLine( - master=chart, - line_style="dashed", - line_style_type=(10,2) - ) - ``` - ---- - -
    - -
    - -- #### point_highlight - point_highlight 参数用于控制点高亮。 -
    - - 支持的值: - - "enabled": 启用点高亮显示。 - - "disabled": 禁用点高亮显示。 - -- #### point_highlight_size - point_highlight_size 用于设置高亮点的大小。 - -- #### point_highlight_color - 高亮点的颜色。 - - - - - - - ``` python - line = ctkchart.CTkLine( - master=chart, - point_highlight="enabled", - point_highlight_color="#80CCFF", - point_highlight_size=8 - ) - ``` - ---- - -
    - -
    - -- #### fill - fill 参数用于控制是否启用或禁用行填充。 -
    - - 支持的值: - - "enabled": 启用线条填充。 - - "disabled": 禁用线条填充。 - -- #### fill_color - fill_color 参数用于指定填充的颜色。 - - - - - - - ``` python - line = ctkchart.CTkLine( - master=chart, - fill="enabled", - fill_color="#5D6DB6" - ) - ``` - -
    - -
    - ---- - -
    - -## 动态颜色变化 - -***对于 ctkchart 中涉及颜色的每个参数,有两种写法***: - -- 代表颜色的单个字符串。 -- 两个字符串的元组,其中第一个字符串表示浅色主题的颜色,第二个字符串表示深色主题的颜色。 - -
    - -
    - ---- - -**回到顶部** | **使用指南** | **参数说明** | **查看新功能** - -## [例子](https://github.com/Thisal-D/ctkchart/tree/main/template(s)) - -
    - - - - - - - - - - - - - - - -
    - -
    - ---- - -## 链接 - -**PyPi.org** : ctkchart - -**GitHub.com** : ctkchart - ---- - -## 翻译贡献 - -**翻译支持** : [有语](https://github.com/childeyouyu) - -**Translation by** : [youyu](https://github.com/childeyouyu) \ No newline at end of file diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index cda92d5..0000000 --- a/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -customtkinter \ No newline at end of file diff --git a/src/ctkchart/CTkLine.py b/src/ctkchart/CTkLine.py index 272f18d..dc0c8fb 100644 --- a/src/ctkchart/CTkLine.py +++ b/src/ctkchart/CTkLine.py @@ -1,305 +1,88 @@ -from typing import Union, Tuple, Literal -from .Validate import Validate +from .Validate import * + +class CTkLine(): + def __init__(self, + master = None, + color: tuple[str, str] | str = ("#404040", "#AAAAAA"), + size: int = 1, + style: str = "normal", + style_type: tuple[int, int] = (10,5), + point_highlight: str = "disabled", + point_highlight_size: int = 0, + point_highlight_color: tuple[str, str] | str = ("#404040", "#AAAAAA"), + *args: any + ) -> None: + + Validate._isValidColor(color, "color") + Validate._isInt(size, "size") + Validate._isValidLineStyle(style, "style") + Validate._isValidStyleType(style_type, "style_type") + Validate._isValidLineHighlight(point_highlight, "point_highlight") + Validate._isInt(point_highlight_size, "point_highlight_size") + Validate._isValidColor(point_highlight_color, "point_highlight_color") + + try : + self.__master = args[0] + except: + self.__master = master + + self.__color = color + self.__size = size + self.__y_end = 0 + self.__x_end = self.__master._CTkLineChart__line_width* -1 + self.__data = [] + self.__temp_data = [] + self.__ret_data = [] + self.__hide_state = False + self.__style = style + self.__style_type = style_type + self.__point_highlight = point_highlight + self.__point_highlight_size = point_highlight_size + self.__point_highlight_color = point_highlight_color + + + def configure(self, + color: tuple[str, str] | str = None, + size: int = None, + style: str = None, + style_type: tuple[int, int] = None, + point_highlight: str = None, + point_highlight_size: int = None, + point_highlight_color: tuple[str, str] | str = None, + ) -> None: + + if color != None: + Validate._isValidColor(color, "color") + self.__color = color + + if size != None: + Validate._isInt(size, "size") + self.__size = size + + if style != None: + Validate._isValidLineStyle(style, "style") + self.__style = style + + if style_type != None: + Validate._isValidStyleType(style_type, "style_type") + self.__style_type = style_type + + if point_highlight != None: + Validate._isValidLineHighlight(point_highlight, "point_highlight") + self.__point_highlight = point_highlight + + if point_highlight_size != None: + Validate._isInt(point_highlight_size, "point_highlight_size") + self.__point_highlight_size = point_highlight_size + + if point_highlight_color != None: + Validate._isValidColor(point_highlight_color, "point_highlight_color") + self.__point_highlight_color = point_highlight_color + + + def __reset(self) -> None: + self.__y_end = 0 + self.__x_end = self.__master._CTkLineChart__line_width* -1 + self.__data = [] -class CTkLine: - def __init__( - self, - master: any = None, - color: Union[Tuple[str, str], str] = ("#768df1", "#768df1"), - size: int = 1, - style: Literal["normal", "dashed", "dotted"] = "normal", - style_type: Tuple[int, int] = (4, 4), - point_highlight: Literal["enabled", "disabled"] = "disabled", - point_highlight_size: int = 8, - point_highlight_color: Union[Tuple[str, str], str] = ("#768df1", "#768df1"), - fill: Literal["enabled", "disabled"] = "disabled", - fill_color: Union[Tuple[str, str], str] = ("#bdc6ed", "#5d6db6"), - *args: any) -> None: - """ - Initialize a CTkLine object. - - Args: - master (any): The master object. - color (Union[Tuple[str, str], str]): The color of the line. - size (int): The size/thickness of the line. - style (str): The style of the line (e.g., 'normal', 'dashed', 'dotted'). - style_type (Tuple[int, int]): The style type for dashed or dotted lines. - point_highlight (str): Whether point highlighting is enabled or disabled. - point_highlight_size (int): The size of points used for highlighting. - point_highlight_color (Union[Tuple[str, str], str]): The color of points used for highlighting. - fill (str): Whether fill for the line is enabled or disabled. - fill_color (Union[Tuple[str, str], str]): The color of the fill for the line. - """ - - if master is None: - if len(args) != 0: - master = args[0] - else: - Validate._MasterAttNotProvideForLine("master") - - Validate._isValidCTkLineChart(master, "master") - Validate._isValidColor(color, "color") - Validate._isInt(size, "size") - Validate._isValidLineStyle(style, "style") - Validate._isValidStyleType(style_type, "style_type") - Validate._isValidLineHighlight(point_highlight, "point_highlight") - Validate._isInt(point_highlight_size, "point_highlight_size") - Validate._isValidColor(point_highlight_color, "point_highlight_color") - Validate._isValidLineFill(fill, "fill") - Validate._isValidColor(fill_color, "fill_color") - - self.__master = master - self.__color = color - self.__size = size - self.__y_end = 0 - self.__x_end = self.__master._CTkLineChart__x_axis_point_spacing * -1 - self.__data = [] - self.__temp_data = [] - self.__ret_data = [] - self.__visibility = self.__master._CTkLineChart__visibility - self.__style = style - self.__style_type = style_type - self.__point_highlight = point_highlight - self.__point_highlight_size = point_highlight_size - self.__point_highlight_color = point_highlight_color - self.__fill = fill - self.__fill_color = fill_color - - self.__master._CTkLineChart__lines.append(self) - - def configure( - self, - color: Union[Tuple[str, str], str] = None, - size: int = None, - style: Literal["normal", "dashed", "dotted"] = None, - style_type: Tuple[int, int] = None, - point_highlight: Literal["enabled", "disabled"] = None, - point_highlight_size: int = None, - point_highlight_color: Union[Tuple[str, str], str] = None, - fill: Literal["enabled", "disabled"] = None, - fill_color: Union[Tuple[str, str], str] = None) -> None: - """ - Configure attributes of the CTkLine object. - - Args: - color (Union[Tuple[str, str], str]): The color of the line. - size (int): The size/thickness of the line. - style (str): The style of the line (e.g., 'normal', 'dashed', 'dotted'). - style_type (Tuple[int, int]): The style type for dashed or dotted lines. - point_highlight (str): Whether point highlighting is enabled or disabled. - point_highlight_size (int): The size of points used for highlighting. - point_highlight_color (Union[Tuple[str, str], str]): The color of points used for highlighting. - fill (str): Whether fill for the line is enabled or disabled. - fill_color (Union[Tuple[str, str], str]): The color of the fill for the line. - """ - - changes_req = False - - if color is not None: - Validate._isValidColor(color, "color") - self.__color = color - changes_req = True - - if size is not None: - Validate._isInt(size, "size") - self.__size = size - changes_req = True - - if style is not None: - Validate._isValidLineStyle(style, "style") - self.__style = style - changes_req = True - - if style_type is not None: - Validate._isValidStyleType(style_type, "style_type") - self.__style_type = style_type - changes_req = True - - if point_highlight is not None: - Validate._isValidLineHighlight(point_highlight, "point_highlight") - self.__point_highlight = point_highlight - changes_req = True - - if point_highlight_size is not None: - Validate._isInt(point_highlight_size, "point_highlight_size") - self.__point_highlight_size = point_highlight_size - changes_req = True - - if point_highlight_color is not None: - Validate._isValidColor(point_highlight_color, "point_highlight_color") - self.__point_highlight_color = point_highlight_color - changes_req = True - - if fill is not None: - Validate._isValidLineFill(fill, "fill") - self.__fill = fill - changes_req = True - - if fill_color is not None: - Validate._isValidColor(fill_color, "fill_color") - self.__fill_color = fill_color - changes_req = True - - if changes_req: - self.__master._CTkLineChart__apply_line_configuration() - - def __reset_positions(self) -> None: - """ - Reset the CTkLine object. - """ - - self.__y_end = 0 - self.__x_end = self.__master._CTkLineChart__x_axis_point_spacing * -1 - - def __reset_data(self) -> None: - self.__data = [] - - def clear_data(self) -> None: - """ - Clears the chart data, ensuring that only the relevant visible data is retained. - - This method works by checking the maximum number of data points across all lines in the chart - and the maximum number of visible data points. If the chart contains more data points than - the visible limit, the data is cropped so that only the most recent data points (up to the - visible limit) are kept. If the chart is already within the visible limit, the data is not altered. - - The data is trimmed from the beginning of the dataset, and the most recent points are kept. - - This ensures that the chart does not display more data than the allowed visible limit, - optimizing performance and display consistency. - - Attributes: - self.__data: The internal list that holds all the data for the lines on the chart. - - Returns: - None: This method modifies the internal state of the data but does not return any value. - - Example: - line.clear_data() - - In this example, the data is cleaned up to ensure that only the most recent visible data - points are kept, improving the rendering performance and reducing memory usage. - """ - - maximum_data = self.__master._CTkLineChart__get_max_data_length_across_lines() - max_visible_points = self.__master._CTkLineChart__get_max_visible_data_points() - - if maximum_data > max_visible_points: - self.__data = self.__data[maximum_data - max_visible_points::] - - def reset(self) -> None: - """ - Reset the line. - """ - self.__reset_positions() - self.__reset_data() - self.__master._CTkLineChart__apply_line_configuration() - - def set_visible(self, state: bool) -> None: - """ - Set the visibility of the line. - - Args: - state (bool): True if the line should be visible, False otherwise. - """ - - Validate._isBool(state, "state") - if self.__visibility != state: - self.__visibility = state - self.__master._CTkLineChart__apply_line_configuration() - - def cget( - self, - attribute_name: Literal[ - "master", "color", "size", "style", "style_type", "point_highlight", - "point_highlight_size", "point_highlight_color", "fill", "fill_color", - "__all__"]) -> any: - """ - Get the value of a CTkLine attribute. - - Args: - attribute_name (str): Name of the attribute. - - Returns: - any: Value of the attribute. - """ - - if attribute_name == "master": - return self.__master - if attribute_name == "color": - return self.__color - if attribute_name == "size": - return self.__size - if attribute_name == "style": - return self.__style - if attribute_name == "style_type": - return self.__style_type - if attribute_name == "point_highlight": - return self.__point_highlight - if attribute_name == "point_highlight_size": - return self.__point_highlight_size - if attribute_name == "point_highlight_color": - return self.__point_highlight_color - if attribute_name == "fill": - return self.__fill - if attribute_name == "fill_color": - return self.__fill_color - - if attribute_name == "__all__": - return { - "master": self.__master, - "color": self.__color, - "size": self.__size, - "style": self.__style, - "style_type": self.__style_type, - "point_highlight": self.__point_highlight, - "point_highlight_size": self.__point_highlight_size, - "point_highlight_color": self.__point_highlight_color, - "fill": self.__fill, - "fill_color": self.__fill_color - } - Validate._invalidCget(attribute_name) - - def get_visibility(self) -> bool: - """ - Get the visibility of the line. - - Returns: - bool: True if the line is visible, False otherwise. - """ - - return self.__visibility - - def __del__(self) -> None: - """Destructor method to delete instance attributes.""" - del self.__master - del self.__color - del self.__size - del self.__y_end - del self.__x_end - del self.__data - del self.__temp_data - del self.__ret_data - del self.__visibility - del self.__style - del self.__style_type - del self.__point_highlight - del self.__point_highlight_size - del self.__point_highlight_color - del self.__fill - del self.__fill_color - - def destroy(self) -> None: - """ - Removes the instance from its master's line chart and - applies the updated line configuration. Calls the destructor - to clean up resources. - """ - try: - self.__master._CTkLineChart__lines.remove(self) - self.__master._CTkLineChart__apply_line_configuration() - except ValueError: - pass # In case the line is not in the list - finally: - self.__del__() diff --git a/src/ctkchart/CTkLineChart.py b/src/ctkchart/CTkLineChart.py index afdf3f6..ff112cf 100644 --- a/src/ctkchart/CTkLineChart.py +++ b/src/ctkchart/CTkLineChart.py @@ -1,2389 +1,1389 @@ -import tkinter -from typing import Union, List, Tuple, Literal, Any, Callable import customtkinter -from .CTkLine import CTkLine -from .ThemeManager import ThemeManager -from .Utils import Utils -from .Validate import Validate - +import tkinter +from .CTkLine import * +from .Utils import * +from .Validate import * +from .FontStyle import * +from typing import Union + + + +class CTkLineChart(): + def __init__(self, master=None, + width: int = 700, + height: int = 400, + axis_size: int = 2, + + axis_color: tuple[str, str] | str = ("#606060" ,"#EEEEEE"), + fg_color: tuple[str, str] | str = ("#FFFFFF" ,"#151515"), + bg_color: tuple[str, str] | str = ("#FFFFFF", "#202020"), + data_font_style: tuple[str, int, str] = ("arial", 12, "normal"), + axis_font_style: tuple[str, int, str] = ("arial", 12, "normal"), + + y_axis_precision: int = 1, + y_axis_data: any = "Y", + y_axis_label_count: int = 5, + y_axis_values: tuple[int | float, int | float] = (None, None), + y_axis_font_color: tuple[str, str] | str = ("#252525", "#909090"), + y_axis_data_font_color: tuple[str, str] | str = ("#252525", "#909090"), + y_axis_data_position: str = "top", + y_axis_section_count: int = 0, + y_axis_section_style: str = "normal", + y_axis_section_style_type: tuple[int, int] = (100, 50), + y_axis_section_color: str = None, + + x_axis_data: str = "X", + x_axis_label_count: int = None, + x_axis_values: tuple[any, ...] = (1, 2, 3, 4, 5), + x_axis_display_values_indices: tuple[int, ...] = None, + x_axis_font_color: tuple[str, str] | str = ("#252525" ,"#909090"), + x_axis_data_font_color: tuple[str, str] | str = ("#252525" ,"#909090"), + x_axis_data_position: str = "top", + x_axis_section_count: int=0, + x_axis_section_style: str = "normal", + x_axis_section_style_type: tuple[int, int] = (100, 50), + x_axis_section_color: str = None, + + line_width: int | str = "auto", + y_space: int = 0, + x_space: int = 0, + + pointer_state: str = "disabled", + pointing_callback_function: callable = None, + pointer_color: tuple[str, str] | str = ("#252525" ,"#AAAAAA"), + pointing_values_precision: int = 1, + pointer_lock: str = "disabled", + pointer_size: int = 4, + *args: any, + + ########DEPRECATED######### + y_axis_max_value:int = None, + section_color:str = None, + ########################### + ) -> None: + + Validate._isInt(height, "height") + Validate._isInt(width, "width") + Validate._isInt(axis_size, "axis_size") + Validate._isInt(y_space, "y_space") + Validate._isInt(x_space, "x_space") + Validate._isInt(y_axis_precision, "y_axis_precision") + Validate._isInt(y_axis_label_count, "y_axis_label_count") + Validate._isInt(y_axis_section_count, "y_axis_section_count") + Validate._isInt(x_axis_section_count, "x_axis_section_count") + Validate._isInt(pointing_values_precision, "pointing_values_precision") + Validate._isInt(pointer_size, "pointer_size") + Validate._isTuple(x_axis_values, "x_axis_values") + ####################################################ENABLE 2024.3.30#################################################### + #Validate._isValidYAxisValues(y_axis_values, "y_axis_values") + #Validate._isValidColor(y_axis_section_color, "y_axis_section_color") + #Validate._isValidColor(x_axis_section_color, "x_axis_section_color") + ####################################################ENABLE 2024.3.30#################################################### + Validate._isValidColor(axis_color, "axis_color") + Validate._isValidColor(fg_color, "fg_color") + Validate._isValidColor(bg_color, "bg_color") + Validate._isValidColor(y_axis_font_color, "y_axis_font_color") + Validate._isValidColor(x_axis_font_color, "x_axis_font_color") + Validate._isValidColor(y_axis_data_font_color, "y_axis_data_font_color") + Validate._isValidColor(x_axis_data_font_color, "x_axis_data_font_color") + Validate._isValidColor(pointer_color, "pointer_color") + Validate._isValidFont(data_font_style, "data_font_style") + Validate._isValidFont(axis_font_style, "axis_font_style") + Validate._isValidDataPostion(y_axis_data_position, "y_axis_data_position") + Validate._isValidDataPostion(x_axis_data_position, "x_axis_data_position") + Validate._isValidStyleType(y_axis_section_style_type, "y_axis_section_style_type") + Validate._isValidStyleType(x_axis_section_style_type, "x_axis_section_style_type") + Validate._isValidSectionStyle(y_axis_section_style, "y_axis_section_style") + Validate._isValidSectionStyle(x_axis_section_style, "x_axis_section_style") + Validate._isValidLineWidth(line_width, "line_width") + Validate._isValidPointerState_Lock(pointer_state, "pointer_state") + Validate._isValidPointerState_Lock(pointer_lock, "pointer_lock") + Validate._isValidFunction(pointing_callback_function, "pointing_callback_function") + Validate._isValidXAxisIndices(x_axis_values, x_axis_display_values_indices, "x_axis_display_values_indices") + Validate._isValidXAxisLabelCount(x_axis_label_count, "x_axis_label_count") + + ####################################################REMOVE 2024.3.30#################################################### + y_axis_values_set_using = "y_axis_values" + if y_axis_max_value != None: + if y_axis_values == (None, None): + y_axis_values_set_using = "y_axis_max_value" + Validate._isValidYAxisMaxValue(y_axis_max_value, "y_axis_max_value") + print(FontStyle._fontStyle("\ny_axis_max_value : ", "red", "black", "normal"), end = "") + print(FontStyle._fontStyle("Parameter is deprecated & not support to configure, it will be removed soon.", "red", "black", "underline")) + print(FontStyle._fontStyle("Use", "red", "black", "underline") + + FontStyle._fontStyle(" y_axis_values ", "green", "black", "italic") + + FontStyle._fontStyle("instead.", "red", "black", "underline")) + else: + Validate._isValidYAxisValues(y_axis_values, "y_axis_values") + elif y_axis_values == (None, None): + y_axis_values = (-10,10) + else: + Validate._isValidYAxisValues(y_axis_values, "y_axis_values") + + section_color_set_using = "y_x_axis_section_color" + if section_color != None: + if x_axis_section_color == None and y_axis_section_color == None: + section_color_set_using = "section_color" + Validate._isValidColor(section_color, "section_color") + print(FontStyle._fontStyle("\nsection_color : ", "red", "black", "normal"), end = "") + print(FontStyle._fontStyle("Parameter is deprecated & not support to configure, it will be removed soon.", "red", "black", "underline")) + print(FontStyle._fontStyle("Use", "red", "black", "underline") + FontStyle._fontStyle(" y_axis_section_color ", "green", "black", "italic") + + FontStyle._fontStyle("&", "red", "black", "underline") + + FontStyle._fontStyle(" x_axis_section_color ", "green", "black", "italic") + + FontStyle._fontStyle("instead.", "red", "black", "underline")) + else: + if x_axis_section_color != None: + Validate._isValidColor(x_axis_section_color, "x_axis_section_color") + else: + x_axis_section_color = ("#606060", "#AAAAAA") + + if y_axis_section_color != None: + Validate._isValidColor(y_axis_section_color, "y_axis_section_color") + else: + y_axis_section_color = ("#606060", "#AAAAAA") + else: + if x_axis_section_color == None: + x_axis_section_color = ("#606060", "#AAAAAA") + else : + Validate._isValidColor(x_axis_section_color, "x_axis_section_color") + + if y_axis_section_color == None: + y_axis_section_color = ("#606060", "#AAAAAA") + else: + Validate._isValidColor(y_axis_section_color, "y_axis_section_color") + ####################################################REMOVE 2024.3.30#################################################### -class CTkLineChart: - def __init__( - self, - master: Any = None, - width: int = 700, - height: int = 400, - axis_size: int = 1, - axis_color: Union[Tuple[str, str], str] = ("#ebebeb", "#2C2C2C"), - fg_color: Union[Tuple[str, str], str] = ("#FFFFFF", "#191919"), - bg_color: Union[Tuple[str, str], str] = ("#FFFFFF", "#191919"), - data_font_style: Tuple[str, int, str] = ("arial", 13, "bold"), - axis_font_style: Tuple[str, int, str] = ("arial", 11, "normal"), + if master != None: + self.master = master + if len(args) > 0: + self.master = args[0] + + self.__height = height + self.__width = width + self.__axis_size = axis_size + self.__axis_color = axis_color + self.__line_width = line_width + self.__line_width_handle_by = "auto" + self.__data_font_style = data_font_style + self.__axis_font_style = axis_font_style + self.__lines = [] + + self.__bg_color = bg_color + self.__fg_color = fg_color + self.__y_axis_font_color = y_axis_font_color + self.__y_axis_data_font_color = y_axis_data_font_color + ####################################################ENABLE 2024.3.30#################################################### + #self.__y_axis_section_color = y_axis_section_color + ####################################################ENABLE 2024.3.30#################################################### + self.__y_axis_section_style = y_axis_section_style + self.__y_axis_section_style_type = y_axis_section_style_type + self.__y_axis_section_count = y_axis_section_count + self.__y_axis_label_count = y_axis_label_count + self.__y_axis_data = y_axis_data + self.__y_axis_data_position = y_axis_data_position + self.__y_axis_values = y_axis_values + + ####################################################ENABLE 2024.3.30#################################################### + #self.__y_axis_min_value = y_axis_values[0] + #self.__y_axis_max_value = y_axis_values[1] + ####################################################ENABLE 2024.3.30#################################################### + + ####################################################REMOVE 2024.3.30#################################################### + if y_axis_values_set_using == "y_axis_values" : + self.__y_axis_min_value = y_axis_values[0] + self.__y_axis_max_value = y_axis_values[1] + else: + if y_axis_max_value>0: + self.__y_axis_min_value = 0 + self.__y_axis_max_value = y_axis_max_value + elif y_axis_max_value <0: + self.__y_axis_max_value = 0 + self.__y_axis_min_value = y_axis_max_value + + if section_color_set_using == "section_color": + self.__y_axis_section_color = section_color + self.__x_axis_section_color = section_color + else: + self.__y_axis_section_color = y_axis_section_color + self.__x_axis_section_color = x_axis_section_color + ####################################################REMOVE 2024.3.30#################################################### + + self.__y_axis_precision = y_axis_precision + self.__y_space = y_space + + self.__x_axis_font_color = x_axis_font_color + self.__x_axis_data_font_color = x_axis_data_font_color + ####################################################ENABLE 2024.3.30#################################################### + #self.__x_axis_section_color = x_axis_section_color + ####################################################ENABLE 2024.3.30#################################################### + self.__x_axis_section_style = x_axis_section_style + self.__x_axis_section_style_type = x_axis_section_style_type + self.__x_axis_section_count = x_axis_section_count + self.__x_axis_label_count = x_axis_label_count + self.__x_axis_display_values_indices = x_axis_display_values_indices + self.__x_labels_values_index_change = 1 + self.__x_axis_data = x_axis_data + self.__x_axis_data_position = x_axis_data_position + self.__x_axis_values = x_axis_values + self.__x_axis_values_handle_by = "auto" + self.__x_space = x_space + + self.__force_to_stop_data_showing = False + self.__is_data_showing_working = False + + self.__pointer_state = pointer_state + self.__pointing_callback_function = pointing_callback_function + self.__pointing_values_precision = pointing_values_precision + self.__pointer_lock = pointer_lock + self.__pointer_size = pointer_size + self.__pointer_color = pointer_color + + self.__place_x = 0 + self.__real_height = 0 + self.__real_width = 0 + self.__const_real_height = 0 + self.__const_real_width = 0 + + self.__place_info_x = 0 + self.__place_info_y = 0 + self.__place_info_rely = 0 + self.__place_info_relx = 0 + self.__place_info_anchor = 0 + + self.__pack_info_pady = 0 + self.__pack_info_padx = 0 + self.__pack_info_before = 0 + self.__pack_info_after = 0 + self.__pack_info_side = 0 + self.__pack_info_anchor = 0 + + self.__grid_info_column = 0 + self.__grid_info_columnspan = 0 + self.__grid_info_padx = 0 + self.__grid_info_pady = 0 + self.__grid_info_row = 0 + self.__grid_info_rowspan = 0 + self.__grid_info_sticky = 0 + + + if self.__line_width == "auto": + self.__line_width_handle_by = "auto" + else: + self.__line_width_handle_by = "manual" + + if self.__x_axis_display_values_indices != None : + self.__x_axis_display_values_indices = Utils._sort_tuple(self.__x_axis_display_values_indices) + self.__x_axis_values_handle_by = "label_indices" + elif self.__x_axis_label_count != None: + self.__x_axis_values_handle_by = "label_count" + else: + self.__x_axis_values_handle_by = "auto" + + + self.__theme = "unknown" - y_axis_precision: int = 0, - y_axis_data: Any = "Y", - y_axis_label_count: int = 1, - y_axis_values: Tuple[Union[int, float], Union[int, float]] = (None, None), - y_axis_font_color: Union[Tuple[str, str], str] = ("#AAAAAA", "#606060"), - y_axis_data_font_color: Union[Tuple[str, str], str] = ("#999999", "#707070"), - y_axis_data_position: Literal["top", "side"] = "top", - y_axis_section_count: int = 0, - y_axis_section_style: Literal["normal", "dashed"] = "normal", - y_axis_section_style_type: Tuple[int, int] = (100, 50), - y_axis_section_color: Union[Tuple[str, str], str] = ("#EBEBEB", "#2C2C2C"), + self.__create_widgets() + + self.__configure_required_widget_size() + self.__configure_x_axis_labels_info() + self.__configure_line_width() + + self.__create_x_axis_labels() + self.__set_x_axis_values() + + self.__create_y_axis_labels() + self.__set_y_axis_values() + + self.__create_y_axis_sections() + self.__create_x_axis_sections() + + self.__set_x_y_axis_data_texts() + + self.__set_pointer_state() + self.__set_pointer_size() + + self.__set_widgets_fonts() + self.__set_widgets_colors() + + self.__place_widgets() + self.__reset_chart_info() + + self.__track_theme_changes() + + + def __track_theme_changes(self) -> None: + def __track_theme_changes_loop(): + if self.__theme != customtkinter.get_appearance_mode(): + self.__theme = customtkinter.get_appearance_mode() + self.__configure_widget_for_theme_changes() + self.__call_reshow_data() + self.master.after(1000,__track_theme_changes_loop) + __track_theme_changes_loop() + + + def __configure_widget_for_theme_changes(self) -> None: + self.__output_canvas.configure(bg=self.__get_color_by_theme(self.__fg_color)) + self.__pointer.configure(bg=self.__get_color_by_theme(self.__pointer_color)) + self.__destroy_x_y_sections() + self.__create_y_axis_sections() + self.__create_x_axis_sections() + + + def __create_widgets(self) -> None: + self.__main_frame = customtkinter.CTkFrame(master=self.master) + self.__y_axis_frame = customtkinter.CTkFrame(master=self.__main_frame) + self.__x_axis_frame = customtkinter.CTkFrame(master=self.__main_frame) + self.__x_axis_values_frame = customtkinter.CTkFrame(master=self.__main_frame) + self.__y_axis_values_frame = customtkinter.CTkFrame(master=self.__main_frame) + self.__y_axis_data_label = customtkinter.CTkLabel(master=self.__main_frame) + self.__x_axis_data_label = customtkinter.CTkLabel(master=self.__main_frame) + self.__output_frame = customtkinter.CTkFrame(master=self.__main_frame) + self.__output_canvas = customtkinter.CTkCanvas(master=self.__output_frame, highlightthickness=0) + self.__pointer = tkinter.Frame(master=self.__output_canvas) + + + def __set_pointer_state(self) -> None: + if self.__pointer_state == "enabled": + self.__output_canvas.bind("",self.__hide_pointer) + self.__output_canvas.bind("",self.__return_pointed_values) + elif self.__pointer_state == "disabled": + self.__output_canvas.unbind("") + self.__output_canvas.unbind("") + + + def __set_widgets_colors(self) -> None: + self.__y_axis_frame.configure(fg_color=self.__axis_color, bg_color=self.__bg_color) + self.__x_axis_frame.configure(fg_color=self.__axis_color, bg_color=self.__bg_color) + self.__y_axis_values_frame.configure(fg_color=self.__bg_color, bg_color=self.__bg_color) + self.__x_axis_values_frame.configure(fg_color=self.__bg_color, bg_color=self.__bg_color) + + + self.__main_frame.configure(fg_color=self.__bg_color) + self.__output_frame.configure(fg_color=self.__fg_color, bg_color=self.__bg_color) + #self.__output_canvas.configure(bg=self.__fg_color) + + self.__y_axis_data_label.configure(fg_color=self.__bg_color, bg_color=self.__bg_color, text_color=self.__y_axis_data_font_color) + for label in self.__x_axis_values_frame.winfo_children() : + if type(label) == customtkinter.CTkLabel: + label.configure(fg_color=self.__bg_color, bg_color=self.__bg_color, text_color=self.__x_axis_font_color) + + self.__x_axis_data_label.configure(fg_color=self.__bg_color, bg_color=self.__bg_color, text_color=self.__x_axis_data_font_color) + for label in self.__y_axis_values_frame.winfo_children(): + if type(label) == customtkinter.CTkLabel: + label.configure(fg_color=self.__bg_color, bg_color=self.__bg_color, text_color=self.__y_axis_font_color) + + + self.__pointer.configure(bg=self.__get_color_by_theme(self.__pointer_color)) + + + def __set_widgets_fonts(self) -> None: + self.__y_axis_data_label.configure(font=self.__data_font_style) + self.__x_axis_data_label.configure(font=self.__data_font_style) + + for label in self.__y_axis_values_frame.winfo_children() : + if type(label) == customtkinter.CTkLabel: + label.configure(font=self.__axis_font_style) + + for label in self.__x_axis_values_frame.winfo_children() : + if type(label) == customtkinter.CTkLabel: + label.configure(font=self.__axis_font_style) - x_axis_data: str = "X", - x_axis_label_count: int = None, - x_axis_values: Tuple[Any, ...] = (None, "None", None, "None"), - x_axis_display_values_indices: Tuple[int, ...] = None, - x_axis_font_color: Union[Tuple[str, str], str] = ("#AAAAAA", "#606060"), - x_axis_data_font_color: Union[Tuple[str, str], str] = ("#999999", "#707070"), - x_axis_data_position: Literal["top", "side"] = "top", - x_axis_section_count: int = 0, - x_axis_section_style: Literal["normal", "dashed"] = "normal", - x_axis_section_style_type: Tuple[int, int] = (100, 50), - x_axis_section_color: Union[Tuple[str, str], str] = ("#ebebeb", "#2c2c2c"), - x_axis_point_spacing: Union[int, float, Literal["auto"]] = "auto", - y_space: int = 0, - x_space: int = 0, + def __set_pointer_size(self) -> None: + self.__pointer.configure(width=self.__pointer_size) + self.__pointer.configure(height=self.__const_real_height) + + + def __place_widgets(self) -> None: + self.__main_frame.configure(width=self.__width, height=self.__height) + + self.__y_axis_data_label.place_forget() + self.__x_axis_data_label.place_forget() + if self.__y_axis_data_position=="top": + self.__y_axis_data_label.place(x=0, y=0) + else: + self.__y_axis_data_label.place(x=0, y=self.__y_space+self.__y_special_height_space+self.__real_height/2,anchor="w") + if self.__x_axis_data_position=="top": + self.__x_axis_data_label.place(rely=1, relx=1, x=-self.__x_axis_data_req_width, y=-self.__x_axis_data_req_height) + else: + self.__x_axis_data_label.place(rely=1, y=-self.__x_axis_data_req_height, relx=0, anchor="n", + x=(self.__real_width/2)+self.__y_axis_data_req_width_space_side+self.__y_value_req_width_space+self.__axis_size+self.__x_axis_data_req_width_space_top+self.__x_special_width_space) + + self.__y_axis_frame.configure(width=self.__axis_size) + self.__x_axis_frame.configure(height=self.__axis_size) + - pointer_state: Literal["enabled", "disabled"] = "disabled", - pointing_callback_function: Callable = None, - pointer_color: Union[Tuple[str, str], str] = ("#CCCCCC", "#606060"), - pointing_values_precision: int = 1, - pointer_lock: Literal["enabled", "disabled"] = "disabled", - pointer_size: int = 1, + self.__y_axis_frame.place(x=self.__y_value_req_width_space+self.__y_axis_data_req_width_space_side, + y=float(self.__y_axis_data_req_height_space_top+(self.__y_value_req_height_space/2)+self.__y_special_height_space), + ) + self.__y_axis_frame.configure(height=self.__const_real_height+self.__y_space+self.__axis_size) + self.__x_axis_frame.place(x=self.__y_value_req_width_space+self.__y_axis_data_req_width_space_side, + rely=1, + y=-self.__axis_size+-self.__x_value_req_height_space+-self.__x_axis_data_req_height_space_side, + ) + self.__x_axis_frame.configure(width=self.__const_real_width+self.__axis_size+self.__x_space) + + self.__output_frame.place(x=self.__y_value_req_width_space+self.__axis_size+self.__y_axis_data_req_width_space_side, + y=float(self.__y_axis_data_req_height_space_top+(self.__y_value_req_height_space/2)+self.__y_special_height_space+self.__y_space)) + self.__output_frame.configure( width=self.__const_real_width, + height=self.__const_real_height,) + + self.__output_canvas.place(y=0, x=0) + self.__output_canvas.configure(height=self.__const_real_height, width=self.__const_real_width) + + self.__y_axis_values_frame.place(x=self.__y_axis_data_req_width_space_side) + self.__y_axis_values_frame.configure(width=self.__y_value_req_width_space, height=self.__height) + self.__x_axis_values_frame.place(x=0, rely=1, y=-self.__x_value_req_height_space+-self.__x_axis_data_req_height_space_side) + self.__x_axis_values_frame.configure(height=self.__x_value_req_height_space, width=self.__width) + + + def __configure_line_width(self) -> None: + if self.__line_width_handle_by== "auto": + self.__line_width = (self.__real_width / len(self.__x_axis_values)) + elif self.__line_width_handle_by== "manual": + self.__line_width = self.__line_width + + + def __configure_required_widget_size(self) -> None: + self.__x_axis_data_req_width_space_top = 0 + self.__x_axis_data_req_height_space_side = 0 + self.__x_axis_data_req_height = Utils._RequiredHeight(text=self.__x_axis_data, font=self.__data_font_style) + self.__x_axis_data_req_width = Utils._RequiredWidth(text=self.__x_axis_data, font=self.__data_font_style) + self.__x_special_width_space = 0 + if self.__x_axis_data_position == "top": + self.__x_special_width_space = 30 + self.__x_axis_data_req_width_space_top = Utils._RequiredWidth(text=self.__x_axis_data, font=self.__data_font_style) + else: + self.__x_axis_data_req_height_space_side = Utils._RequiredHeight(text=self.__x_axis_data, font=self.__data_font_style) + + self.__y_axis_data_req_height_space_top = 0 + self.__y_axis_data_req_height = Utils._RequiredHeight(text=self.__y_axis_data, font=self.__data_font_style) + self.__y_axis_data_req_width = Utils._RequiredWidth(text=self.__y_axis_data, font=self.__data_font_style) + self.__y_special_height_space = 0 + self.__y_axis_data_req_width_space_side = 0 + if self.__y_axis_data_position == "top": + self.__y_special_height_space = 30 + self.__y_axis_data_req_height_space_top = Utils._RequiredHeight(text=self.__y_axis_data[0], font=self.__data_font_style) + else: + self.__y_axis_data_req_width_space_side = Utils._RequiredWidth(text=self.__y_axis_data[0], font=self.__data_font_style) + + if self.__y_axis_label_count == 0: + self.__y_value_req_height_space = 1 + self.__y_value_req_width_space = 1 + else: + if len(Utils._format_float_with_precision(self.__y_axis_max_value, self.__y_axis_precision)) > len(Utils._format_float_with_precision(self.__y_axis_min_value, self.__y_axis_precision)) : + y_value_temp = self.__y_axis_max_value + else: + y_value_temp = self.__y_axis_min_value + self.__y_value_req_height_space = Utils._RequiredHeight(text=Utils._format_float_with_precision(y_value_temp, self.__y_axis_precision), font=self.__axis_font_style) + self.__y_value_req_width_space = Utils._RequiredWidth(text=Utils._format_float_with_precision(y_value_temp, self.__y_axis_precision), font=self.__axis_font_style) + + self.__x_value_req_height_space = Utils._RequiredHeight(text=self.__x_axis_values[0], font=self.__axis_font_style) + #self.__x_value_req_width_space = RequiredWidth(text=format_float_with_precision(self.__x_axis_data_max, self.__x_values_decimals), font=self.__axis_font_style) + self.__x_value_req_width_space = Utils._get_max_required_label_width(data=self.__x_axis_values, font=self.__axis_font_style) + + self.__real_width = self.__width - (self.__y_value_req_width_space+self.__axis_size+self.__x_axis_data_req_width_space_top+self.__y_axis_data_req_width_space_side+\ + (self.__x_value_req_width_space/2)+self.__x_special_width_space+self.__x_space) + + self.__const_real_width = self.__real_width + self.__real_height = self.__height - (self.__y_axis_data_req_height_space_top+self.__axis_size+self.__x_value_req_height_space+self.__x_axis_data_req_height_space_side+\ + (self.__y_value_req_height_space/2)+self.__y_special_height_space+self.__y_space) + self.__real_height = self.__real_height + + self.__const_real_height = int(self.__real_height) + + self.__y_axis_values_gap = abs(self.__y_axis_max_value - self.__y_axis_min_value) + - *args: Any) -> None: + def __set_x_y_axis_data_texts(self) -> None: + if self.__y_axis_data_position=="top": + self.__y_axis_data_label.configure(text=self.__y_axis_data) + else: + self.__y_axis_data_label.configure(text="\n".join(self.__y_axis_data)) + self.__x_axis_data_label.configure(text=self.__x_axis_data) + + + def __set_y_axis_values(self) -> None: + if self.__y_axis_label_count>0: + for i,label in enumerate(self.__y_axis_values_frame.winfo_children()): + value = (self.__y_axis_max_value - ((self.__y_axis_values_gap)/self.__y_axis_label_count)*i) + if self.__y_axis_min_value == 0 and i==self.__y_axis_label_count: + value = 0 + value = Utils._format_float_with_precision(value,self.__y_axis_precision) + label.configure(text=value) + + def __create_y_axis_labels(self) -> None: + if self.__y_axis_label_count>0: + y = self.__y_axis_data_req_height_space_top+(self.__y_value_req_height_space/2)+self.__y_special_height_space+self.__y_space + for i in range(self.__y_axis_label_count+1): + customtkinter.CTkLabel(master=self.__y_axis_values_frame, justify="right", width=self.__y_value_req_width_space).place(y=y, x=0, + anchor="w") + y += self.__real_height/self.__y_axis_label_count + + + def __destroy_y_axis_labels(self) -> None: + for y_value in self.__y_axis_values_frame.winfo_children(): + y_value.place_forget() + y_value.destroy() + + + def __set_x_axis_values_using_label_count(self) -> None: + index = -1 + for label in (self.__x_axis_values_frame.winfo_children()): + value = self.__x_axis_values[index] + index -= self.__x_labels_values_index_change + label.configure(text=value) + + + def __set_x_axis_values_using_indices(self) -> None: + index = -1 + for label in (self.__x_axis_values_frame.winfo_children()): + value = self.__x_axis_values[self.__x_axis_display_values_indices[index]] + index -= 1 + label.configure(text=value) + - """ - Initialize the CTkLineChart. + def __create_x_axis_labels_using_label_count(self) -> None: + x = self.__width - self.__x_axis_data_req_width_space_top-(self.__x_value_req_width_space/2)-self.__x_special_width_space - self.__x_space + for i in range(self.__x_axis_label_count): + customtkinter.CTkLabel(master=self.__x_axis_values_frame).place(rely=1, y=-self.__x_value_req_height_space, x=x, anchor="n") + x -= self.__const_real_width / self.__x_axis_label_count + + + def __create_x_axis_labels_using_indices(self) -> None: + x = self.__width - self.__x_axis_data_req_width_space_top-(self.__x_value_req_width_space/2)-self.__x_special_width_space - self.__x_space + for i in range(self.__x_axis_label_count): + if (self.__x_axis_label_count-(i+1)) in self.__x_axis_display_values_indices: + customtkinter.CTkLabel(master=self.__x_axis_values_frame).place(rely=1, y=-self.__x_value_req_height_space, x=x, anchor="n") + x -= self.__const_real_width / self.__x_axis_label_count + + + def __create_x_axis_labels(self) -> None: + if self.__x_axis_values_handle_by == "label_indices": + self.__create_x_axis_labels_using_indices() + else: + self.__create_x_axis_labels_using_label_count() + + + def __set_x_axis_values(self) -> None: + if self.__x_axis_values_handle_by == "label_indices": + self.__set_x_axis_values_using_indices() + else: + self.__set_x_axis_values_using_label_count() + + + def __destroy_x_axis_labels(self) -> None: + for x_value in self.__x_axis_values_frame.winfo_children(): + x_value.place_forget() + x_value.destroy() + + + def __configure_x_axis_labels_info(self) -> None: + if self.__x_axis_values_handle_by == "label_indices" : + self.__x_axis_label_count = len(self.__x_axis_values) + + elif self.__x_axis_values_handle_by=="auto": + self.__x_axis_label_count=len(self.__x_axis_values) + self.__x_labels_values_index_change = 1 + + elif self.__x_axis_values_handle_by=="label_count": + if self.__x_axis_label_count == 0: + return + x_axis_real_label_count = len(self.__x_axis_values) + if self.__x_axis_label_count > x_axis_real_label_count: + self.__x_axis_label_count = x_axis_real_label_count + while x_axis_real_label_count%self.__x_axis_label_count != 0: + self.__x_axis_label_count+=1 + self.__x_labels_values_index_change = int(x_axis_real_label_count/self.__x_axis_label_count) + + + def __create_y_axis_sections(self) -> None: + y = 0 + bg = self.__get_color_by_theme(self.__y_axis_section_color) + if self.__y_axis_section_style == "normal": + for i in range(self.__y_axis_section_count): + tkinter.Frame(master=self.__output_frame, + height=1, + width=self.__const_real_width, + bg = bg, + ).place(y=y, anchor="w") + y += self.__real_height/self.__y_axis_section_count + else: + width_ = self.__y_axis_section_style_type[0] + space_ = self.__y_axis_section_style_type[1] + for i in range(self.__y_axis_section_count): + x_ = self.__const_real_width-width_ + while x_ > -(width_+space_) : + tkinter.Frame(master=self.__output_frame, + height=1, + width=width_, + bg=bg).place(y=y, anchor="w", x=x_) + x_ -= width_ + space_ + y += self.__real_height/self.__y_axis_section_count + + + def __create_x_axis_sections(self) -> None: + x = self.__const_real_width - 1 + bg = self.__get_color_by_theme(self.__x_axis_section_color) + if self.__x_axis_section_style == "normal": + for i in range(self.__x_axis_section_count): + tkinter.Frame(master=self.__output_frame, + height=self.__const_real_height, + width=1, + bg=bg).place(x=x, anchor="n") + x -= (self.__const_real_width / self.__x_axis_section_count) + else: + height_ = self.__x_axis_section_style_type[0] + space_ = self.__x_axis_section_style_type[1] + for i in range(self.__x_axis_section_count): + y_ = 0 + while y_ < self.__const_real_height : + tkinter.Frame(master=self.__output_frame, + height=height_, + width=1, + bg=bg, + ).place(x=x, anchor="n", y=y_) + y_ += height_ + space_ + x -= (self.__const_real_width / self.__x_axis_section_count) + - Args: - master (Any): The master widget. - width (int): The width of the chart canvas. - height (int): The height of the chart canvas. - axis_size (int): The size of the chart axis. + def __destroy_x_y_sections(self) -> None: + for widget in self.__output_frame.winfo_children(): + if type(widget) == tkinter.Frame : + widget.place_forget() + widget.destroy() + + + def configure(self, + width: int = None, + height: int = None, + axis_size: int = None, + line_width: int | str = None, + + fg_color: tuple[str, str] | str = None, + axis_color: tuple[str, str] | str = None, + bg_color: tuple[str, str] | str = None, + data_font_style: tuple[str, int, str] = None, + axis_font_style: tuple[str, int, str] = None, - axis_color (Union[Tuple[str, str], str]): The color of the chart axis. - fg_color (Union[Tuple[str, str], str]): The foreground color of the chart. - bg_color (Union[Tuple[str, str], str]): The background color of the chart. - data_font_style (Tuple[str, int, str]): The font style for data labels. - axis_font_style (Tuple[str, int, str]): The font style for axis labels. + y_axis_values: int | float=None, + y_axis_precision: int = None, + y_axis_font_color: tuple[str, str] | str = None, + y_axis_data_font_color: tuple[str, str] | str = None, + y_axis_section_count: int = None, + y_axis_section_color: tuple[str, str] | str = None, + y_axis_section_style: str = None, + y_axis_section_style_type: tuple[int, int] = None, + y_axis_label_count: int=None, + y_axis_data: any = None, + y_axis_data_position: str = None, + y_space: int = None, + + x_axis_values: tuple[any, ...] = None, + x_axis_data: any = None, + x_axis_font_color: tuple[str, str] | str = None, + x_axis_data_font_color: tuple[str, str] | str = None, + x_axis_label_count: int = None, + x_axis_section_count: int = None, + x_axis_section_style: str = None, + x_axis_section_style_type: tuple[int, int] = None, + x_axis_section_color: tuple[str, str] | str = None, + x_axis_display_values_indices: tuple[int, ...] = None, + x_axis_data_position: str = None, + x_space: int = None , + + pointer_state: str = None, + pointing_values_precision: int = None, + pointer_color: tuple[str, str] | str = None, + pointer_lock: str = None, + pointing_callback_function: callable = None, + pointer_size: int = None + ) -> None: + + chart_reset_req = False + widget_color_change_req = False + widget_size_change_req = False + widget_font_change_req = False + chart_y_values_change_req = False + chart_x_values_change_req = False + chart_sections_change_req = False + chart_sections_color_change_req = False + chart_x_labels_change_req = False + chart_y_labels_change_req = False + pointer_state_change_req = False + pointer_size_change_req = False + reshow_data_req = False + + if width != None: + Validate._isInt(width, "width") + if width != self.__width: + self.__width = width + chart_reset_req = True + + if height != None: + Validate._isInt(height, "height") + if height != self.__height: + self.__height = height + chart_reset_req = True - y_axis_precision (int): The precision of the y-axis values. - y_axis_data (Any): The label for the y-axis. - y_axis_label_count (int): The number of labels on the y-axis. - y_axis_values (Tuple[Union[int, float], Union[int, float]]): The range of values for the y-axis. - y_axis_font_color (Union[Tuple[str, str], str]): The font color for y-axis labels. - y_axis_data_font_color (Union[Tuple[str, str], str]): The font color for y-axis data labels. - y_axis_data_position (str): The position of y-axis data labels. - y_axis_section_count (int): The number of sections on the y-axis. - y_axis_section_style (str): The style of sections on the y-axis. - y_axis_section_style_type (Tuple[int, int]): The style type of sections on the y-axis. - y_axis_section_color (Union[Tuple[str, str], str]): The color of sections on the y-axis. + if y_space != None: + Validate._isInt(y_space, "y_space") + if y_space != self.__y_space: + self.__y_space = y_space + chart_reset_req = True + + if x_space != None: + Validate._isInt(x_space, "x_space") + if x_space != self.__x_space: + self.__x_space = x_space + chart_reset_req = True + + if y_axis_values != None: + Validate._isValidYAxisValues(y_axis_values, "y_axis_values") + if y_axis_values != self.__y_axis_values: + self.__y_axis_values = y_axis_values + self.__y_axis_min_value = y_axis_values[0] + self.__y_axis_max_value = y_axis_values[1] + chart_reset_req = True + + if axis_size != None: + Validate._isInt(axis_size, "axis_size") + if axis_size != self.__axis_size: + self.__axis_size = axis_size + chart_reset_req = True + + if y_axis_precision != None: + Validate._isInt(y_axis_precision, "y_axis_precision") + if y_axis_precision != self.__y_axis_precision: + self.__y_axis_precision = y_axis_precision + chart_reset_req = True + + if x_axis_data != None: + if x_axis_data != self.__x_axis_data: + self.__x_axis_data = x_axis_data + chart_reset_req = True - x_axis_data (str): The label for the x-axis. - x_axis_label_count (int): The number of labels on the x-axis. - x_axis_values (Tuple[Any, ...]): The values for the x-axis labels. - x_axis_display_values_indices (Tuple[int, ...]): The indices to display values on the x-axis. - x_axis_font_color (Union[Tuple[str, str], str]): The font color for x-axis labels. - x_axis_data_font_color (Union[Tuple[str, str], str]): The font color for x-axis data labels. - x_axis_data_position (str): The position of x-axis data labels. - x_axis_section_count (int): The number of sections on the x-axis. - x_axis_section_style (str): The style of sections on the x-axis. - x_axis_section_style_type (Tuple[int, int]): The style type of sections on the x-axis. - x_axis_section_color (Union[Tuple[str, str], str]): The color of sections on the x-axis. + if data_font_style != None: + Validate._isValidFont(data_font_style, "data_font_style") + if data_font_style != self.__data_font_style: + self.__data_font_style = data_font_style + chart_reset_req = True - x_axis_point_spacing (Union[int, str]): Spacing between x-axis points. - x_space: The space between x-axis labels and the edge of the canvas. - y_space: The space between y-axis labels and the edge of the canvas. + if axis_font_style != None: + Validate._isValidFont(axis_font_style, "axis_font_style") + if axis_font_style != self.__axis_font_style: + self.__axis_font_style = axis_font_style + chart_reset_req = True + + if fg_color != None: + Validate._isValidColor(fg_color, "fg_color") + if fg_color != self.__fg_color: + self.__fg_color = fg_color + widget_color_change_req = True - pointer_state: The initial state of the pointer ('disabled' or 'enabled'). - pointing_callback_function: A callback function to be called when pointing to a data point. - pointer_color: The color of the pointer, specified as a tuple of two colors or a single color string. - pointing_values_precision: The precision for the values displayed when pointing to data points. - pointer_lock: The lock state of the pointer ('disabled' or 'enabled'). - pointer_size: The size of the pointer. - """ - - Validate._isInt(height, "height") - Validate._isInt(width, "width") - Validate._isInt(axis_size, "axis_size") - Validate._isInt(y_space, "y_space") - Validate._isInt(x_space, "x_space") - Validate._isInt(y_axis_precision, "y_axis_precision") - Validate._isInt(y_axis_label_count, "y_axis_label_count") - Validate._isInt(y_axis_section_count, "y_axis_section_count") - Validate._isInt(x_axis_section_count, "x_axis_section_count") - Validate._isInt(pointing_values_precision, "pointing_values_precision") - Validate._isInt(pointer_size, "pointer_size") - Validate._isValidXAxisValues(x_axis_values, "x_axis_values") - Validate._isValidYAxisValues(y_axis_values, "y_axis_values") - Validate._isValidColor(y_axis_section_color, "y_axis_section_color") - Validate._isValidColor(x_axis_section_color, "x_axis_section_color") - Validate._isValidColor(axis_color, "axis_color") - Validate._isValidColor(fg_color, "fg_color") - Validate._isValidColor(bg_color, "bg_color") - Validate._isValidColor(y_axis_font_color, "y_axis_font_color") - Validate._isValidColor(x_axis_font_color, "x_axis_font_color") - Validate._isValidColor(y_axis_data_font_color, "y_axis_data_font_color") - Validate._isValidColor(x_axis_data_font_color, "x_axis_data_font_color") - Validate._isValidColor(pointer_color, "pointer_color") - Validate._isValidFont(data_font_style, "data_font_style") - Validate._isValidFont(axis_font_style, "axis_font_style") - Validate._isValidDataPostion(y_axis_data_position, "y_axis_data_position") - Validate._isValidDataPostion(x_axis_data_position, "x_axis_data_position") - Validate._isValidStyleType(y_axis_section_style_type, "y_axis_section_style_type") - Validate._isValidStyleType(x_axis_section_style_type, "x_axis_section_style_type") - Validate._isValidSectionStyle(y_axis_section_style, "y_axis_section_style") - Validate._isValidSectionStyle(x_axis_section_style, "x_axis_section_style") - Validate._isValidXAxisPointSpacing(x_axis_point_spacing, "x_axis_point_spacing") - Validate._isValidPointerState_Lock(pointer_state, "pointer_state") - Validate._isValidPointerState_Lock(pointer_lock, "pointer_lock") - Validate._isValidFunction(pointing_callback_function, "pointing_callback_function") - Validate._isValidXAxisIndices(x_axis_values, x_axis_display_values_indices, "x_axis_display_values_indices") - Validate._isValidXAxisLabelCount(x_axis_label_count, "x_axis_label_count") - - if master is not None: - self.__master = master - elif len(args) != 0: - self.__master = args[0] - else: - self.__master = master - - self.__height: int = height - self.__width: int = width - self.__axis_size: int = axis_size - self.__axis_color: Union[Tuple[str, str], str] = axis_color - self.__x_axis_point_spacing: Union[int, float, Literal["auto"]] = x_axis_point_spacing - self.__x_axis_point_spacing_handle_by: str = "auto" - self.__data_font_style: Tuple[str, int, str] = data_font_style - self.__axis_font_style: Tuple[str, int, str] = axis_font_style - self.__lines: List[CTkLine] = [] - self.__bg_color: Union[Tuple[str, str], str] = bg_color - self.__fg_color: Union[Tuple[str, str], str] = fg_color - self.__y_axis_font_color: Union[Tuple[str, str], str] = y_axis_font_color - self.__y_axis_data_font_color: Union[Tuple[str, str], str] = y_axis_data_font_color - self.__y_axis_section_color: Union[Tuple[str, str], str] = y_axis_section_color - self.__y_axis_section_style: Literal["normal", "dashed"] = y_axis_section_style - self.__y_axis_section_style_type: Tuple[int, int] = y_axis_section_style_type - self.__y_axis_section_count: int = y_axis_section_count - self.__y_axis_label_count: int = y_axis_label_count - self.__y_axis_data = str(y_axis_data) - self.__y_axis_data_position: Literal["top", "side"] = y_axis_data_position - self.__y_axis_values: Tuple[Union[int, float], Union[int, float]] = y_axis_values - self.__y_axis_min_value: Union[int, float] = y_axis_values[0] - self.__y_axis_max_value: Union[int, float] = y_axis_values[1] - self.__y_axis_precision: int = y_axis_precision - self.__y_space: int = y_space - self.__x_axis_font_color: Union[Tuple[str, str], str] = x_axis_font_color - self.__x_axis_data_font_color: Union[Tuple[str, str], str] = x_axis_data_font_color - self.__x_axis_section_color: Union[Tuple[str, str], str] = x_axis_section_color - self.__x_axis_section_style: Literal["normal", "dashed"] = x_axis_section_style - self.__x_axis_section_style_type: Tuple[int, int] = x_axis_section_style_type - self.__x_axis_section_count: int = x_axis_section_count - self.__x_axis_label_count: int = x_axis_label_count - self.__x_axis_display_values_indices: Tuple[int, ...] = x_axis_display_values_indices - self.__x_labels_values_index_change: int = 1 - self.__x_axis_data: str = str(x_axis_data) - self.__x_axis_data_position: Literal["top", "side"] = x_axis_data_position - self.__x_axis_values: Tuple[Any, ...] = x_axis_values - self.__x_axis_values_handle_by: str = "label_count" - self.__x_space: int = x_space - self.__pointer_state: Literal["enabled", 'disabled'] = pointer_state - self.__pointing_callback_function: Callable = pointing_callback_function - self.__pointing_values_precision: int = pointing_values_precision - self.__pointer_lock: Literal["enabled", 'disabled'] = pointer_lock - self.__pointer_size: int = pointer_size - self.__pointer_color: Union[Tuple[str, str], str] = pointer_color - self.__x_values_frame_place_req: bool = True - self.__y_values_frame_place_req: bool = True - - self.__place_x: int = 0 - self.__real_height: int = 0 - self.__real_width: int = 0 - self.__const_real_height: int = 0 - self.__const_real_width: int = 0 - self.__visibility: bool = True - - self.__place_info_x: Union[int, None] = None - self.__place_info_y: Union[int, None] = None - self.__place_info_rely: Union[int, float, None] = None - self.__place_info_relx: Union[int, float, None] = None - self.__place_info_anchor: Literal["n", "e", "s", "w", "ne", "nw", "se", "sw", "center", None] = None - - self.__pack_info_pady: Union[int, None] = None - self.__pack_info_padx: Union[int, None] = None - self.__pack_info_before: Any = None - self.__pack_info_after: Any = None - self.__pack_info_side: Literal["top", "bottom", "left", "right", None] = None - self.__pack_info_anchor: Literal["n", "e", "s", "w", "ne", "nw", "se", "sw", "center", None] = None - - self.__grid_info_column: Union[int, None] = None - self.__grid_info_columnspan: Union[int, None] = None - self.__grid_info_padx: Union[int, None] = None - self.__grid_info_pady: Union[int, None] = None - self.__grid_info_row: Union[int, None] = None - self.__grid_info_rowspan: Union[int, None] = None - self.__grid_info_sticky: Literal["n", "e", "s", "w", "ne", "nw", "se", "sw", None] = None - - if self.__x_axis_point_spacing == "auto": - self.__x_axis_point_spacing_handle_by = "auto" - else: - self.__x_axis_point_spacing_handle_by = "manual" - - if self.__x_axis_display_values_indices is not None: - self.__x_axis_display_values_indices = Utils._sort_tuple(self.__x_axis_display_values_indices) - self.__x_axis_values_handle_by = "label_indices" - else: - self.__x_axis_values_handle_by = "label_count" - - self.__theme: str = customtkinter.get_appearance_mode() - self.__margin: int = 10 - - self.__create_widgets() - self.__configure_required_widget_size() - self.__configure_x_axis_labels_info() - self.__configure_x_axis_point_spacing() - self.__create_x_axis_labels() - self.__set_x_axis_values() - self.__create_y_axis_labels() - self.__set_y_axis_values() - self.__create_y_axis_sections() - self.__create_x_axis_sections() - self.__set_x_y_axis_data_texts() - self.__set_pointer_state() - self.__set_pointer_size() - self.__set_widgets_fonts() - self.__set_customtkinter_widgets_colors() - self.__set_tkinter_widgets_colors() - self.__place_widgets() - self.__reset_chart_info() - self.__configure_theme_mode() - self.__configure_theme_management() - - def __configure_theme_management(self): - """ - Initialize Theme manager (if not already initialized)and bind the widget to it - """ - - ThemeManager.bind_widget(self) - if ThemeManager.running_state is not True: - ThemeManager.run() - - def __configure_theme_mode(self) -> None: - """ - Configure the widget appearance to match changes in the theme. - - This method adjusts the colors and sections of the widget to match the current theme. - """ - - self.__set_tkinter_widgets_colors() - self.__destroy_x_y_sections() - self.__create_y_axis_sections() - self.__create_x_axis_sections() - self.__reshow_data() - - def __create_widgets(self) -> None: - """ - Create widgets for the CTkLineChart. - - This method initializes the main frame along with frames for the y-axis, x-axis, - y-axis values, x-axis values, y-axis data label, x-axis data label, output frame, - output canvas, and pointer. - """ - - self.__main_frame = customtkinter.CTkFrame(master=self.__master) - self.__x_axis_values_frame = customtkinter.CTkFrame(master=self.__main_frame) - self.__y_axis_values_frame = customtkinter.CTkFrame(master=self.__main_frame) - self.__y_axis_data_label = customtkinter.CTkLabel(master=self.__main_frame) - self.__x_axis_data_label = customtkinter.CTkLabel(master=self.__main_frame) - self.__output_frame = customtkinter.CTkFrame(master=self.__main_frame) - self.__output_canvas = tkinter.Canvas(master=self.__output_frame, highlightthickness=0) - self.__y_axis_frame = tkinter.Frame(master=self.__main_frame) - self.__x_axis_frame = tkinter.Frame(master=self.__main_frame) - self.__pointer = tkinter.Frame(master=self.__output_canvas) - - def __set_pointer_state(self) -> None: - """ - Set the state of the pointer. - - This method configures the behavior of the pointer based on its state (enabled or disabled). - If the pointer is enabled, it binds events for mouse movement to display pointed values. - If the pointer is disabled, it unbinds those events. - """ - - if self.__pointer_state == "enabled": - self.__output_canvas.bind("", self.__hide_pointer) - self.__output_canvas.bind("", self.__return_pointed_values) - elif self.__pointer_state == "disabled": - self.__output_canvas.unbind("") - self.__output_canvas.unbind("") - - def __set_tkinter_widgets_colors(self): - """ - Set the colors of Tkinter widgets based on the current theme. - - This method adjusts the background colors of various Tkinter widgets based on the current theme. - """ - - self.__y_axis_frame.configure(bg=ThemeManager.get_color_by_theme(self.__axis_color)) - self.__x_axis_frame.configure(bg=ThemeManager.get_color_by_theme(self.__axis_color)) - self.__output_canvas.configure(bg=ThemeManager.get_color_by_theme(self.__fg_color)) - self.__pointer.configure(bg=ThemeManager.get_color_by_theme(self.__pointer_color)) - - def __set_customtkinter_widgets_colors(self) -> None: - """ - Set custom colors for specific Tkinter widgets. - - This method sets custom foreground and background colors for specific Tkinter widgets. - """ - - self.__y_axis_values_frame.configure(fg_color=self.__bg_color, bg_color=self.__bg_color) - self.__x_axis_values_frame.configure(fg_color=self.__bg_color, bg_color=self.__bg_color) - - self.__main_frame.configure(fg_color=self.__bg_color, bg_color="transparent") - self.__output_frame.configure(fg_color=self.__fg_color, bg_color=self.__bg_color) - - self.__y_axis_data_label.configure( - fg_color=self.__bg_color, - bg_color=self.__bg_color, - text_color=self.__y_axis_data_font_color - ) - for label in self.__x_axis_values_frame.winfo_children(): - if type(label) is customtkinter.CTkLabel: - label.configure( - fg_color=self.__bg_color, - bg_color=self.__bg_color, - text_color=self.__x_axis_font_color - ) - - self.__x_axis_data_label.configure( - fg_color=self.__bg_color, - bg_color=self.__bg_color, - text_color=self.__x_axis_data_font_color - ) - for label in self.__y_axis_values_frame.winfo_children(): - if type(label) is customtkinter.CTkLabel: - label.configure( - fg_color=self.__bg_color, - bg_color=self.__bg_color, - text_color=self.__y_axis_font_color - ) - - def __set_widgets_fonts(self) -> None: - """ - Set the fonts for CTkLineChart widgets. - - This method configures the font styles for various widgets in the LineChart, - including the y-axis data label, x-axis data label, y-axis values labels, - and x-axis values labels, using the specified data font style and axis font style. - """ - - self.__y_axis_data_label.configure(font=self.__data_font_style) - self.__x_axis_data_label.configure(font=self.__data_font_style) - - for label in self.__y_axis_values_frame.winfo_children(): - if type(label) is customtkinter.CTkLabel: - label.configure(font=self.__axis_font_style) - - for label in self.__x_axis_values_frame.winfo_children(): - if type(label) is customtkinter.CTkLabel: - label.configure(font=self.__axis_font_style) - - def __set_pointer_size(self) -> None: - """ - Set the size of the pointer. - - This method adjusts the width and height of the pointer widget based on the specified pointer size. - """ - - self.__pointer.configure(width=self.__pointer_size) - self.__pointer.configure(height=self.__const_real_height) - - def __place_widgets(self) -> None: - """ - Place widgets within the CTkLineChart. - - This method handles the placement of various widgets within the LineChart, including the main frame, - y-axis frame, x-axis frame, output frame, output canvas, y-axis values frame, and x-axis values frame, - based on the specified dimensions and positions. - """ - - self.__main_frame.configure(width=self.__width, height=self.__height) - - self.__y_axis_data_label.place_forget() - self.__x_axis_data_label.place_forget() - if self.__y_axis_data != "": - if self.__y_axis_data_position == "top": - self.__y_axis_data_label.place(x=self.__margin, y=0) - else: - self.__y_axis_data_label.place( - x=self.__margin, - y=self.__y_space + self.__y_special_height_space + self.__real_height / 2, - anchor="w" - ) - - if self.__x_axis_data != "": - if self.__x_axis_data_position == "top": - self.__x_axis_data_label.place( - relx=1, - x=-self.__x_axis_data_req_width + -self.__margin, - y=self.__height - self.__x_axis_data_req_height - ) - else: - self.__x_axis_data_label.place( - rely=1, - y=-self.__x_axis_data_req_height, - relx=0, - anchor="n", - x=( - self.__const_real_width / 2 + self.__y_axis_data_req_width_space_side + - self.__y_value_req_width_space + self.__axis_size + self.__x_axis_data_req_width_space_top + - self.__x_special_width_space + self.__margin - ) - ) - - self.__y_axis_frame.configure(width=self.__axis_size) - self.__x_axis_frame.configure(height=self.__axis_size) - - self.__y_axis_frame.place( - x=self.__y_value_req_width_space + self.__y_axis_data_req_width_space_side + self.__margin, - y=float( - self.__y_axis_data_req_height_space_top + - (self.__y_value_req_height_space / 2) + - self.__y_special_height_space - ), - ) - self.__y_axis_frame.configure(height=self.__const_real_height + self.__y_space + self.__axis_size) - self.__x_axis_frame.place( - x=self.__y_value_req_width_space + self.__y_axis_data_req_width_space_side + self.__margin, - y=(self.__height - self.__axis_size + -self.__x_value_req_height_space + - -self.__x_axis_data_req_height_space_side), - ) - - self.__x_axis_frame.configure(width=self.__const_real_width + self.__axis_size + self.__x_space) - - self.__output_frame.place( - x=( - self.__y_value_req_width_space + self.__axis_size + self.__y_axis_data_req_width_space_side + - self.__margin - ), - y=float( - self.__y_axis_data_req_height_space_top + (self.__y_value_req_height_space / 2) + - self.__y_special_height_space + self.__y_space - ) - ) - self.__output_frame.configure( - width=self.__const_real_width, - height=self.__const_real_height - ) - - self.__output_canvas.place(y=0, x=0) - self.__output_canvas.configure(height=self.__const_real_height, width=self.__const_real_width) - - if self.__y_values_frame_place_req: - self.__y_axis_values_frame.place(x=self.__y_axis_data_req_width_space_side + self.__margin) - self.__y_axis_values_frame.configure(width=self.__y_value_req_width_space, height=self.__height) - else: - self.__y_axis_values_frame.place_forget() - - if self.__x_values_frame_place_req: - self.__x_axis_values_frame.place( - x=self.__margin, - y=self.__height - self.__x_value_req_height_space + -self.__x_axis_data_req_height_space_side - ) - self.__x_axis_values_frame.configure( - height=self.__x_value_req_height_space, - width=self.__width - (self.__margin * 2) - ) - else: - self.__x_axis_values_frame.place_forget() - - def __configure_x_axis_point_spacing(self) -> None: - """ - Configure the spacing between points on the x-axis. - - This method calculates and sets the spacing between points on the x-axis based on the - specified handle method. If the spacing is handled automatically, it calculates the spacing - based on the real width of the LineChart and the number of x-axis values. If handled manually, - it uses the specified x-axis point spacing value. - """ - - if self.__x_axis_point_spacing_handle_by == "auto": - self.__x_axis_point_spacing = (self.__const_real_width / len(self.__x_axis_values)) - elif self.__x_axis_point_spacing_handle_by == "manual": - self.__x_axis_point_spacing = self.__x_axis_point_spacing - - def __configure_required_widget_size(self) -> None: - """ - Configure the required sizes of the LineChart's widgets. - - This method calculates and sets the required sizes for various widgets in the LineChart, - such as axis labels, based on the provided data and styling options. It determines the - necessary space for displaying the data labels, axis values, and adjusts the real width - and height of the LineChart accordingly. - """ - - self.__x_axis_data_req_width_space_top = 0 - self.__x_axis_data_req_height_space_side = 0 - self.__x_special_width_space = 0 - self.__x_axis_data_req_height = 0 - self.__x_axis_data_req_width = 0 - if self.__x_axis_data != "": - self.__x_axis_data_req_height = Utils._RequiredHeight(text=self.__x_axis_data, font=self.__data_font_style) - self.__x_axis_data_req_width = Utils._RequiredWidth(text=self.__x_axis_data, font=self.__data_font_style) - if self.__x_axis_data_position == "top": - self.__x_special_width_space = 15 - self.__x_axis_data_req_width_space_top = Utils._RequiredWidth( - text=self.__x_axis_data, font=self.__data_font_style - ) - else: - self.__x_axis_data_req_height_space_side = Utils._RequiredHeight( - text=self.__x_axis_data, font=self.__data_font_style - ) - - self.__y_axis_data_req_height_space_top = 0 - self.__y_axis_data_req_width_space_side = 0 - self.__y_special_height_space = 0 - - self.__y_values_frame_place_req = True - self.__x_values_frame_place_req = True - # self.__y_axis_data_req_height = Utils._RequiredHeight(text=self.__y_axis_data, font=self.__data_font_style) - # self.__y_axis_data_req_width = Utils._RequiredWidth(text=self.__y_axis_data, font=self.__data_font_style) - if self.__y_axis_data != "": - if self.__y_axis_data_position == "top": - self.__y_special_height_space = 15 - self.__y_axis_data_req_height_space_top = Utils._RequiredHeight( - text=self.__y_axis_data, font=self.__data_font_style - ) - else: - self.__y_axis_data_req_width_space_side = Utils._RequiredWidth( - text=self.__y_axis_data[0], font=self.__data_font_style - ) - - if self.__y_axis_label_count == 0: - self.__y_value_req_height_space = 0 - self.__y_value_req_width_space = 0 - self.__y_values_frame_place_req = False - else: - if (len(Utils._format_float_with_precision(self.__y_axis_max_value, self.__y_axis_precision)) > - len(Utils._format_float_with_precision(self.__y_axis_min_value, self.__y_axis_precision))): - y_value_temp = self.__y_axis_max_value - else: - y_value_temp = self.__y_axis_min_value - self.__y_value_req_height_space = Utils._RequiredHeight( - text=Utils._format_float_with_precision(y_value_temp, self.__y_axis_precision), - font=self.__axis_font_style - ) - self.__y_value_req_width_space = Utils._RequiredWidth( - text=Utils._format_float_with_precision(y_value_temp, self.__y_axis_precision), - font=self.__axis_font_style - ) - - self.__x_value_req_width_space = 0 - self.__x_value_req_height_space = 0 - if self.__x_axis_label_count == 0 and self.__x_axis_values_handle_by == "label_count": - self.__x_values_frame_place_req = False - elif self.__x_axis_values_handle_by == "label_indices" and (len(self.__x_axis_display_values_indices) == 0): - self.__x_values_frame_place_req = False - else: - self.__x_value_req_height_space = Utils._RequiredHeight( - text=self.__x_axis_values[0], font=self.__axis_font_style - ) - # self.__x_value_req_width_space = RequiredWidth(text=format_float_with_precision(self.__x_axis_data_max, - # self.__x_values_decimals), font=self.__axis_font_style) - self.__x_value_req_width_space = Utils._get_max_required_label_width( - data=self.__x_axis_values, font=self.__axis_font_style - ) - - if self.__y_value_req_height_space / 2 > self.__x_value_req_height_space: - self.__x_value_req_height_space = self.__y_value_req_height_space / 2 - - self.__real_width = self.__width - ( - self.__y_value_req_width_space + self.__axis_size + self.__x_axis_data_req_width_space_top + - self.__y_axis_data_req_width_space_side + (self.__x_value_req_width_space / 2) + - self.__x_special_width_space + self.__x_space + self.__margin * 2 - ) - - self.__const_real_width = self.__real_width - self.__real_height = self.__height - ( - self.__y_axis_data_req_height_space_top + self.__axis_size + self.__x_value_req_height_space + - self.__x_axis_data_req_height_space_side + (self.__y_value_req_height_space / 2) + - self.__y_special_height_space + self.__y_space - ) - self.__real_height = self.__real_height - - self.__const_real_height = int(self.__real_height) - - self.__y_axis_values_gap = abs(self.__y_axis_max_value - self.__y_axis_min_value) - - def __set_x_y_axis_data_texts(self) -> None: - """ - Set the text for the x and y axis data labels. - - This method sets the text for the y-axis data label based on its position. If the position - is 'top', the label text is set to the provided y-axis data. Otherwise, if the position is - 'side', the label text is set as a newline-separated string of the y-axis data elements. - - The text for the x-axis data label is set directly to the provided x-axis data. - """ - - if self.__y_axis_data_position == "top": - self.__y_axis_data_label.configure(text=self.__y_axis_data) - else: - self.__y_axis_data_label.configure(text="\n".join(self.__y_axis_data)) - self.__x_axis_data_label.configure(text=self.__x_axis_data) - - def __set_y_axis_values(self) -> None: - """ - Set the values for the y-axis labels. - - This method sets the values for the y-axis labels based on the specified label count and the - range of values between the maximum and minimum y-axis values. If the y-axis label count is greater - than 0, it iterates over the y-axis labels and calculates the value for each label using the - formula: maximum y-axis value - ((y-axis value range) / y-axis label count) * index. If the minimum - y-axis value is 0 and the index is equal to the y-axis label count, the value is set to 0. The values - are formatted with the specified precision before being assigned to the labels. - """ - - if self.__y_axis_label_count > 0: - for i, label in enumerate(self.__y_axis_values_frame.winfo_children()): - value = (self.__y_axis_max_value - (self.__y_axis_values_gap / self.__y_axis_label_count) * i) - if self.__y_axis_min_value == 0 and i == self.__y_axis_label_count: - value = 0 - value = Utils._format_float_with_precision(value, self.__y_axis_precision) - label.configure(text=value) - - def __create_y_axis_labels(self) -> None: - """ - Create the y-axis labels. - - This method creates the y-axis labels based on the specified label count. If the y-axis label count is - greater than 0, it iterates over the range of label count and creates a tkinter Label for each label. - The labels are placed vertically with equal spacing between them. The y-coordinate for each label is - calculated based on the initial y-position, the height of each label, additional spacing, and the total - height of the plot area divided by the number of labels. - """ - - if self.__y_axis_label_count > 0: - y = self.__y_axis_data_req_height_space_top + ( - self.__y_value_req_height_space / 2) + self.__y_special_height_space + self.__y_space - for i in range(self.__y_axis_label_count + 1): - customtkinter.CTkLabel( - master=self.__y_axis_values_frame, - justify="right", - width=self.__y_value_req_width_space - ).place( - y=y, - x=0, - anchor="w" - ) - y += self.__real_height / self.__y_axis_label_count - - def __destroy_y_axis_labels(self) -> None: - """ - Destroy the y-axis labels. - - This method removes and destroys all existing y-axis labels. It iterates over the children of the - y-axis values frame, which contain the y-axis labels, and calls the place_forget() and destroy() methods - for each label to remove them from the GUI and release system resources. - """ - - for y_value in self.__y_axis_values_frame.winfo_children(): - y_value.place_forget() - y_value.destroy() - - def __set_x_axis_values_using_label_count(self) -> None: - """ - Set the x-axis values using the label count. - - This method sets the x-axis values using the label count. It iterates over the children of the - x-axis values frame, which contain the x-axis labels, and assigns values to each label from the - provided x-axis values list in reverse order. The index is decremented by the value of - x_labels_values_index_change for each iteration. - """ - - index = -1 - for label in (self.__x_axis_values_frame.winfo_children()): - value = self.__x_axis_values[index] - index -= self.__x_labels_values_index_change - label.configure(text=value) - - def __set_x_axis_values_using_indices(self) -> None: - """ - Set the x-axis values using the specified display indices. - - This method sets the x-axis values using the specified display indices. It iterates over the children of the - x-axis values frame, which contain the x-axis labels, and assigns values to each label from the - provided x-axis values list based on the display indices provided. - """ - - index = -1 - for label in (self.__x_axis_values_frame.winfo_children()): - value = self.__x_axis_values[self.__x_axis_display_values_indices[index]] - index -= 1 - label.configure(text=value) - - def __create_x_axis_labels_using_label_count(self) -> None: - """ - Create x-axis labels using the specified label count. - - This method creates x-axis labels using the specified label count. It iterates over the range of the label - count and places labels inside the x-axis values frame. The labels are evenly spaced across the - x-axis based on the provided label count. - """ - - x = self.__width - self.__x_axis_data_req_width_space_top - ( - self.__x_value_req_width_space / 2) - self.__x_special_width_space - self.__x_space - self.__margin * 2 - for i in range(self.__x_axis_label_count): - customtkinter.CTkLabel(master=self.__x_axis_values_frame).place( - rely=1, - y=-self.__x_value_req_height_space, - x=x, - anchor="n" - ) - x -= self.__const_real_width / self.__x_axis_label_count - - def __create_x_axis_labels_using_indices(self) -> None: - """ - Create x-axis labels using the specified display indices. - - This method creates x-axis labels using the specified display indices. It iterates over the range of the label - count and places labels inside the x-axis values frame. - The labels are placed at positions corresponding to the indices specified for display. - """ - - x = self.__width - self.__x_axis_data_req_width_space_top - ( - (self.__x_value_req_width_space / 2) - self.__x_special_width_space - self.__x_space - self.__margin * 2 - ) - for i in range(self.__x_axis_label_count): - if (self.__x_axis_label_count - (i + 1)) in self.__x_axis_display_values_indices: - customtkinter.CTkLabel(master=self.__x_axis_values_frame).place( - rely=1, - y=-self.__x_value_req_height_space, x=x, - anchor="n" - ) - x -= self.__const_real_width / self.__x_axis_label_count - - def __create_x_axis_labels(self) -> None: - """ - Create x-axis labels based on the method specified for handling x-axis values. - - This method creates x-axis labels based on the method specified for handling x-axis values. - If the values are to be displayed using label indices, it calls the __create_x_axis_labels_using_indices method. - Otherwise, it calls the __create_x_axis_labels_using_label_count method. - """ - - if self.__x_axis_values_handle_by == "label_indices": - self.__create_x_axis_labels_using_indices() - else: - self.__create_x_axis_labels_using_label_count() - - def __set_x_axis_values(self) -> None: - """ - Set x-axis values based on the method specified for handling x-axis values. - - This method sets x-axis values based on the method specified for handling x-axis values. If the values are to be - set using label indices, it calls the __set_x_axis_values_using_indices method. Otherwise, it calls the - __set_x_axis_values_using_label_count method. - """ - - if self.__x_axis_values_handle_by == "label_indices": - self.__set_x_axis_values_using_indices() - else: - self.__set_x_axis_values_using_label_count() - - def __destroy_x_axis_labels(self) -> None: - """ - Destroy x-axis labels. - - This method destroys all the x-axis labels by iterating through the children of the x-axis values frame, - forgetting their placement, and then destroying them. - """ - - for x_value in self.__x_axis_values_frame.winfo_children(): - x_value.place_forget() - x_value.destroy() - - def __configure_x_axis_labels_info(self) -> None: - """ - Configure information for x-axis labels. - - This method determines the count and index change for x-axis labels based on the method used to provide - x-axis values. If x-axis values are provided using label indices, it sets the label count to the length - of the x-axis values. If x-axis values are handled automatically or by label count, it adjusts the label - count and index change accordingly to ensure proper spacing and distribution of labels. - """ - - if self.__x_axis_values_handle_by == "label_indices": - self.__x_axis_label_count = len(self.__x_axis_values) - - elif self.__x_axis_values_handle_by == "label_count": - if self.__x_axis_label_count == 0: - return - if self.__x_axis_label_count is None: - self.__x_axis_label_count = len(self.__x_axis_values) - x_axis_real_label_count = len(self.__x_axis_values) - if self.__x_axis_label_count > x_axis_real_label_count: - self.__x_axis_label_count = x_axis_real_label_count - else: - while x_axis_real_label_count % self.__x_axis_label_count != 0: - self.__x_axis_label_count += 1 - self.__x_labels_values_index_change = int(x_axis_real_label_count / self.__x_axis_label_count) - - def __create_y_axis_sections(self) -> None: - """ - Create sections on the y-axis. - - This method creates sections on the y-axis based on the specified section style. - If the section style is 'normal', it creates evenly spaced sections. If the section style is 'dashed', - it creates sections with custom width and spacing as specified in the style type tuple. - """ - - y = 0 - bg = ThemeManager.get_color_by_theme(self.__y_axis_section_color) - if self.__y_axis_section_style == "normal": - for i in range(self.__y_axis_section_count): - tkinter.Frame(master=self.__output_frame, - height=1, - width=self.__const_real_width, - bg=bg, - ).place(y=y, anchor="w") - y += self.__real_height / self.__y_axis_section_count - else: - width_ = self.__y_axis_section_style_type[0] - space_ = self.__y_axis_section_style_type[1] - for i in range(self.__y_axis_section_count): - x_ = self.__const_real_width - width_ - while x_ > -(width_ + space_): - tkinter.Frame(master=self.__output_frame, - height=1, - width=width_, - bg=bg).place(y=y, anchor="w", x=x_) - x_ -= width_ + space_ - y += self.__real_height / self.__y_axis_section_count - - def __create_x_axis_sections(self) -> None: - """ - Create sections on the x-axis. - - This method creates sections on the x-axis based on the specified section style. - If the section style is 'normal',it creates evenly spaced sections. If the section style is 'dashed', - it creates sections with custom height and spacing is specified in the style type tuple. - """ - - x = self.__const_real_width - 1 - bg = ThemeManager.get_color_by_theme(self.__x_axis_section_color) - if self.__x_axis_section_style == "normal": - for i in range(self.__x_axis_section_count): - tkinter.Frame( - master=self.__output_frame, - height=self.__const_real_height, - width=1, - bg=bg - ).place(x=x, anchor="n") - x -= (self.__const_real_width / self.__x_axis_section_count) - else: - height_ = self.__x_axis_section_style_type[0] - space_ = self.__x_axis_section_style_type[1] - for i in range(self.__x_axis_section_count): - y_ = 0 - while y_ < self.__const_real_height: - tkinter.Frame( - master=self.__output_frame, - height=height_, - width=1, - bg=bg - ).place(x=x, anchor="n", y=y_) - y_ += height_ + space_ - x -= (self.__const_real_width / self.__x_axis_section_count) - - def __destroy_x_y_sections(self) -> None: - """ - Destroy all x-axis and y-axis sections. - - This method destroys all sections created on both the x-axis and y-axis by removing them from the output frame. - """ - - for widget in self.__output_frame.winfo_children(): - if type(widget) is tkinter.Frame: - widget.place_forget() - widget.destroy() - - def configure( - self, - width: int = None, - height: int = None, - axis_size: int = None, - x_axis_point_spacing: Union[int, Literal["auto"]] = None, - - fg_color: Union[Tuple[str, str], str] = None, - axis_color: Union[Tuple[str, str], str] = None, - bg_color: Union[Tuple[str, str], str] = None, - data_font_style: Tuple[str, int, str] = None, - axis_font_style: Tuple[str, int, str] = None, - - y_axis_values: Union[int, float] = None, - y_axis_precision: int = None, - y_axis_font_color: Union[Tuple[str, str], str] = None, - y_axis_data_font_color: Union[Tuple[str, str], str] = None, - y_axis_section_count: int = None, - y_axis_section_color: Union[Tuple[str, str], str] = None, - y_axis_section_style: Literal["normal", "dashed"] = None, - y_axis_section_style_type: Tuple[int, int] = None, - y_axis_label_count: int = None, - y_axis_data: Any = None, - y_axis_data_position: Literal["top", "side"] = None, - y_space: int = None, - - x_axis_values: Tuple[Any, ...] = None, - x_axis_data: Any = None, - x_axis_font_color: Union[Tuple[str, str], str] = None, - x_axis_data_font_color: Union[Tuple[str, str], str] = None, - x_axis_label_count: int = None, - x_axis_section_count: int = None, - x_axis_section_style: Literal["normal", "dashed"] = None, - x_axis_section_style_type: Tuple[int, int] = None, - x_axis_section_color: Union[Tuple[str, str], str] = None, - x_axis_display_values_indices: Tuple[int, ...] = None, - x_axis_data_position: Literal["top", "side"] = None, - x_space: int = None, - - pointer_state: Literal["enabled", "disabled"] = None, - pointing_values_precision: int = None, - pointer_color: Union[Tuple[str, str], str] = None, - pointer_lock: Literal["enabled", "disabled"] = None, - pointing_callback_function: Callable = None, - pointer_size: int = None) -> None: - """ - Configures the properties of the chart widget based on the provided arguments. - - Args: - width (int): The width of the chart canvas. - height (int): The height of the chart canvas. - axis_size (int): The size of the chart axis. + if axis_color != None: + Validate._isValidColor(axis_color, "axis_color") + if axis_color != self.__axis_color: + self.__axis_color = axis_color + widget_color_change_req = True - axis_color (Union[Tuple[str, str], str]): The color of the chart axis. - fg_color (Union[Tuple[str, str], str]): The foreground color of the chart. - bg_color (Union[Tuple[str, str], str]): The background color of the chart. - data_font_style (Tuple[str, int, str]): The font style for data labels. - axis_font_style (Tuple[str, int, str]): The font style for axis labels. + if bg_color != None: + Validate._isValidColor(bg_color, "bg_color") + if bg_color != self.__bg_color: + self.__bg_color = bg_color + widget_color_change_req = True - y_axis_precision (int): The precision of the y-axis values. - y_axis_data (Any): The label for the y-axis. - y_axis_label_count (int): The number of labels on the y-axis. - y_axis_values (Tuple[Union[int, float], Union[int, float]]): The range of values for the y-axis. - y_axis_font_color (Union[Tuple[str, str], str]): The font color for y-axis labels. - y_axis_data_font_color (Union[Tuple[str, str], str]): The font color for y-axis data labels. - y_axis_data_position (str): The position of y-axis data labels. - y_axis_section_count (int): The number of sections on the y-axis. - y_axis_section_style (str): The style of sections on the y-axis. - y_axis_section_style_type (Tuple[int, int]): The style type of sections on the y-axis. - y_axis_section_color (Union[Tuple[str, str], str]): The color of sections on the y-axis. + if y_axis_font_color != None: + Validate._isValidColor(y_axis_font_color, "y_axis_font_color") + if y_axis_font_color != self.__y_axis_font_color: + self.__y_axis_font_color = y_axis_font_color + widget_color_change_req = True - x_axis_data (str): The label for the x-axis. - x_axis_label_count (int): The number of labels on the x-axis. - x_axis_values (Tuple[Any, ...]): The values for the x-axis labels. - x_axis_display_values_indices (Tuple[int, ...]): The indices to display values on the x-axis. - x_axis_font_color (Union[Tuple[str, str], str]): The font color for x-axis labels. - x_axis_data_font_color (Union[Tuple[str, str], str]): The font color for x-axis data labels. - x_axis_data_position (str): The position of x-axis data labels. - x_axis_section_count (int): The number of sections on the x-axis. - x_axis_section_style (str): The style of sections on the x-axis. - x_axis_section_style_type (Tuple[int, int]): The style type of sections on the x-axis. - x_axis_section_color (Union[Tuple[str, str], str]): The color of sections on the x-axis. + if x_axis_font_color != None: + Validate._isValidColor(x_axis_font_color, "x_axis_font_color") + if x_axis_font_color != self.__x_axis_font_color: + self.__x_axis_font_color = x_axis_font_color + widget_color_change_req = True - x_axis_point_spacing (Union[int, str]): Spacing between x-axis points. - x_space: The space between x-axis labels and the edge of the canvas. - y_space: The space between y-axis labels and the edge of the canvas. + if y_axis_data_font_color != None: + Validate._isValidColor(y_axis_data_font_color, "y_axis_data_font_color") + if y_axis_data_font_color != self.__y_axis_data_font_color: + self.__y_axis_data_font_color = y_axis_data_font_color + widget_color_change_req = True - pointer_state: The initial state of the pointer ('disabled' or 'enabled'). - pointing_callback_function: A callback function to be called when pointing to a data point. - pointer_color: The color of the pointer, specified as a tuple of two colors or a single color string. - pointing_values_precision: The precision for the values displayed when pointing to data points. - pointer_lock: The lock state of the pointer ('disabled' or 'enabled'). - pointer_size: The size of the pointer. - """ - - chart_reset_req: bool = False - widget_color_change_req: bool = False - widget_size_change_req: bool = False - widget_font_change_req: bool = False - chart_x_values_change_req: bool = False - chart_sections_change_req: bool = False - chart_sections_color_change_req: bool = False - chart_x_labels_change_req: bool = False - chart_y_labels_change_req: bool = False - pointer_state_change_req: bool = False - pointer_size_change_req: bool = False - reshow_data_req: bool = False - - if width is not None: - Validate._isInt(width, "width") - if width != self.__width: - self.__width = width - chart_reset_req = True - - if height is not None: - Validate._isInt(height, "height") - if height != self.__height: - self.__height = height - chart_reset_req = True - - if y_space is not None: - Validate._isInt(y_space, "y_space") - if y_space != self.__y_space: - self.__y_space = y_space - chart_reset_req = True - - if x_space is not None: - Validate._isInt(x_space, "x_space") - if x_space != self.__x_space: - self.__x_space = x_space - chart_reset_req = True - - if y_axis_values is not None: - Validate._isValidYAxisValues(y_axis_values, "y_axis_values") - if y_axis_values != self.__y_axis_values: - self.__y_axis_values = y_axis_values - self.__y_axis_min_value = y_axis_values[0] - self.__y_axis_max_value = y_axis_values[1] - chart_reset_req = True - - if axis_size is not None: - Validate._isInt(axis_size, "axis_size") - if axis_size != self.__axis_size: - self.__axis_size = axis_size - chart_reset_req = True - - if y_axis_precision is not None: - Validate._isInt(y_axis_precision, "y_axis_precision") - if y_axis_precision != self.__y_axis_precision: - self.__y_axis_precision = y_axis_precision - chart_reset_req = True - - if x_axis_data is not None: - if x_axis_data != self.__x_axis_data: - self.__x_axis_data = x_axis_data - chart_reset_req = True - - if data_font_style is not None: - Validate._isValidFont(data_font_style, "data_font_style") - if data_font_style != self.__data_font_style: - self.__data_font_style = data_font_style - chart_reset_req = True - - if axis_font_style is not None: - Validate._isValidFont(axis_font_style, "axis_font_style") - if axis_font_style != self.__axis_font_style: - self.__axis_font_style = axis_font_style - chart_reset_req = True - - if fg_color is not None: - Validate._isValidColor(fg_color, "fg_color") - if fg_color != self.__fg_color: - self.__fg_color = fg_color - widget_color_change_req = True - - if axis_color is not None: - Validate._isValidColor(axis_color, "axis_color") - if axis_color != self.__axis_color: - self.__axis_color = axis_color - widget_color_change_req = True - - if bg_color is not None: - Validate._isValidColor(bg_color, "bg_color") - if bg_color != self.__bg_color: - self.__bg_color = bg_color - widget_color_change_req = True - - if y_axis_font_color is not None: - Validate._isValidColor(y_axis_font_color, "y_axis_font_color") - if y_axis_font_color != self.__y_axis_font_color: - self.__y_axis_font_color = y_axis_font_color - widget_color_change_req = True - - if x_axis_font_color is not None: - Validate._isValidColor(x_axis_font_color, "x_axis_font_color") - if x_axis_font_color != self.__x_axis_font_color: - self.__x_axis_font_color = x_axis_font_color - widget_color_change_req = True - - if y_axis_data_font_color is not None: - Validate._isValidColor(y_axis_data_font_color, "y_axis_data_font_color") - if y_axis_data_font_color != self.__y_axis_data_font_color: - self.__y_axis_data_font_color = y_axis_data_font_color - widget_color_change_req = True - - if x_axis_data_font_color is not None: - Validate._isValidColor(x_axis_data_font_color, "x_axis_data_font_color") - if x_axis_data_font_color != self.__x_axis_data_font_color: - self.__x_axis_data_font_color = x_axis_data_font_color - widget_color_change_req = True - - if x_axis_section_color is not None: - Validate._isValidColor(x_axis_section_color, "x_axis_section_color") - if x_axis_section_color != self.__x_axis_section_color: - self.__x_axis_section_color = x_axis_section_color - chart_sections_color_change_req = True - - if y_axis_section_color is not None: - Validate._isValidColor(y_axis_section_color, "y_axis_section_color") - if y_axis_section_color != self.__y_axis_section_color: - self.__y_axis_section_color = y_axis_section_color - chart_sections_color_change_req = True - - if y_axis_section_style is not None: - Validate._isValidSectionStyle(y_axis_section_style, "y_axis_section_style") - if y_axis_section_style != self.__y_axis_section_style: - self.__y_axis_section_style = y_axis_section_style - chart_sections_change_req = True - - if x_axis_section_style is not None: - Validate._isValidSectionStyle(x_axis_section_style, "x_axis_section_style") - if x_axis_section_style != self.__x_axis_section_style: - self.__x_axis_section_style = x_axis_section_style - chart_sections_change_req = True - - if y_axis_section_style_type is not None: - Validate._isValidStyleType(y_axis_section_style_type, "y_axis_section_style_type") - if y_axis_section_style_type != self.__y_axis_section_style_type: - self.__y_axis_section_style_type = y_axis_section_style_type - chart_sections_change_req = True - - if x_axis_section_style_type is not None: - Validate._isValidStyleType(x_axis_section_style_type, "x_axis_section_style_type") - if x_axis_section_style_type != self.__x_axis_section_style_type: - self.__x_axis_section_style_type = x_axis_section_style_type - chart_sections_change_req = True - - if y_axis_label_count is not None: - Validate._isInt(y_axis_label_count, "y_axis_label_count") - if y_axis_label_count != self.__y_axis_label_count: - if y_axis_label_count == 0 or self.__y_axis_label_count == 0: - chart_reset_req = True - self.__y_axis_label_count = y_axis_label_count - chart_y_labels_change_req = True - widget_color_change_req = True - - if x_axis_section_count is not None: - Validate._isInt(x_axis_section_count, "x_axis_section_count") - if x_axis_section_count != self.__x_axis_section_count: - self.__x_axis_section_count = x_axis_section_count - chart_sections_change_req = True - - if y_axis_section_count is not None: - Validate._isInt(y_axis_section_count, "y_axis_section_count") - if y_axis_section_count != self.__y_axis_section_count: - self.__y_axis_section_count = y_axis_section_count - chart_sections_change_req = True - - if x_axis_data_position is not None: - Validate._isValidDataPostion(x_axis_data_position, "x_axis_data_position") - if x_axis_data_position != self.__x_axis_data_position: - self.__x_axis_data_position = x_axis_data_position - chart_reset_req = True - - if y_axis_data_position is not None: - Validate._isValidDataPostion(y_axis_data_position, "y_axis_data_position") - if y_axis_data_position != self.__y_axis_data_position: - self.__y_axis_data_position = y_axis_data_position - chart_reset_req = True - - if y_axis_data is not None: - if y_axis_data != self.__y_axis_data: - self.__y_axis_data = y_axis_data - chart_reset_req = True - - if x_axis_values is not None: - if x_axis_values != self.__x_axis_values: - Validate._isValidXAxisValues(x_axis_values, "x_axis_values") - if self.__x_axis_values_handle_by == "label_indices": - if x_axis_display_values_indices is not None: - Validate._isValidXAxisIndices( - x_axis_values, - x_axis_display_values_indices, - "x_axis_display_values_indices" - ) - else: - Validate._isValidXAxisIndices( - x_axis_values, - self.__x_axis_display_values_indices, - "x_axis_display_values_indices" - ) - if len(x_axis_values) != len(self.__x_axis_values): - chart_reset_req = True - elif Utils._get_max_required_label_width( - x_axis_values, self.__axis_font_style - ) != self.__x_value_req_width_space: - chart_reset_req = True - else: - chart_x_values_change_req = True - self.__x_axis_values = x_axis_values - - if x_axis_display_values_indices is not None: - if x_axis_values is None: - Validate._isValidXAxisIndices( - self.__x_axis_values, - x_axis_display_values_indices, - "x_axis_display_values_indices" - ) - self.__x_axis_values_handle_by = "label_indices" - x_axis_display_values_indices = Utils._sort_tuple(x_axis_display_values_indices) - if x_axis_display_values_indices != self.__x_axis_display_values_indices: - self.__x_axis_display_values_indices = x_axis_display_values_indices - chart_x_labels_change_req = True - widget_color_change_req = True - widget_font_change_req = True - - elif x_axis_label_count is not None: - Validate._isValidXAxisLabelCount(x_axis_label_count, "x_axis_label_count") - self.__x_axis_values_handle_by = "label_count" - if x_axis_label_count != self.__x_axis_label_count: - if x_axis_label_count == 0 or self.__x_axis_label_count == 0: - chart_reset_req = True - self.__x_axis_label_count = x_axis_label_count - chart_x_labels_change_req = True - widget_color_change_req = True - widget_font_change_req = True - - if pointer_color is not None: - Validate._isValidColor(pointer_color, "pointer_color") - self.__pointer_color = pointer_color + if x_axis_data_font_color != None: + Validate._isValidColor(x_axis_data_font_color, "x_axis_data_font_color") + if x_axis_data_font_color != self.__x_axis_data_font_color: + self.__x_axis_data_font_color = x_axis_data_font_color widget_color_change_req = True - if pointing_callback_function is not None: - Validate._isValidFunction(pointing_callback_function, "pointing_callback_function") - self.__pointing_callback_function = pointing_callback_function - - if pointing_values_precision is not None: - Validate._isInt(pointing_values_precision, "pointing_values_precision") - self.__pointing_values_precision = pointing_values_precision - - if pointer_lock is not None: - Validate._isValidPointerState_Lock(pointer_lock, "pointer_lock") - self.__pointer_lock = pointer_lock - - if pointer_state is not None: - Validate._isValidPointerState_Lock(pointer_state, "pointer_state") - self.__pointer_state = pointer_state - pointer_state_change_req = True - - if pointer_size is not None: - Validate._isInt(pointer_size, "pointer_size") - self.__pointer_size = pointer_size - pointer_size_change_req = True - - if x_axis_point_spacing is not None: - Validate._isValidXAxisPointSpacing(x_axis_point_spacing, "x_axis_point_spacing") - if x_axis_point_spacing == "auto": - if self.__x_axis_point_spacing_handle_by != "auto": - self.__x_axis_point_spacing_handle_by = "auto" - reshow_data_req = True - elif self.__x_axis_point_spacing != x_axis_point_spacing: - self.__x_axis_point_spacing_handle_by = "manual" - self.__x_axis_point_spacing = x_axis_point_spacing - reshow_data_req = True - - if chart_reset_req: - self.__destroy_x_axis_labels() - self.__destroy_y_axis_labels() - self.__destroy_x_y_sections() - self.__configure_required_widget_size() - self.__configure_x_axis_point_spacing() - self.__configure_x_axis_labels_info() - self.__create_x_axis_labels() - self.__set_x_axis_values() - self.__create_y_axis_labels() - self.__set_y_axis_values() - self.__create_y_axis_sections() - self.__create_x_axis_sections() - self.__set_x_y_axis_data_texts() - self.__set_pointer_state() - self.__set_pointer_size() - self.__set_widgets_fonts() - self.__set_customtkinter_widgets_colors() - self.__set_tkinter_widgets_colors() - self.__place_widgets() - self.__reset_chart_info() - self.__reshow_data() - - if chart_x_labels_change_req: - self.__configure_x_axis_labels_info() - self.__destroy_x_axis_labels() - self.__create_x_axis_labels() - self.__set_x_axis_values() - - elif chart_y_labels_change_req: - self.__destroy_y_axis_labels() - self.__create_y_axis_labels() - self.__set_y_axis_values() - - if chart_x_values_change_req: - self.__set_x_axis_values() - - if chart_sections_change_req or chart_sections_color_change_req: - self.__destroy_x_y_sections() - self.__create_y_axis_sections() - self.__create_x_axis_sections() - - if widget_color_change_req: - self.__set_customtkinter_widgets_colors() - self.__set_tkinter_widgets_colors() - - if widget_size_change_req is True: - self.__set_pointer_size() - - if reshow_data_req: - self.__configure_x_axis_point_spacing() - self.__reshow_data() - - if pointer_size_change_req: - self.__set_pointer_size() - - if pointer_state_change_req: - self.__set_pointer_state() - - if widget_font_change_req: - self.__set_widgets_fonts() - - def __reset_chart_info(self) -> None: - """ - Reset the chart information and clear the canvas. - - This method deletes all items on the canvas and recalculates the real width and real height of the chart. - """ - - self.__output_canvas.delete("all") - self.__real_width = (self.__width - ( - self.__y_value_req_width_space + self.__axis_size + self.__x_axis_data_req_width_space_top + - self.__y_axis_data_req_width_space_side + - self.__x_value_req_width_space / 2 + - self.__x_special_width_space + self.__x_space - ) - self.__margin * 2) - - self.__const_real_width = self.__real_width - self.__real_height = self.__height - ( - self.__y_axis_data_req_height_space_top + self.__axis_size + self.__x_value_req_height_space + - self.__x_axis_data_req_height_space_side + self.__y_value_req_height_space / 2 + - self.__y_special_height_space + self.__y_space - ) - self.__real_height = self.__real_height - - self.__const_real_height = self.__real_height - - self.__output_canvas.place(y=0, x=0, height=self.__const_real_height, width=self.__const_real_width) - self.__place_x = 0 - - def __reset_lines_info(self) -> None: - """ - Reset the information for all lines in the chart. - - This method calls the __reset() method for each line object stored in the __lines list. - """ - - for line in self.__lines: - line._CTkLine__reset() + if x_axis_section_color != None: + Validate._isValidColor(x_axis_section_color, "x_axis_section_color") + if x_axis_section_color != self.__x_axis_section_color: + self.__x_axis_section_color = x_axis_section_color + chart_sections_color_change_req = True + + if y_axis_section_color != None: + Validate._isValidColor(y_axis_section_color, "y_axis_section_color") + if y_axis_section_color != self.__y_axis_section_color: + self.__y_axis_section_color = y_axis_section_color + chart_sections_color_change_req = True + + if y_axis_section_style != None: + Validate._isValidSectionStyle(y_axis_section_style, "y_axis_section_style") + if y_axis_section_style != self.__y_axis_section_style: + self.__y_axis_section_style = y_axis_section_style + chart_sections_change_req = True + + if x_axis_section_style != None: + Validate._isValidSectionStyle(x_axis_section_style, "x_axis_section_style") + if x_axis_section_style != self.__x_axis_section_style: + self.__x_axis_section_style = x_axis_section_style + chart_sections_change_req = True - def __get_max_visible_data_points(self) -> int: - """ - Calculate the maximum number of data points that can be displayed - on the chart at the current resolution and axis spacing. - - Returns: - int: The maximum number of data points visible on the x-axis. - """ - # Determine the maximum number of data points based on the available width - # and spacing between points on the x-axis. - max_visible_points = int(self.__const_real_width / self.__x_axis_point_spacing) + 1 - return max_visible_points - - def __get_max_data_length_across_lines(self) -> int: - """ - Determine the maximum number of data points in any line within the chart. - - This is useful for determining how much data is present in the most - populated data series. - - Returns: - int: The maximum length of data in any line. - """ - if len(self.__lines) > 0: - # Retrieve the number of data points in each line - lines_values = [len(line._CTkLine__data) for line in self.__lines] + if y_axis_section_style_type != None: + Validate._isValidStyleType(y_axis_section_style_type, "y_axis_section_style_type") + if y_axis_section_style_type != self.__y_axis_section_style_type: + self.__y_axis_section_style_type = y_axis_section_style_type + chart_sections_change_req = True + + if x_axis_section_style_type != None: + Validate._isValidStyleType(x_axis_section_style_type, "x_axis_section_style_type") + if x_axis_section_style_type != self.__x_axis_section_style_type: + self.__x_axis_section_style_type = x_axis_section_style_type + chart_sections_change_req = True + + if y_axis_label_count!=None: + Validate._isInt(y_axis_label_count, "y_axis_label_count") + if y_axis_label_count != self.__y_axis_label_count: + if y_axis_label_count == 0 or self.__y_axis_label_count == 0: + chart_reset_req = True + self.__y_axis_label_count = y_axis_label_count + chart_y_labels_change_req = True + widget_color_change_req = True + + if x_axis_section_count!=None: + Validate._isInt(x_axis_section_count, "x_axis_section_count") + if x_axis_section_count != self.__x_axis_section_count: + self.__x_axis_section_count = x_axis_section_count + chart_sections_change_req = True + + if y_axis_section_count!=None: + Validate._isInt(y_axis_section_count, "y_axis_section_count") + if y_axis_section_count != self.__y_axis_section_count: + self.__y_axis_section_count = y_axis_section_count + chart_sections_change_req = True + + if x_axis_data_position!=None: + Validate._isValidDataPostion(x_axis_data_position, "x_axis_data_position") + if x_axis_data_position != self.__x_axis_data_position: + self.__x_axis_data_position = x_axis_data_position + chart_reset_req = True - # Find and return the maximum length among all lines - max_data_length = max(lines_values) - return max_data_length - return 0 - - - def __reshow_data(self) -> None: - """ - Re-shows data on the chart. - - This method recalculates the chart info, ensures that the chart can support the maximum amount of - data to be shown, resets each line with the latest data, and then displays the data for each line. - """ - - self.__reset_chart_info() - - maximum_data = self.__get_max_data_length_across_lines() - max_visible_points = self.__get_max_visible_data_points() - - for line in self.__lines: - if maximum_data > max_visible_points: - line._CTkLine__temp_data = line._CTkLine__data[maximum_data - max_visible_points::] - line._CTkLine__data = line._CTkLine__data[:maximum_data - max_visible_points:] + if y_axis_data_position!=None: + Validate._isValidDataPostion(y_axis_data_position, "y_axis_data_position") + if y_axis_data_position != self.__y_axis_data_position: + self.__y_axis_data_position = y_axis_data_position + chart_reset_req = True + + if y_axis_data != None: + if y_axis_data != self.__y_axis_data: + self.__y_axis_data = y_axis_data + chart_reset_req = True + + if x_axis_values != None: + if x_axis_values != self.__x_axis_values: + Validate._isTuple(x_axis_values, "x_axis_values") + if self.__x_axis_values_handle_by == "label_indices": + if x_axis_display_values_indices != None : + Validate._isValidXAxisIndices(x_axis_values, x_axis_display_values_indices, "x_axis_display_values_indices") + else: + Validate._isValidXAxisIndices(x_axis_values, self.__x_axis_display_values_indices, "x_axis_display_values_indices") + if len(x_axis_values) != len(self.__x_axis_values): + chart_reset_req = True + elif Utils._get_max_required_label_width(x_axis_values,self.__axis_font_style)!=self.__x_value_req_width_space: + chart_reset_req = True else: - line._CTkLine__temp_data = line._CTkLine__data - line._CTkLine__data = [] - line._CTkLine__reset_positions() - - for line in self.__lines: - self.show_data(line=line, data=line._CTkLine__temp_data) - - - def show_data(self, line: CTkLine, data: List[Union[int, float]]) -> None: - """ - Show data on the chart for the given line. - - Args: - line (CTkLine): The line object to which the data belongs. - data (List[Union[int, float]]): The list of data points to be displayed. - - Raises: - ValueError: If the provided line object is not valid or not found in the chart. + chart_x_values_change_req = True + self.__x_axis_values = x_axis_values + + if x_axis_display_values_indices!=None: + if x_axis_values == None: + Validate._isValidXAxisIndices(self.__x_axis_values, x_axis_display_values_indices, "x_axis_display_values_indices") + self.__x_axis_values_handle_by = "label_indices" + x_axis_display_values_indices = Utils._sort_tuple(x_axis_display_values_indices) + if x_axis_display_values_indices != self.__x_axis_display_values_indices: + self.__x_axis_display_values_indices = x_axis_display_values_indices + chart_x_labels_change_req = True + widget_color_change_req = True + widget_font_change_req = True + + elif x_axis_label_count!=None: + Validate._isValidXAxisLabelCount(x_axis_label_count, "x_axis_label_count") + self.__x_axis_values_handle_by = "label_count" + if x_axis_label_count != self.__x_axis_label_count: + self.__x_axis_label_count = x_axis_label_count + chart_x_labels_change_req = True + widget_color_change_req = True + widget_font_change_req = True - This method adds the provided data to the line's existing data, adjusts the display of the chart accordingly, - and shows the data points on the chart. It also handles various styles for displaying the data points, - such as dashed or dotted lines, and highlights for individual data points. - """ - - Validate._isValidCTkLine(line, "line") - Validate._isValidData(data, "data") - - re_show_data = False - if line not in self.__lines: - Validate._invalidCTkLine(line) - - line._CTkLine__data += data - - if line._CTkLine__visibility: - - line_color = ThemeManager.get_color_by_theme(line._CTkLine__color) - highlight_color = ThemeManager.get_color_by_theme(line._CTkLine__point_highlight_color) - fill_color = ThemeManager.get_color_by_theme(line._CTkLine__fill_color) - - for d in data: - x_start = line._CTkLine__x_end - y_start = line._CTkLine__y_end - - line._CTkLine__x_end += self.__x_axis_point_spacing - - if d >= 0: - d = d - self.__y_axis_min_value - line._CTkLine__y_end = self.__const_real_height - ( - d / self.__y_axis_values_gap * self.__const_real_height) - else: - d = abs(d) + self.__y_axis_max_value - line._CTkLine__y_end = (d / self.__y_axis_values_gap * self.__const_real_height) - line._CTkLine__y_end += (line._CTkLine__size / 2) - - if round(line._CTkLine__x_end) > round(self.__real_width) and self.__real_width < self.__width * 5: - self.__place_x -= self.__x_axis_point_spacing - - self.__output_canvas.place( - x=self.__place_x, - width=self.__real_width + self.__x_axis_point_spacing - ) - - self.__real_width += self.__x_axis_point_spacing - - elif self.__real_width > self.__width * 5: - re_show_data = True - break - - if line._CTkLine__fill == "enabled": - points_of_polygon = [ - x_start, y_start, - line._CTkLine__x_end, line._CTkLine__y_end, - line._CTkLine__x_end, self.__const_real_height, - x_start, self.__const_real_height - ] - self.__output_canvas.create_polygon( - points_of_polygon, fill=fill_color - ) - - if line._CTkLine__style == "dashed": - dash_width = line._CTkLine__style_type[0] - space_width = line._CTkLine__style_type[1] - total_width = dash_width + space_width - real_x_axis_point_spacing = ((abs(y_start - line._CTkLine__y_end) ** 2) + ( - self.__x_axis_point_spacing ** 2)) ** (1 / 2) - dash_count = real_x_axis_point_spacing / (dash_width + space_width) - total_change_x = (line._CTkLine__x_end - x_start) - total_change_y = (line._CTkLine__y_end - y_start) - dash_change_percentage = dash_width / total_width - space_change_percentage = space_width / total_width - change_x = (total_change_x / dash_count) - change_y = (total_change_y / dash_count) - dash_change_x = change_x * dash_change_percentage - dash_change_y = change_y * dash_change_percentage - space_change_x = change_x * space_change_percentage - space_change_y = change_y * space_change_percentage - dashed_x_start = x_start - dashed_y_start = y_start - if y_start > line._CTkLine__y_end: - line_going = "to_up" - else: - line_going = "to_down" - while line._CTkLine__x_end > dashed_x_start: - dashed_x_end = dashed_x_start + dash_change_x - dashed_y_end = dashed_y_start + dash_change_y - if dashed_x_end > line._CTkLine__x_end: - dashed_x_end = dashed_x_end - (dashed_x_end - line._CTkLine__x_end) - if dashed_y_end <= line._CTkLine__y_end and line_going == "to_up": - dashed_y_end = dashed_y_end - (dashed_y_end - line._CTkLine__y_end) - if dashed_y_end > line._CTkLine__y_end and line_going == "to_down": - dashed_y_end = dashed_y_end - (dashed_y_end - line._CTkLine__y_end) - self.__output_canvas.create_line( - dashed_x_start, dashed_y_start, - dashed_x_end, dashed_y_end, - fill=line_color, width=line._CTkLine__size - ) - dashed_x_start += dash_change_x + space_change_x - dashed_y_start += dash_change_y + space_change_y - - elif line._CTkLine__style == "dotted": - circle_size = line._CTkLine__style_type[0] - space_width = line._CTkLine__style_type[1] - total_width = circle_size + space_width - real_x_axis_point_spacing = ((abs(y_start - line._CTkLine__y_end) ** 2) + ( - self.__x_axis_point_spacing ** 2)) ** (1 / 2) - circle_count = real_x_axis_point_spacing / (circle_size + space_width) - total_change_x = (line._CTkLine__x_end - x_start) - total_change_y = (line._CTkLine__y_end - y_start) - circle_change_percentage = circle_size / total_width * 100 - space_change_percentage = space_width / total_width * 100 - circle_change_x = (total_change_x / circle_count) / 100 * circle_change_percentage - circle_change_y = (total_change_y / circle_count) / 100 * circle_change_percentage - space_change_x = (total_change_x / circle_count) / 100 * space_change_percentage - space_change_y = (total_change_y / circle_count) / 100 * space_change_percentage - dotted_x_start = x_start - dotted_y_start = y_start - - while line._CTkLine__x_end > dotted_x_start: - self.__output_canvas.create_oval( - dotted_x_start - circle_size / 2, - dotted_y_start - circle_size / 2, - dotted_x_start + circle_size - circle_size / 2, - dotted_y_start + circle_size - circle_size / 2, - fill=line_color, outline=line_color - ) - dotted_x_start += circle_change_x + space_change_x - dotted_y_start += circle_change_y + space_change_y - - elif line._CTkLine__style == "normal": - self.__output_canvas.create_line( - x_start, y_start, - line._CTkLine__x_end, line._CTkLine__y_end, - fill=line_color, width=line._CTkLine__size - ) - - if line._CTkLine__point_highlight == "enabled" and line._CTkLine__point_highlight_size > 0: - highlight_size = line._CTkLine__point_highlight_size / 2 - self.__output_canvas.create_oval( - line._CTkLine__x_end - highlight_size, - line._CTkLine__y_end - highlight_size, - line._CTkLine__x_end + highlight_size, - line._CTkLine__y_end + highlight_size, - fill=highlight_color, - outline=highlight_color - ) - - self.__output_canvas.create_oval( - x_start - highlight_size, - y_start - highlight_size, - x_start + highlight_size, - y_start + highlight_size, - fill=highlight_color, - outline=highlight_color - ) - - if re_show_data: - self.__reshow_data() - - def __hide_pointer(self, _event: tkinter.Event) -> None: - """ - Hides the pointer widget from the GUI canvas. - - Args: - _event (tkinter.Event): The event triggering the pointer hiding. - """ - - self.__pointer.place_forget() - - def __return_pointed_values(self, event: tkinter.Event) -> None: - """ - Returns the values pointed by the user's mouse cursor. - - Args: - event (tkinter.Event): The mouse event containing cursor position. - """ - - def round_x(x) -> Union[int, float]: - """ - Rounds the x-coordinate to the nearest x-axis point spacing. - - Args: - x (float): The x-coordinate to be rounded. - - Returns: - float: The rounded x-coordinate. - """ - - x_ = (x // self.__x_axis_point_spacing) * self.__x_axis_point_spacing - if x % self.__x_axis_point_spacing >= self.__x_axis_point_spacing / 2: - x_ += self.__x_axis_point_spacing - return x_ - - max_view = self.__get_max_visible_data_points() - max_sup = max_view - 1 - values = [] - max_data = self.__get_max_data_length_across_lines() - - try: - max_data = max([len(line._CTkLine__data) for line in self.__lines]) - if self.__pointer_lock == "enabled": - event_x = round_x(event.x) + if pointer_color!=None: + Validate._isValidColor(pointer_color, "pointer_color") + self.__pointer_color = pointer_color + widget_color_change_req = True + + if pointing_callback_function != None: + Validate._isValidFunction(pointing_callback_function, "pointing_callback_function") + self.__pointing_callback_function = pointing_callback_function + + if pointing_values_precision != None: + Validate._isInt(pointing_values_precision, "pointing_values_precision") + self.__pointing_values_precision = pointing_values_precision + + if pointer_lock!=None: + Validate._isValidPointerState_Lock(pointer_lock, "pointer_lock") + self.__pointer_lock = pointer_lock + + if pointer_state!=None: + Validate._isValidPointerState_Lock(pointer_state, "pointer_state") + self.__pointer_state = pointer_state + pointer_state_change_req = True + + if pointer_size != None: + Validate._isInt(pointer_size, "pointer_size") + self.__pointer_size = pointer_size + pointer_size_change_req = True + + if line_width != None: + Validate._isValidLineWidth(line_width, "line_width") + if line_width != self.__line_width: + if line_width == "auto": + self.__line_width_handle_by = "auto" else: - event_x = event.x - if self.__const_real_width >= self.__real_width: - event_x_converted = event_x + self.__line_width_handle_by = "manual" + self.__line_width = line_width + reshow_data_req = True + + if chart_reset_req : + self.__destroy_x_axis_labels() + self.__destroy_y_axis_labels() + + self.__destroy_x_y_sections() + + self.__configure_required_widget_size() + self.__configure_line_width() + + self.__configure_x_axis_labels_info() + self.__create_x_axis_labels() + self.__set_x_axis_values() + + self.__create_y_axis_labels() + self.__set_y_axis_values() + + self.__create_y_axis_sections() + self.__create_x_axis_sections() + + self.__set_x_y_axis_data_texts() + + self.__set_pointer_state() + self.__set_pointer_size() + + self.__set_widgets_fonts() + self.__set_widgets_colors() + + self.__place_widgets() + self.__reset_chart_info() + + self.__call_reshow_data() + + if chart_x_labels_change_req: + self.__configure_x_axis_labels_info() + self.__destroy_x_axis_labels() + self.__create_x_axis_labels() + self.__set_x_axis_values() + + elif chart_y_labels_change_req: + self.__destroy_y_axis_labels() + self.__create_y_axis_labels() + self.__set_y_axis_values() + + if chart_x_values_change_req: + self.__set_x_axis_values() + + if chart_sections_change_req or chart_sections_color_change_req: + self.__destroy_x_y_sections() + self.__create_y_axis_sections() + self.__create_x_axis_sections() + + if widget_color_change_req : + self.__set_widgets_colors() + + if widget_size_change_req == True: + self.__set_pointer_size() + + if reshow_data_req: + self.__configure_line_width() + self.__call_reshow_data() + + if pointer_size_change_req: + self.__set_pointer_size() + + if pointer_state_change_req: + self.__set_pointer_state() + + if widget_font_change_req: + self.__set_widgets_fonts() + + + def __reset_chart_info(self) -> None: + self.__output_canvas.delete("all") + self.__real_width = self.__width - (self.__y_value_req_width_space+self.__axis_size+self.__x_axis_data_req_width_space_top+self.__y_axis_data_req_width_space_side+\ + (self.__x_value_req_width_space/2)+self.__x_special_width_space+self.__x_space) + + self.__const_real_width = self.__real_width + self.__real_height = self.__height - (self.__y_axis_data_req_height_space_top+self.__axis_size+self.__x_value_req_height_space+self.__x_axis_data_req_height_space_side+\ + (self.__y_value_req_height_space/2)+self.__y_special_height_space+self.__y_space) + self.__real_height = self.__real_height + + self.__const_real_height = self.__real_height + + self.__output_canvas.place(y=0, x=0, height=self.__const_real_height, width=self.__const_real_width) + self.__place_x = 0 + + + def __reset_lines_info(self) -> None: + for line in self.__lines: + line._CTkLine__reset() + + + def __call_reshow_data(self) -> None: + self.__force_to_stop_data_showing = True + while self.__is_data_showing_working: + pass + self.__force_to_stop_data_showing = False + self.__reshow_data() + + + def __reshow_data(self) -> None: + lines_values = [len(line._CTkLine__data) for line in self.__lines] + if len(lines_values) > 0: + self.__reset_chart_info() + + maximum_data = max(lines_values) + max_support = int(self.__const_real_width/self.__line_width)+1 + + for line in self.__lines: + if maximum_data>max_support: + line._CTkLine__temp_data = line._CTkLine__data[maximum_data-(max_support)::] else: - event_x_converted = event_x - (self.__x_axis_point_spacing * (max_data - max_view)) - width_x = self.__const_real_width - (self.__const_real_width - (self.__x_axis_point_spacing * max_sup)) - index_float = ((event_x_converted / width_x) * max_sup) - index_round_float = round(index_float) - if event_x == self.__real_width: - self.__pointer.place(x=((event_x - self.__pointer_size / 2) - 2), y=0) + line._CTkLine__temp_data = line._CTkLine__data + line._CTkLine__reset() + + lines = self.__lines + self.lines =[] + + for line in lines: + self.show_data(line=line, data=line._CTkLine__temp_data) + + + def __get_color_by_theme(self, color_s: tuple | str) -> str: + if type(color_s) == tuple: + if self.__theme == "Light": + return color_s[0] + else: + return color_s[1] + else: + return color_s + + def show_data(self, line: CTkLine, data: tuple) -> None: + re_show_data = False + if line not in self.__lines: + self.__lines.append(line) + line._CTkLine__data += list(data) + + if line._CTkLine__hide_state != True : + for d in data: + + line_color = self.__get_color_by_theme(line._CTkLine__color) + highlight_color = self.__get_color_by_theme(line._CTkLine__point_highlight_color) + + self.__is_data_showing_working = True + + if not self.__force_to_stop_data_showing: + x_start = line._CTkLine__x_end + y_start = line._CTkLine__y_end + + line._CTkLine__x_end += self.__line_width + + if d >=0 : + d = d - self.__y_axis_min_value + line._CTkLine__y_end = self.__const_real_height - ((d )/self.__y_axis_values_gap * self.__const_real_height) + else: + d = abs(d) +self.__y_axis_max_value + line._CTkLine__y_end = ((d)/self.__y_axis_values_gap * self.__const_real_height) + line._CTkLine__y_end += ((line._CTkLine__size)/2) + + if round(line._CTkLine__x_end) > round(self.__real_width) and self.__real_width < 15000: + self.__place_x -= self.__line_width + + self.__output_canvas.place(x=self.__place_x, + width=self.__real_width+self.__line_width) + + self.__real_width += self.__line_width; + + elif self.__real_width > 15000: + re_show_data = True + break; + + if line._CTkLine__style == "dashed" : + dash_width = line._CTkLine__style_type[0] + space_width = line._CTkLine__style_type[1] + total_width = dash_width+space_width + real_line_width = ((abs(y_start - line._CTkLine__y_end)**2) + (self.__line_width**2)) ** (1/2) + dash_count = real_line_width /( dash_width + space_width) + total_change_x = (line._CTkLine__x_end - x_start) + total_change_y = (line._CTkLine__y_end - y_start) + dash_change_percentage = dash_width/total_width + space_change_percentage = space_width/total_width + change_x = (total_change_x/dash_count) + change_y = (total_change_y/dash_count) + dash_change_x = change_x*dash_change_percentage + dash_change_y = change_y*dash_change_percentage + space_change_x = change_x*space_change_percentage + space_change_y = change_y*space_change_percentage + if y_start > line._CTkLine__y_end: line_going = "to_up" + else : line_going = "to_down" + + while (line._CTkLine__x_end>x_start): + x_end = x_start+dash_change_x + y_end = y_start+dash_change_y + if x_end>line._CTkLine__x_end: + x_end = x_end - (x_end-line._CTkLine__x_end) + if y_end<=line._CTkLine__y_end and line_going=="to_up": + y_end = y_end - (y_end-line._CTkLine__y_end) + if y_end>line._CTkLine__y_end and line_going=="to_down": + y_end = y_end - (y_end-line._CTkLine__y_end) + self.__output_canvas.create_line(x_start, y_start, x_end, y_end + ,fill=line_color ,width=line._CTkLine__size) + x_start += dash_change_x + space_change_x + y_start += dash_change_y + space_change_y + + elif line._CTkLine__style == "dotted": + circle_size = line._CTkLine__style_type[0] + space_width = line._CTkLine__style_type[1] + total_width = circle_size+space_width + real_line_width = ((abs(y_start - line._CTkLine__y_end)**2) + (self.__line_width**2)) ** (1/2) + circle_count = real_line_width /( circle_size + space_width) + total_change_x = (line._CTkLine__x_end - x_start) + total_change_y = (line._CTkLine__y_end - y_start) + circle_change_percentage = circle_size/total_width*100 + space_change_percentage = space_width/total_width*100 + circle_change_x = (total_change_x/circle_count)/100*circle_change_percentage + circle_change_y = (total_change_y/circle_count)/100*circle_change_percentage + space_change_x = (total_change_x/circle_count)/100*space_change_percentage + space_change_y = (total_change_y/circle_count)/100*space_change_percentage + if y_start > line._CTkLine__y_end: line_going = "to_up" + else : line_going = "to_down" + while (line._CTkLine__x_end>x_start): + x_end = x_start+circle_change_x + y_end = y_start+circle_change_y + if x_end>line._CTkLine__x_end: + x_end = x_end - (x_end-line._CTkLine__x_end) + if y_end<=line._CTkLine__y_end and line_going=="to_up": + y_end = y_end - (y_end-line._CTkLine__y_end) + if y_end>line._CTkLine__y_end and line_going=="to_down": + y_end = y_end - (y_end-line._CTkLine__y_end) + self.__output_canvas.create_oval(x_start-circle_size/2, + y_start-circle_size/2, + x_start+circle_size-circle_size/2, + y_start+circle_size-circle_size/2, + fill=line_color, outline=line_color ) + x_start += circle_change_x + space_change_x + y_start += circle_change_y + space_change_y + + elif line._CTkLine__style=="normal": + self.__output_canvas.create_line(x_start, y_start, line._CTkLine__x_end, line._CTkLine__y_end + ,fill=line_color ,width=line._CTkLine__size) + + if line._CTkLine__style=="dashed" or line._CTkLine__style=="normal": + if line._CTkLine__point_highlight == "enabled" and line._CTkLine__point_highlight_size > 0 : + highlight_size = line._CTkLine__point_highlight_size /2 + self.__output_canvas.create_oval(line._CTkLine__x_end - highlight_size, + line._CTkLine__y_end - highlight_size, + line._CTkLine__x_end + highlight_size, + line._CTkLine__y_end + highlight_size, + fill=highlight_color + ) else: - self.__pointer.place(x=((event_x - self.__pointer_size / 2) + 1), y=0) - index_int = int(index_float) - x_index = index_int - if index_float != 0 and index_float == index_int: - x_index -= 1 - for line in self.__lines: - line._CTkLine__ret_data = line._CTkLine__data + (max_data - len(line._CTkLine__data)) * [None] - line._CTkLine__ret_data = line._CTkLine__ret_data[-int(max_view)::] - line._CTkLine__ret_data = line._CTkLine__ret_data + (int(max_view) - len(line._CTkLine__ret_data)) * [ - None] - for line in self.__lines: - try: - if self.__pointer_lock == "enabled": - value = line._CTkLine__ret_data[int(index_round_float)] - else: - if index_float == index_int: - value = line._CTkLine__ret_data[index_int] - else: - value = line._CTkLine__ret_data[index_int] - value = value + ( - ((line._CTkLine__ret_data[index_int + 1] - value) * (index_float - index_int))) - values.append(Utils._format_float_with_precision(float(value), self.__pointing_values_precision)) - except: - values.append("null") - if self.__pointing_callback_function is not None: - try: - self.__pointing_callback_function(self.__x_axis_values[x_index], values) - except: - self.__pointing_callback_function("null", values) - except: - pass - - def clear_data(self) -> None: - """ - Clears the data of all lines within the LineChart object, ensuring the data fits the - maximum visible points allowed for the chart. - - This method calculates the maximum number of data points across all lines and the maximum - number of visible data points allowed. If the total data exceeds the visible points limit, - it trims each line's data to retain only the most recent visible data points. - - The method checks the length of the data across all lines and compares it with the maximum - visible data points. If necessary, each line’s data is cropped by removing earlier data - points, retaining only the most recent data within the visible limit. - - Attributes: - self.__lines: A list of line objects representing each individual line on the chart. - - Returns: - None: This method modifies the internal state of each line's data but does not return any value. - - Example: - chart.clear_data() - - In this example, the data for each line in the chart will be cleared or trimmed based on the - maximum visible data points. Only the most recent data within the allowed visible range is kept. - """ - - maximum_data = self.__get_max_data_length_across_lines() - max_visible_points = self.__get_max_visible_data_points() - - for line in self.__lines: - if maximum_data > max_visible_points: - line._CTkLine__data = line._CTkLine__data[maximum_data - max_visible_points::] - - def place( - self, - x: int = None, - y: int = None, - rely: Union[int, float] = None, - relx: Union[int, float] = None, - anchor: Literal[ - "n", "e", "s", "w", "ne", "nw", "se", "sw", "center" - ] = None) -> None: - """ - Place the widget at a specific position within its parent widget. - - Args: - x (int): The x-coordinate of the upper-left corner of the widget. - y (int): The y-coordinate of the upper-left corner of the widget. - rely (Union[int, float]): The vertical relative position of the widget, ranging from 0 to 1. - relx (Union[int, float]): The horizontal relative position of the widget, ranging from 0 to 1. - anchor (str): Specifies which part of the widget is to be placed at the given coordinates. - """ - - self.__main_frame.place(x=x, y=y, rely=rely, relx=relx, anchor=anchor) - self.__place_info_x = x - self.__place_info_y = y - self.__place_info_rely = rely - self.__place_info_relx = relx - self.__place_info_anchor = anchor - - def pack( - self, + break + + if re_show_data: + self.__reshow_data() + self.__is_data_showing_working = False + + + def __hide_pointer(self, event: tkinter.Event) -> None: + self.__pointer.place_forget() + + + def __return_pointed_values(self, event: tkinter.Event): + def round_x(x): + x_ = (x//self.__line_width)*self.__line_width + if x%self.__line_width >= self.__line_width/2: + x_ += self.__line_width + return x_ + max_sup= int(self.__const_real_width/self.__line_width) + max_view = max_sup + 1 + values = [] + try: + max_data = max([len(line._CTkLine__data) for line in self.__lines]) + if self.__pointer_lock=="enabled": + event_x = round_x(event.x) + else: + event_x = event.x + if self.__const_real_width >= self.__real_width: + event_x_converted = event_x + else: + event_x_converted = event_x-(self.__line_width*(max_data-max_view)) + width_x = self.__const_real_width - (self.__const_real_width - (self.__line_width*max_sup)) + index_float = ((event_x_converted/width_x)*max_sup) + index_round_float = round(index_float) + if event_x == self.__real_width : + self.__pointer.place(x=((event_x-self.__pointer_size/2)-2) ,y=0) + else: + self.__pointer.place(x=((event_x-self.__pointer_size/2)+1) ,y=0) + index_int = int((index_float)) + x_index = index_int + if index_float !=0 and index_float == index_int: + x_index -= 1 + for line in self.__lines: + line._CTkLine__ret_data = line._CTkLine__data + (max_data-len(line._CTkLine__data)) * [None] + line._CTkLine__ret_data = line._CTkLine__ret_data[-int(max_view)::] + line._CTkLine__ret_data = line._CTkLine__ret_data + (int(max_view) - len(line._CTkLine__ret_data)) * [None] + for line in self.__lines: + try: + if self.__pointer_lock=="enabled": + value = line._CTkLine__ret_data[int(index_round_float)] + else: + if index_float == index_int: + value = line._CTkLine__ret_data[index_int] + else: + value = line._CTkLine__ret_data[index_int] + value = value + (((line._CTkLine__ret_data[index_int+1] - value) * (index_float - index_int))) + values.append(Utils._format_float_with_precision(float(value),self.__pointing_values_precision )) + except Exception as error: + values.append("null") + if self.__pointing_callback_function != None: + try: + self.__pointing_callback_function(self.__x_axis_values[x_index],values) + except Exception as e: + self.__pointing_callback_function("null",values) + except: + pass + + def place(self, + x: int = None, + y: int = None, + rely: int | float = None, + relx: int | float = None, + anchor: str = None + ) -> None: + self.__main_frame.place(x=x, y=y, rely=rely, relx=relx, anchor=anchor) + self.__place_info_x = x + self.__place_info_y = y + self.__place_info_rely = rely + self.__place_info_relx = relx + self.__place_info_anchor = anchor + + + def pack(self, pady: int = None, padx: int = None, - before: Any = None, - after: Any = None, - side: Literal["top", "bottom", "left", "right"] = None, - anchor: Literal[ - "n", "e", "s", "w", "ne", "nw", "se", "sw", "center" - ] = None) -> None: - """ - Pack the widget into its parent widget. - - Args: - pady (int): Vertical padding. - padx (int): Horizontal padding. - before (Any): Widget before which this widget will be packed. - after (Any): Widget after which this widget will be packed. - side (str): Specifies which side of the parent widget to pack against. - anchor (str): Specifies where the widget will be placed if the available area is larger than the widget's - requested size. - """ - - self.__main_frame.pack( - pady=pady, padx=padx, before=before, - after=after, side=side, anchor=anchor - ) - self.__pack_info_pady = pady - self.__pack_info_padx = padx - self.__pack_info_before = before - self.__pack_info_after = after - self.__pack_info_side = side - self.__pack_info_anchor = anchor - - def grid( - self, - column: int = None, - columnspan: int = None, - padx: int = None, - pady: int = None, - row: int = None, - rowspan: int = None, - sticky: Literal[ - "n", "e", "s", "w", "ne", "nw", "se", "sw" - ] = None) -> None: - """ - Grid the widget into its parent widget. - - Args: - column (int): The column in which to place the widget. - columnspan (int): The number of columns the widget occupies. - padx (int): Horizontal padding. - pady (int): Vertical padding. - row (int): The row in which to place the widget. - rowspan (int): The number of rows the widget occupies. - sticky (str): Specifies how the widget should be expanded to fill the cell. - """ - - self.__main_frame.grid( - column=column, columnspan=columnspan, - padx=padx, pady=pady, row=row, - rowspan=rowspan, sticky=sticky - ) - self.__grid_info_column = column - self.__grid_info_columnspan = columnspan - self.__grid_info_padx = padx - self.__grid_info_pady = pady - self.__grid_info_row = row - self.__grid_info_rowspan = rowspan - self.__grid_info_sticky = sticky - - def place_forget(self) -> None: - """ - Remove the widget from the grid. - """ - - self.__main_frame.place_forget() - self.__place_info_x = None - self.__place_info_y = None - self.__place_info_rely = None - self.__place_info_relx = None - self.__place_info_anchor = None - - def pack_forget(self) -> None: - """ - Remove the widget from the pack. - """ - - self.__main_frame.pack_forget() - self.__pack_info_pady = None - self.__pack_info_padx = None - self.__pack_info_before = None - self.__pack_info_after = None - self.__pack_info_side = None - self.__pack_info_anchor = None - - def grid_forget(self) -> None: - """ - Remove the widget from the grid. - """ - - self.__main_frame.grid_forget() - self.__grid_info_column = None - self.__grid_info_columnspan = None - self.__grid_info_padx = None - self.__grid_info_pady = None - self.__grid_info_row = None - self.__grid_info_rowspan = None - self.__grid_info_sticky = None - - def set_line_visibility(self, line: CTkLine, state: bool) -> None: - """ - Hide or show a specific line. - - Args: - line (CTkLine): The line object to hide or show. - state (bool): The hide/show state of the line. - """ - - Validate._isValidCTkLine(line, "line") - Validate._isBool(state, "state") - if line._CTkLine__visibility != state or self.__visibility != state: - line._CTkLine__visibility = state - self.__reshow_data() - - def set_lines_visibility(self, state: bool) -> None: - """ - Hide or show all lines. - - Args: - state (bool): The hide/show state of all lines. - """ - - Validate._isBool(state, "state") - self.__visibility = state - if state is False: - self.__output_canvas.place_forget() - for line in self.__lines: - line._CTkLine__visibility = state - self.__reshow_data() - - def reset(self) -> None: - """ - Reset the chart and lines to their initial state. - """ - - self.__reset_chart_info() - self.__reset_lines_info() - - def __apply_line_configuration(self) -> None: - """ - Apply changes to the lines and redraw the chart. - """ - - self.__reshow_data() - - def cget( - self, - attribute_name: Literal[ - "width", "height", "axis_color", "bg_color", "fg_color", - "data_font_style", "axis_font_style", "y_axis_precision", - "y_axis_data", "y_axis_label_count", "y_axis_values", - "y_axis_font_color", "y_axis_data_font_color", - "y_axis_data_position", "y_axis_section_count", - "y_axis_section_style", "y_axis_section_style_type", - "y_axis_section_color", "x_axis_data", "x_axis_label_count", - "x_axis_values", "x_axis_display_values_indices", - "x_axis_font_color", "x_axis_data_font_color", - "x_axis_data_position", "x_axis_section_count", - "x_axis_section_style", "x_axis_section_style_type", - "x_axis_section_color", "x_axis_point_spacing", - "y_space", "x_space", "pointer_state", - "pointing_callback_function", "pointer_color", - "pointing_values_precision", "pointer_lock", - "pointer_size", "__all__" - ] = "__all__") -> Any: - """ - Get the value of the specified attribute. - - Args: - attribute_name (str): The name of the attribute to get. - - Returns: - Any: The value of the specified attribute. - """ - - if attribute_name == "width": - return self.__width - if attribute_name == "height": - return self.__height - if attribute_name == "axis_color": - return self.__axis_color - if attribute_name == "bg_color": - return self.__bg_color - if attribute_name == "fg_color": - return self.__fg_color - if attribute_name == "data_font_style": - return self.__data_font_style - if attribute_name == "axis_font_style": - return self.__axis_font_style - if attribute_name == "y_axis_precision": - return self.__y_axis_precision - if attribute_name == "y_axis_data": - return self.__y_axis_data - if attribute_name == "y_axis_label_count": - return self.__y_axis_label_count - if attribute_name == "y_axis_values": - return self.__y_axis_values - if attribute_name == "y_axis_font_color": - return self.__y_axis_font_color - if attribute_name == "y_axis_data_font_color": - return self.__y_axis_data_font_color - if attribute_name == "y_axis_data_position": - return self.__y_axis_data_position - if attribute_name == "y_axis_section_count": - return self.__y_axis_section_count - if attribute_name == "y_axis_section_style": - return self.__y_axis_section_style - if attribute_name == "y_axis_section_style_type": - return self.__y_axis_section_style_type - if attribute_name == "y_axis_section_color": - return self.__y_axis_section_color - if attribute_name == "x_axis_data": - return self.__x_axis_data - if attribute_name == "x_axis_label_count": - return self.__x_axis_label_count - if attribute_name == "x_axis_values": - return self.__x_axis_values - if attribute_name == "x_axis_display_values_indices": - return self.__x_axis_display_values_indices - if attribute_name == "x_axis_font_color": - return self.__x_axis_font_color - if attribute_name == "x_axis_data_font_color": - return self.__x_axis_data_font_color - if attribute_name == "x_axis_data_position": - return self.__x_axis_data_position - if attribute_name == "x_axis_section_count": - return self.__x_axis_section_count - if attribute_name == "x_axis_section_style": - return self.__x_axis_section_style - if attribute_name == "x_axis_section_style_type": - return self.__x_axis_section_style_type - if attribute_name == "x_axis_section_color": - return self.__x_axis_section_color - if attribute_name == "x_axis_point_spacing": - return self.__x_axis_point_spacing - if attribute_name == "y_space": - return self.__y_space - if attribute_name == "x_space": - return self.__x_space - if attribute_name == "pointer_state": - return self.__pointer_state - if attribute_name == "pointing_callback_function": - return self.__pointing_callback_function - if attribute_name == "pointer_color": - return self.__pointer_color - if attribute_name == "pointing_values_precision": - return self.__pointing_values_precision - if attribute_name == "pointer_lock": - return self.__pointer_lock - if attribute_name == "pointer_size": - return self.__pointer_size - - if attribute_name == "__all__": - return { - "width": self.__width, - "height": self.__height, - "axis_color": self.__axis_color, - "bg_color": self.__bg_color, - "fg_color": self.__fg_color, - "data_font_style": self.__data_font_style, - "axis_font_style": self.__axis_font_style, - "y_axis_precision": self.__y_axis_precision, - "y_axis_data": self.__y_axis_data, - "y_axis_label_count": self.__y_axis_label_count, - "y_axis_values": self.__y_axis_values, - "y_axis_font_color": self.__y_axis_font_color, - "y_axis_data_font_color": self.__y_axis_data_font_color, - "y_axis_data_position": self.__y_axis_data_position, - "y_axis_section_count": self.__y_axis_section_count, - "y_axis_section_style": self.__y_axis_section_style, - "y_axis_section_style_type": self.__y_axis_section_style_type, - "y_axis_section_color": self.__y_axis_section_color, - "x_axis_data": self.__x_axis_data, - "x_axis_label_count": self.__x_axis_label_count, - "x_axis_values": self.__x_axis_values, - "x_axis_display_values_indices": self.__x_axis_display_values_indices, - "x_axis_font_color": self.__x_axis_font_color, - "x_axis_data_font_color": self.__x_axis_data_font_color, - "x_axis_data_position": self.__x_axis_data_position, - "x_axis_section_count": self.__x_axis_section_count, - "x_axis_section_style": self.__x_axis_section_style, - "x_axis_section_style_type": self.__x_axis_section_style_type, - "x_axis_section_color": self.__x_axis_section_color, - "x_axis_point_spacing": self.__x_axis_point_spacing, - "y_space": self.__y_space, - "x_space": self.__x_space, - "pointer_state": self.__pointer_state, - "pointing_callback_function": self.__pointing_callback_function, - "pointer_color": self.__pointer_color, - "pointing_values_precision": self.__pointing_values_precision, - "pointer_lock": self.__pointer_lock, - "pointer_size": self.__pointer_size - } - - Validate._invalidCget(attribute_name) - - def get_line_visibility(self, line: CTkLine): - """ - Get the visibility state of a specific line. - - Args: - line (CTkLine): The CTkLine object for which visibility is queried. - - Returns: - bool: True if the line is visible, False otherwise. - - Raises: - ValueError: If the provided line object is not valid or not found in the chart. - """ - - Validate._isValidCTkLine(line, "line") - if line in self.__lines: - return line._CTkLine__visibility - else: - Validate._invalidCTkLine(line) - - def get_lines_area(self): - """ - Get the area of all lines. - - Returns: - Area: The area of the lines. - - Raises: - ValueError: If the provided line object is not valid or not found in the chart. - """ - - total_area = 0 - for line in self.__lines: - total_area += self.get_line_area(line) - return total_area - - def get_line_area(self, line: CTkLine): - """ - Get the area of a specific line. - - Args: - line (CTkLine): The CTkLine object for which the area is queried. - - Returns: - Area: The area of the line. - - Raises: - ValueError: If the provided line object is not valid or not found in the chart. - """ - - Validate._isValidCTkLine(line, "line") - if line not in self.__lines: - Validate._invalidCTkLine(line) - - maximum_data = self.__get_max_data_length_across_lines() - max_visible_points = self.__get_max_visible_data_points() - - if maximum_data > max_visible_points: - line._CTkLine__temp_data = line._CTkLine__data[maximum_data - max_visible_points::] - else: - line._CTkLine__temp_data = line._CTkLine__data - - # print(self.__x_axis_point_spacing) - total_area = 0 - for i, data in enumerate(line._CTkLine__temp_data[0: -1]): - area = ((data - self.__y_axis_min_value) + (line._CTkLine__temp_data[i+1] - self.__y_axis_min_value)) * self.__x_axis_point_spacing * 1/2 - # print("-" * 20) - # print(f"(({data - self.__y_axis_min_value}) + ({line._Line__temp_data[i+1] - self.__y_axis_min_value})) * { self.__x_axis_point_spacing} * 1/2 = {area}") - total_area += area - - return total_area - - def place_info( - self, - attribute_name: Literal[ - "x", "y", "relx", "rely", "anchor", "__all__" - ] = "__all__") -> Any: - """ - Get the value of the specified place info. - - Args: - attribute_name (str): The name of the attribute to get. - - Returns: - Any: The value of the specified attribute. - """ - - if attribute_name == "x": - return self.__place_info_x - if attribute_name == "y": - return self.__place_info_y - if attribute_name == "relx": - return self.__place_info_relx - if attribute_name == "rely": - return self.__place_info_rely - if attribute_name == "anchor": - return self.__place_info_anchor - - if attribute_name == "__all__": - return { - "x": self.__place_info_x, - "y": self.__place_info_y, - "relx": self.__place_info_relx, - "rely": self.__place_info_rely, - "anchor": self.__place_info_anchor - } - - Validate._invalidCget(attribute_name) - - def pack_info( - self, - attribute_name: Literal[ - "padx", "pady", "before", "after", - "side", "anchor", "__all__" - ] = "__all__") -> Any: - """ - Get the value of the specified pack info. - - Args: - attribute_name (str): The name of the attribute to get. - - Returns: - Any: The value of the specified attribute. - """ - - if attribute_name == "padx": - return self.__pack_info_padx - if attribute_name == "pady": - return self.__pack_info_pady - if attribute_name == "before": - return self.__pack_info_before - if attribute_name == "after": - return self.__pack_info_after - if attribute_name == "side": - return self.__pack_info_side - if attribute_name == "anchor": - return self.__pack_info_anchor - - if attribute_name == "__all__": - return { - "padx": self.__pack_info_padx, - "pady": self.__pack_info_pady, - "before": self.__pack_info_before, - "after": self.__pack_info_after, - "side": self.__pack_info_side, - "anchor": self.__pack_info_anchor - } - - Validate._invalidCget(attribute_name) - - def grid_info( - self, - attribute_name: Literal[ - "row", "column", "rowspan", "columnspan", - "padx", "pady", "sticky", "__all__" - ] = "__all__") -> Any: - """ - Get the value of the specified grid info. - - Args: - attribute_name (str): The name of the attribute to get. - - Returns: - Any: The value of the specified attribute. - """ - - if attribute_name == "row": - return self.__grid_info_row - if attribute_name == "column": - return self.__grid_info_column - if attribute_name == "rowspan": - return self.__grid_info_rowspan - if attribute_name == "columnspan": - return self.__grid_info_columnspan - if attribute_name == "padx": - return self.__grid_info_padx - if attribute_name == "pady": - return self.__grid_info_pady - if attribute_name == "sticky": - return self.__grid_info_sticky - - if attribute_name == "__all__": - return { - "row": self.__grid_info_row, - "column": self.__grid_info_column, - "rowspan": self.__grid_info_rowspan, - "columnspan": self.__grid_info_columnspan, - "padx": self.__grid_info_padx, - "pady": self.__grid_info_pady, - "sticky": self.__grid_info_sticky - } - - Validate._invalidCget(attribute_name) - - def __del__(self) -> None: - """ - Destructor to clean up resources and perform necessary cleanup. - This method will be called when the object is about to be destroyed. - It ensures that all widgets are destroyed and attributes are deleted - to aid in garbage collection. - """ - - # Destroy widgets - try: - self.__main_frame.destroy() - except Exception as error: - return - - self.__main_frame.destroy() - self.__x_axis_values_frame.destroy() - self.__y_axis_values_frame.destroy() - self.__y_axis_data_label.destroy() - self.__x_axis_data_label.destroy() - self.__output_frame.destroy() - self.__output_canvas.destroy() - self.__y_axis_frame.destroy() - self.__x_axis_frame.destroy() - self.__pointer.destroy() - - # Deleting attributes to help with garbage collection - del self.__main_frame - del self.__x_axis_values_frame - del self.__y_axis_values_frame - del self.__y_axis_data_label - del self.__x_axis_data_label - del self.__output_frame - del self.__output_canvas - del self.__y_axis_frame - del self.__x_axis_frame - del self.__pointer - del self.__master - del self.__height - del self.__width - del self.__axis_size - del self.__axis_color - del self.__x_axis_point_spacing - del self.__x_axis_point_spacing_handle_by - del self.__data_font_style - del self.__axis_font_style - del self.__lines - del self.__bg_color - del self.__fg_color - del self.__y_axis_font_color - del self.__y_axis_data_font_color - del self.__y_axis_section_color - del self.__y_axis_section_style - del self.__y_axis_section_style_type - del self.__y_axis_section_count - del self.__y_axis_label_count - del self.__y_axis_data - del self.__y_axis_data_position - del self.__y_axis_values - del self.__y_axis_min_value - del self.__y_axis_max_value - del self.__y_axis_precision - del self.__y_space - del self.__x_axis_font_color - del self.__x_axis_data_font_color - del self.__x_axis_section_color - del self.__x_axis_section_style - del self.__x_axis_section_style_type - del self.__x_axis_section_count - del self.__x_axis_label_count - del self.__x_axis_display_values_indices - del self.__x_labels_values_index_change - del self.__x_axis_data - del self.__x_axis_data_position - del self.__x_axis_values - del self.__x_axis_values_handle_by - del self.__x_space - del self.__pointer_state - del self.__pointing_callback_function - del self.__pointing_values_precision - del self.__pointer_lock - del self.__pointer_size - del self.__pointer_color - del self.__x_values_frame_place_req - del self.__y_values_frame_place_req - del self.__place_x - del self.__real_height - del self.__real_width - del self.__const_real_height - del self.__const_real_width - del self.__visibility - del self.__place_info_x - del self.__place_info_y - del self.__place_info_rely - del self.__place_info_relx - del self.__place_info_anchor - del self.__pack_info_pady - del self.__pack_info_padx - del self.__pack_info_before - del self.__pack_info_after - del self.__pack_info_side - del self.__pack_info_anchor - del self.__grid_info_column - del self.__grid_info_columnspan - del self.__grid_info_padx - del self.__grid_info_pady - del self.__grid_info_row - del self.__grid_info_rowspan - del self.__grid_info_sticky - del self.__theme - del self.__margin - - def destroy(self) -> None: - """ - Destroy the chart. - """ - - ThemeManager.unbind_widget(self) - for line in self.__lines: - line.destroy() - - self.__del__() + before: tkinter.Widget = None, + after: tkinter.Widget = None, + side: str = None, + anchor: str = None + ) -> None: + self.__main_frame.pack(pady=pady, padx=padx, before=before, + after=after, side=side, anchor=anchor) + self.__pack_info_pady = pady + self.__pack_info_padx = padx + self.__pack_info_before = before + self.__pack_info_after = after + self.__pack_info_side = side + self.__pack_info_anchor = anchor + + + def grid(self, + column: int = None, + columnspan: int =None, + padx: int = None, + pady: int = None, + row: int = None, + rowspan: int = None, + sticky: str = None + ) -> None: + self.__main_frame.grid(column=column, columnspan=columnspan, + padx=padx, pady=pady, row=row, rowspan=rowspan, sticky=sticky) + self.__grid_info_column = column + self.__grid_info_columnspan = columnspan + self.__grid_info_padx = padx + self.__grid_info_pady = pady + self.__grid_info_row = row + self.__grid_info_rowspan = rowspan + self.__grid_info_sticky = sticky + + + def place_forget(self) -> None: + self.__main_frame.place_forget() + + + def pack_forget(self) -> None: + self.__main_frame.pack_forget() + + + def grid_forget(self) -> None: + self.__main_frame.grid_forget() + + + def place_back(self) -> None: + self.__main_frame.place(x=self.__place_info_x, y=self.__place_info_y, + rely=self.__place_info_rely, relx=self.__place_info_relx, + anchor=self.__place_info_anchor) + + + def pack_back(self) -> None: + self.__main_frame.pack(pady=self.__pack_info_pady, padx=self.__pack_info_padx, + before=self.__pack_info_before, after=self.__pack_info_after, + side=self.__pack_info_side, + anchor=self.__pack_info_anchor) + + + def grid_back(self) -> None: + self.__main_frame.grid(column=self.__grid_info_column, columnspan=self.__grid_info_columnspan, + padx=self.__grid_info_padx, pady=self.__grid_info_pady, + row=self.__grid_info_row, rowspan=self.__grid_info_rowspan, sticky=self.__grid_info_sticky) + + + def hide(self, line: CTkLine, state: bool) -> None: + if line._CTkLine__hide_state != state: + line._CTkLine__hide_state = state + self.__reshow_data() + + + def hide_all(self, state: bool) -> None: + if state == True: + self.__output_canvas.place_forget() + self.__force_to_stop_data_showing = True + while self.__is_data_showing_working : + pass + for line in self.__lines: + line._CTkLine__hide_state = state + self.__force_to_stop_data_showing = False + self.__reshow_data() + + + def reset(self) -> None: + self.__reset_chart_info() + self.__reset_lines_info() \ No newline at end of file diff --git a/src/ctkchart/Exceptions.py b/src/ctkchart/Exceptions.py new file mode 100644 index 0000000..86bc4da --- /dev/null +++ b/src/ctkchart/Exceptions.py @@ -0,0 +1,7 @@ +class TypeError(Exception): ... +class LengthError(Exception): ... +class IndexError(Exception): ... +class FunctionError(Exception): ... +class ColorError(Exception): ... +class FontError(Exception): ... +class ValueError(Exception): ... \ No newline at end of file diff --git a/src/ctkchart/FontStyle.py b/src/ctkchart/FontStyle.py index 3e0abe2..ea18420 100644 --- a/src/ctkchart/FontStyle.py +++ b/src/ctkchart/FontStyle.py @@ -1,48 +1,42 @@ class FontStyle: - @staticmethod - def _get_font_style_code( - fg_color: str, - bg_color: str, - style: str) -> str: + def _get_font_style_code(fg_color: str, + bg_color: str, + style: str): - colors_data = { - "black": ("30", "40"), - "gray": ("90", "100"), - "red": ("31", "41"), - "green": ("32", "42"), - "yellow": ("33", "43"), - "blue": ("34", "44"), - "Magenta": ("35", "45"), - "cyan": ("36", "46"), - "white": ("37", "47"), - "bright red": ("91", "101"), - "bright green": ("92", "102"), - "bright yellow": ("92", "102"), - "bright blue": ("92", "102"), - "bright magenta": ("92", "102"), - "bright cyan": ("92", "102"), - "bright white": ("92", "102") - } + colors_data = {"black" : ("30", "40"), + "gray" : ("90", "100"), + "red" : ("31", "41"), + "green" : ("32", "42"), + "yellow" : ("33", "43"), + "blue" : ("34", "44"), + "Magenta" : ("35", "45"), + "cyan" : ("36", "46"), + "white" : ("37", "47" ), + "bright red" : ("91", "101"), + "bright green" : ("92", "102"), + "bright yellow" : ("92", "102"), + "bright blue" : ("92", "102"), + "bright magenta" : ("92", "102"), + "bright cyan" : ("92", "102"), + "bright white" : ("92", "102") + } - fg_color_code = colors_data[fg_color][0] - bg_color_code = colors_data[bg_color][1] + fg_color_code = colors_data[fg_color][0] ; + bg_color_code = colors_data[bg_color][1] ; - styles_data = { - "normal": "0", - "italic": "3", - "underline": "4" - } + styles_data = {"normal" : "0", + "italic" : "3", + "underline" : "4" + } style_code = styles_data[style] - styled_font_code = "\x1b[" + style_code + ";" + fg_color_code + ";" + bg_color_code + "m" + styled_font_code = "\x1b[" + style_code + ";" + fg_color_code + ";" + bg_color_code + "m" ; - return styled_font_code + return styled_font_code; - @staticmethod - def _fontStyle( - value: str, - fg_color: str, - bg_color: str, - style: str = "normal") -> str: - output_text = FontStyle._get_font_style_code(fg_color, bg_color, style) + value + "\x1b[0m" - return output_text + def _fontStyle(value : str, + fg_color : str, + bg_color : str, + style : str = "normal"): + output_text = FontStyle._get_font_style_code(fg_color, bg_color, style) + value + "\x1b[0m" ; + return output_text ; \ No newline at end of file diff --git a/src/ctkchart/ThemeManager.py b/src/ctkchart/ThemeManager.py deleted file mode 100644 index 798a7dd..0000000 --- a/src/ctkchart/ThemeManager.py +++ /dev/null @@ -1,53 +0,0 @@ -import customtkinter as ctk -import time -from typing import List, Tuple, Any, Union -import threading - - -class ThemeManager: - running_state = False - child_objects: List = [] - theme: str = "-" - - @staticmethod - def get_color_by_theme(color_s: Union[Tuple[str, str], str]) -> str: - if type(color_s) is tuple: - if ThemeManager.theme == "Light": - return color_s[0] - else: - return color_s[1] - else: - return color_s - - @staticmethod - def theme_tracker() -> None: - while len(ThemeManager.child_objects) != 0: - if ctk.get_appearance_mode() != ThemeManager.theme: - ThemeManager.theme = ctk.get_appearance_mode() - for child_object in ThemeManager.child_objects: - try: - child_object._CTkLineChart__configure_theme_mode() - except Exception as error: - print(f"Line Chart theme configure failed : {error}") - - time.sleep(1) - ThemeManager.running_state = False - - @staticmethod - def run(): - ThemeManager.running_state = True - thread = threading.Thread(target=ThemeManager.theme_tracker) - thread.daemon = True - thread.start() - - @staticmethod - def bind_widget(widget: Any) -> None: - ThemeManager.child_objects.append(widget) - - @staticmethod - def unbind_widget(widget: Any) -> None: - try: - ThemeManager.child_objects.remove(widget) - except Exception as error: - print(f"Unable to remove widgets from Theme Manager : {error}") - \ No newline at end of file diff --git a/src/ctkchart/Utils.py b/src/ctkchart/Utils.py index 3d0e6e5..6b2a37c 100644 --- a/src/ctkchart/Utils.py +++ b/src/ctkchart/Utils.py @@ -1,56 +1,50 @@ import tkinter -from typing import Union, Tuple, Any - +import math +import customtkinter class Utils: - __change_val = 1 - - @staticmethod - def _RequiredWidth(text: Any, font: Tuple[str, int, str]) -> float: + def _RequiredWidth(text: any, font: str) -> int: label = tkinter.Label(font=font) - label.config(text=str(text) + "") - return label.winfo_reqwidth() / Utils.__change_val + label.config(text=str(text) +"") + return label.winfo_reqwidth() + - @staticmethod - def _RequiredHeight(text: Any, font: Tuple[str, int, str]) -> float: + def _RequiredHeight(text: any, font: str) -> int: label = tkinter.Label(font=font) - label.config(text=str(text) + "") - return label.winfo_reqheight() / Utils.__change_val + label.config(text=str(text) +"") + return label.winfo_reqheight() - @staticmethod - def _format_float_with_precision(float_val: Union[float, int], decimals: int) -> str: + def _format_float_with_precision(float_val: float | int, decimals: int) -> float: if decimals: - float_val = round(float(float_val), decimals) + float_val = round(float(float_val),decimals) float_val = str(float_val) + ((decimals-len(str(float_val).split(".")[-1]))*"0") return float_val else: return str(int(float_val)) - @staticmethod - def _get_max_required_label_width(data: Any, font: Tuple[str, int, str]) -> float: + def _get_max_required_label_width(data: any, font: str) -> int: max_required_width = 0 for d in data: required_width = Utils._RequiredWidth(text=d, font=font) - if max_required_width < required_width: - max_required_width = required_width - return max_required_width / Utils.__change_val + if max_required_width float: + + def _get_max_required_label_height(data :any, font: str) -> int: max_required_height = 0 for d in data: required_height = Utils._RequiredHeight(text=d, font=font) - if max_required_height < required_height: - max_required_height = required_height - return max_required_height / Utils.__change_val + if max_required_height Tuple[int, ...]: + def _sort_tuple(values: tuple[int]) -> tuple[int]: values_list = list(set(values)) values_list.sort() return tuple(values_list) - - @staticmethod - def _toInt(value: Union[int, str]) -> int: - # return math.ceil(value) - return value + + def _toInt(value: int | str) -> int: + #return math.ceil(value) + return value \ No newline at end of file diff --git a/src/ctkchart/Validate.py b/src/ctkchart/Validate.py index cacad76..e0fa350 100644 --- a/src/ctkchart/Validate.py +++ b/src/ctkchart/Validate.py @@ -1,130 +1,117 @@ -from typing import Tuple, Any -from .FontStyle import FontStyle +from .FontStyle import * +from .Exceptions import * import tkinter - class Validate: - @staticmethod - def _error_font(value: str) -> str: + + def _error_font(value): return FontStyle._fontStyle(value, "red", "black", "underline") - @staticmethod - def _var_font(value: str) -> str: + def _var_font(value): return FontStyle._fontStyle(value, "green", "black", "italic") - @staticmethod - def _isTuple(value: Any, var: str) -> None: - if type(value) is not tuple: + def _isTuple(value: any, var: str) -> None: + if type(value) != tuple: raise TypeError( f"{Validate._var_font(var)} {Validate._error_font('must be tuple.')}" ) - @staticmethod - def _isList(value: Any, var: str) -> None: - if type(value) is not list: + def _isInt(value: any, var: str) -> None: + if type(value) != int: raise TypeError( - f"{Validate._var_font(var)} {Validate._error_font('must be list.')}" + f"{Validate._var_font(var)} {Validate._error_font('must be int.')}" ) - @staticmethod - def _isInt(value: Any, var: str) -> None: - if type(value) is not int: + def _isFloat(value: any, var: str) -> None: + if type(value) != float: raise TypeError( - f"{Validate._var_font(var)} {Validate._error_font('must be int.')}" + f"{Validate._var_font(var)} {Validate._error_font('must be float.')}" ) - @staticmethod - def _isBool(value: Any, var: str) -> None: - if type(value) is not bool: + def _isStr(value: any, var: str) -> None: + if type(value) != str: raise TypeError( - f"{Validate._var_font(var)} {Validate._error_font('must be bool.')}" + f"{Validate._var_font(var)} {Validate._error_font('must be str.')}" ) - @staticmethod - def _isStr(value: Any, var: str) -> None: - if type(value) is not str: + def _isNumeric(value: int, var: str) -> None: + if type(value) == int or type(value) == float: + ... + else: raise TypeError( - f"{Validate._var_font(var)} {Validate._error_font('must be str.')}" + f"{Validate._var_font(var)} {Validate._error_font('must be int or float.')}" ) - @staticmethod - def _isValidColor(value: Any, var: str) -> None: - valid = True - if type(value) is tuple: + def _isValidColor(value: any, var: str) -> None: + valid = True + if type(value) == tuple: if len(value) == 2: try: tkinter.Label(bg=value[0]) - except: + except Exception: valid = False try: tkinter.Label(bg=value[1]) - except: - valid = False + except Exception: + valid = False else: - valid = False - - elif type(value) is str: + valid = False + + elif type(value) == str: try: tkinter.Label(bg=value) - except: - valid = False + except Exception: + valid = False else: - valid = False + valid = False if not valid: - raise ValueError( + raise ColorError( f'''{Validate._var_font(var)} {Validate._error_font("must be valid color. eg:- '#ff0000'/ 'red'/ ('#ffffff', '#000000')")}''' ) - @staticmethod - def _isValidFont(value: Any, var: str) -> None: + def _isValidFont(value: any, var: str) -> None: Validate._isTuple(value, var) try: tkinter.Label(font=value) except: - raise ValueError( + raise FontError( f'''{Validate._var_font(var)} {Validate._error_font("must be valid font. eg:- ('arial',10,'bold')")}''' ) - @staticmethod - def _isValidFunction(value: Any, var: str) -> None: - if not callable(value) and value is not None: - raise TypeError( + def _isValidFunction(value: any, var: str) -> None: + if not callable(value) and value != None: + raise FunctionError( f'''{Validate._var_font(var)} {Validate._error_font("must be function with two parameters or *args.")}''' ) - @staticmethod - def _isValidXAxisIndices(values: Tuple[Any, ...], indices: Tuple[int, ...], var: str) -> None: - if indices is not None: + def _isValidXAxisIndices(values: tuple, indices: tuple, var: str) -> None: + if indices != None: Validate._isTuple(indices, var) - Validate._isValidIndices(indices, var) for index in indices: if index >= len(values): raise IndexError( f'''{Validate._var_font(var)} {Validate._error_font("values must be lower than length of x_axis_values.")}''' ) - @staticmethod - def _isValidXAxisLabelCount(values: Any, var: str) -> None: - if values is not None: + def _isValidXAxisLabelCount(values: any, var: str) -> None: + if values != None: Validate._isInt(values, var) - @staticmethod - def _isValidStyleType(value: Any, var: str) -> None: + def _isValidStyleType(value: any, var: str) -> None: Validate._isTuple(value, var) if len(value) == 2: - if type(value[0]) is int and type(value[1]) is int: + if type(value[0]) == int and type(value[1]) == int: ... else: raise TypeError( f'''{Validate._var_font(var)} {Validate._error_font("values must be integers.")}''' ) else: - raise ValueError( + raise LengthError( f'''{Validate._var_font(var)} {Validate._error_font("length must be two.")}''' ) - @staticmethod - def _isValidDataPostion(value: Any, var: str) -> None: + def _isValidDataPostion(value: any, var: str) -> None: Validate._isStr(value, var) if value == "top" or value == "side": ... @@ -133,8 +120,7 @@ def _isValidDataPostion(value: Any, var: str) -> None: f'''{Validate._var_font(var)} {Validate._error_font("must be 'top' or 'side'.")}''' ) - @staticmethod - def _isValidLineStyle(value: Any, var: str) -> None: + def _isValidLineStyle(value: any, var: str) -> None: Validate._isStr(value, var) if value == "dotted" or value == "dashed" or value == "normal": ... @@ -143,8 +129,7 @@ def _isValidLineStyle(value: Any, var: str) -> None: f'''{Validate._var_font(var)} {Validate._error_font("must be 'normal' or 'dotted' or 'dashed'.")}''' ) - @staticmethod - def _isValidSectionStyle(value: Any, var: str) -> None: + def _isValidSectionStyle(value: any, var: str) -> None: Validate._isStr(value, var) if value == "dashed" or value == "normal": ... @@ -153,19 +138,17 @@ def _isValidSectionStyle(value: Any, var: str) -> None: f'''{Validate._var_font(var)} {Validate._error_font("must be 'normal' or 'dashed'.")}''' ) - @staticmethod - def _isValidXAxisPointSpacing(value: Any, var: str) -> None: - if type(value) is int: + def _isValidLineWidth(value: any, var: str) -> None: + if type(value) == int: ... - elif type(value) is str and value == "auto": + elif type(value) == str and value == "auto": ... else: raise TypeError( f'''{Validate._var_font(var)} {Validate._error_font("must be integer or 'auto'.")}''' ) - @staticmethod - def _isValidPointerState_Lock(value: Any, var: str) -> None: + def _isValidPointerState_Lock(value: any, var: str) -> None: Validate._isStr(value, var) if value == "disabled" or value == "enabled": ... @@ -173,19 +156,8 @@ def _isValidPointerState_Lock(value: Any, var: str) -> None: raise ValueError( f'''{Validate._var_font(var)} {Validate._error_font("must be 'disabled' or 'enabled'.")}''' ) - - @staticmethod - def _isValidLineHighlight(value: Any, var: str) -> None: - Validate._isStr(value, var) - if value == "disabled" or value == "enabled": - ... - else: - raise ValueError( - f'''{Validate._var_font(var)} {Validate._error_font("must be 'disabled' or 'enabled'.")}''' - ) - - @staticmethod - def _isValidLineFill(value: Any, var: str) -> None: + + def _isValidLineHighlight(value: any, var: str) -> None: Validate._isStr(value, var) if value == "disabled" or value == "enabled": ... @@ -193,17 +165,13 @@ def _isValidLineFill(value: Any, var: str) -> None: raise ValueError( f'''{Validate._var_font(var)} {Validate._error_font("must be 'disabled' or 'enabled'.")}''' ) + - @staticmethod - def _isValidYAxisValues(value: Any, var: str) -> None: + def _isValidYAxisValues(value: any, var: str) -> None: Validate._isTuple(value, var) - if value == (None, None): - raise ValueError( - f'''{Validate._var_font(var)} {Validate._error_font("must be provide.")}''' - ) if len(value) == 2: - if type(value[0]) is int or type(value[0]) is float and type( - value[1]) is int or type(value[1]) is float: + if type(value[0]) == int or type(value[0]) == float and type( + value[1]) == int or type(value[1]) == float: if value[0] < value[1]: ... else: @@ -215,73 +183,13 @@ def _isValidYAxisValues(value: Any, var: str) -> None: f'''{Validate._var_font(var)} {Validate._error_font("values must be integer or float.")}''' ) else: - raise ValueError( + raise LengthError( f'''{Validate._var_font(var)} {Validate._error_font("length must be two.")}''' ) - @staticmethod - def _isValidXAxisValues(value: Any, var: str) -> None: - if value == (None, "None", None, "None"): - raise ValueError( - f'''{Validate._var_font(var)} {Validate._error_font("must be provide.")}''' - ) - Validate._isTuple(value, "x_axis_values") - - @staticmethod - def _isValidCTkLine(value: Any, var: str) -> None: - from .CTkLine import CTkLine - if type(value) is not CTkLine: + def _isValidYAxisMaxValue(value: any, var: str) -> None: + Validate._isNumeric(value, var) + if value == 0: raise TypeError( - f'''{Validate._var_font(var)} {Validate._error_font("type must be ctkchart.CTkLine")}''' + f'''{Validate._var_font(var)} {Validate._error_font("must be less than 0 or bigger than 0")}''' ) - - @staticmethod - def _isValidCTkLineChart(value: Any, var: str) -> None: - from .CTkLineChart import CTkLineChart - if type(value) is not CTkLineChart: - raise TypeError( - f'''{Validate._var_font(var)} {Validate._error_font("type must be ctkchart.CTkLineChart")}''' - ) - - @staticmethod - def _isValidData(value: Any, var: str) -> None: - Validate._isList(value, var) - if all(isinstance(value, (int, float)) for value in value): - ... - else: - raise TypeError( - f'''{Validate._var_font(var)} {Validate._error_font("all values in the list should be either int or float.")}''' - ) - - @staticmethod - def _isValidIndices(value: Any, var: str) -> None: - if all(isinstance(value, int) for value in value): - ... - else: - raise TypeError( - f'''{Validate._var_font(var)} {Validate._error_font("all values should be int.")}''' - ) - - @staticmethod - def _invalidCget(var: str) -> None: - raise TypeError( - f'''{Validate._var_font(str(var))} {Validate._error_font("Invalid attribute.")}''' - ) - - @staticmethod - def _invalidCTkLine(line) -> None: - raise ValueError( - f'''{Validate._var_font(str(line))} {Validate._error_font("The line is not part of this line chart.")}''' - ) - - @staticmethod - def _invalidMaster(value): - raise ValueError( - f'''{Validate._var_font(str(value))} {Validate._error_font("Invalid Master for chart.")}''' - ) - - @staticmethod - def _MasterAttNotProvideForLine(value): - raise ValueError( - f'''{Validate._var_font(str(value))} {Validate._error_font("master must be provide for CTkLine")}''' - ) diff --git a/src/ctkchart/__init__.py b/src/ctkchart/__init__.py index 710aa69..3a1bf26 100644 --- a/src/ctkchart/__init__.py +++ b/src/ctkchart/__init__.py @@ -1,21 +1,5 @@ -from .CTkLineChart import CTkLineChart -from .CTkLine import CTkLine +from .CTkLineChart import * +from .CTkLine import * +from .Exceptions import * -ENABLED: str = "enabled" -DISABLED: str = "disabled" - -NORMAL: str = "normal" -DASHED: str = "dashed" -DOTTED: str = "dotted" - -TOP: str = "top" -SIDE: str = "side" - -AUTO: str = "auto" - -""" -ctkchart: a library for create live update chart for customtkinter guis. -""" -__title__ = "ctkchart" -__version__ = "2.1.6" -__authors__ = ("Thisal Dilmith", "childeyouyu (有语)") +__version__ = "0.0.1" diff --git a/template(s)/Template (8).py b/template(s)/Template (8).py deleted file mode 100644 index e2ff5d6..0000000 --- a/template(s)/Template (8).py +++ /dev/null @@ -1,52 +0,0 @@ -import customtkinter as ctk -import ctkchart -import random - -#root -root = ctk.CTk() -root.geometry("700x400+500+300") -#creating a chart -chart = ctkchart.CTkLineChart(master=root, - width=1700, - height=800, - axis_size=5, - x_axis_values = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10), - y_axis_values = (-1000,1000), - y_axis_label_count=10, - - x_axis_section_color=("#aaaaaa","#555555"), - y_axis_section_color=("#aaaaaa","#555555"), - - y_axis_font_color=("#454545", "#aaaaaa"), - x_axis_font_color=("#454545", "#aaaaaa"), - data_font_style=("arial", 17, "bold"), - axis_font_style=("arial", 13, "bold"), - x_axis_data_font_color=("#505050","#efefef"), - y_axis_data_font_color=("#505050","#efefef"), - - y_space=20, - x_space=20, - ) -chart.pack(pady=40) - -#creating a line -line1 = ctkchart.CTkLine(master=chart, - size=3, - style="normal", - - fill="enabled", - point_highlight="enabled", - point_highlight_size=15, - ) - - - - -data = [x for x in range(-1000,1000)] -#dipslay data (random) -def loop(): - chart.show_data(line=line1, data=random.choices(data, k=1)) - root.after(500, loop) -loop() - -root.mainloop() \ No newline at end of file diff --git a/template(s)/template (1).py b/template(s)/template (1).py deleted file mode 100644 index 8e5d8f7..0000000 --- a/template(s)/template (1).py +++ /dev/null @@ -1,27 +0,0 @@ -import customtkinter as ctk -import ctkchart -import random - -root = ctk.CTk() -root.geometry("600+300") -root.title("Line Chart") -chart = ctkchart.CTkLineChart(master=root, - y_axis_values = (-100,100), - x_axis_values = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10), - pointer_state="enabled" - ) -chart.pack() - -line = ctkchart.CTkLine(master=chart, - size=1) - #point_highlight="enabled", - #fill="enabled") - - - -data = [x for x in range(-100,100)] -def loop(): - chart.show_data(line=line, data=[0, -80, -40, 100, 0, 80, 50, -50, -10,80,50,100]) -loop() - -root.mainloop() \ No newline at end of file diff --git a/template(s)/template (2).py b/template(s)/template (2).py deleted file mode 100644 index 244b949..0000000 --- a/template(s)/template (2).py +++ /dev/null @@ -1,29 +0,0 @@ -import customtkinter as ctk -import ctkchart -import random - -root = ctk.CTk() -root.geometry("600+300") -root.title("Line Chart") -chart = ctkchart.CTkLineChart(master=root, - y_axis_values = (-100,100), - x_axis_values = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10), - pointer_state="enabled" - ) -chart.pack() - -line = ctkchart.CTkLine(master=chart, - size=1, - point_highlight="enabled",) - #fill="enabled") - - - -data = [x for x in range(-100,100)] -def loop(): - chart.show_data(line=line, data=[0, -80, -40, 100, 0, 80, 50, -50, -10,80,50,100]) - - -loop() - -root.mainloop() \ No newline at end of file diff --git a/template(s)/template (3).py b/template(s)/template (3).py deleted file mode 100644 index f9963b6..0000000 --- a/template(s)/template (3).py +++ /dev/null @@ -1,29 +0,0 @@ -import customtkinter as ctk -import ctkchart -import random - -root = ctk.CTk() -root.geometry("600+300") -root.title("Line Chart") -chart = ctkchart.CTkLineChart(master=root, - y_axis_values = (-100,100), - x_axis_values = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10), - pointer_state="enabled" - ) -chart.pack() - -line = ctkchart.CTkLine(master=chart, - size=1, - point_highlight="enabled", - fill="enabled") - - - -data = [x for x in range(-100,100)] -def loop(): - chart.show_data(line=line, data=[0, -80, -40, 100, 0, 80, 50, -50, -10,80,50,100]) - - -loop() - -root.mainloop() \ No newline at end of file diff --git a/template(s)/template (4).py b/template(s)/template (4).py deleted file mode 100644 index 84b0e0d..0000000 --- a/template(s)/template (4).py +++ /dev/null @@ -1,32 +0,0 @@ -import customtkinter as ctk -import ctkchart -import random - -root = ctk.CTk() -root.geometry("600+300") -root.title("Line Chart") -chart = ctkchart.CTkLineChart(master=root, - y_axis_values = (-100,100), - x_axis_values = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10), - - - ) -chart.pack() - -line = ctkchart.CTkLine(master=chart, - size=1, - style="dashed", - style_type=(10,5), - point_highlight="enabled",) - #fill="enabled") - - - -data = [x for x in range(-100,100)] -def loop(): - chart.show_data(line=line, data=[0, -80, -40, 100, 0, 80, 50, -50, -10,80,50,100]) - - -loop() - -root.mainloop() \ No newline at end of file diff --git a/template(s)/template (5).py b/template(s)/template (5).py deleted file mode 100644 index ef7616e..0000000 --- a/template(s)/template (5).py +++ /dev/null @@ -1,32 +0,0 @@ -import customtkinter as ctk -import ctkchart -import random - -root = ctk.CTk() -root.geometry("600+300") -root.title("Line Chart") -chart = ctkchart.CTkLineChart(master=root, - y_axis_values = (-100,100), - x_axis_values = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10), - - - ) -chart.pack() - -line = ctkchart.CTkLine(master=chart, - size=1, - style="dotted", - style_type=(4,5), - point_highlight="enabled",) - #fill="enabled") - - - -data = [x for x in range(-100,100)] -def loop(): - chart.show_data(line=line, data=[0, -80, -40, 100, 0, 80, 50, -50, -10,80,50,100]) - - -loop() - -root.mainloop() \ No newline at end of file diff --git a/template(s)/template (6).py b/template(s)/template (6).py deleted file mode 100644 index c1a0073..0000000 --- a/template(s)/template (6).py +++ /dev/null @@ -1,31 +0,0 @@ -import customtkinter as ctk -import ctkchart -import random - -root = ctk.CTk() -root.geometry("600+300") -root.title("Line Chart") -chart = ctkchart.CTkLineChart(master=root, - y_axis_values = (-100,100), - x_axis_values = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10), - - ) -chart.pack() - -line = ctkchart.CTkLine(master=chart, - size=3, - point_highlight="enabled", - style="dashed", - style_type=(20,5), - fill="enabled") - - - -data = [x for x in range(-100,100)] -def loop(): - chart.show_data(line=line, data=[0, -80, -40, 100, 0, 80, 50, -50, -10,80,50,100]) - - -loop() - -root.mainloop() \ No newline at end of file diff --git a/template(s)/template (7).py b/template(s)/template (7).py deleted file mode 100644 index aad6a79..0000000 --- a/template(s)/template (7).py +++ /dev/null @@ -1,37 +0,0 @@ -import customtkinter as ctk -import ctkchart -import random - -root = ctk.CTk() -root.geometry("600+300") -root.title("Line Chart") -chart = ctkchart.CTkLineChart(master=root, - y_axis_values = (-100,100), - x_axis_values = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10), - - ) -chart.pack() - -line = ctkchart.CTkLine(master=chart, - size=2, - point_highlight="enabled", - style="dashed", - style_type=(20,5), - fill="disabled") - -line2 = ctkchart.CTkLine(master=chart, - size=3,style="normal", - style_type=(15,7), - color=("#5dffb6","#5dffb6"), - fill="enabled", - fill_color = ("#5dffb6","#5dffb6") - ) - -data = [x for x in range(-100,100)] -def loop(): - chart.show_data(line=line, data=[0, -80, -40, 100, 0, 80, 50, -50, -10,80,50,100]) - chart.show_data(line=line2, data=[100, -10, -90, 40, -30, 40, 90,-90, -40,-100,40,0]) - -loop() - -root.mainloop() \ No newline at end of file diff --git a/tests/main - test.py b/tests/main - test.py deleted file mode 100644 index f22ad3b..0000000 --- a/tests/main - test.py +++ /dev/null @@ -1,571 +0,0 @@ -import ctkchart -import customtkinter as ctk -import random - -root = ctk.CTk() -root.geometry("1900x900") - -data = ([x for x in range(0,1001)]) -x_axis_values = tuple([x for x in range(1,21)]) -line_chart = ctkchart.CTkLineChart(master=root, - x_axis_values=x_axis_values, y_axis_values=(0, 1000)) -line_chart.pack() - - -line = ctkchart.CTkLine(master=line_chart, style="dashed", style_type=(10,5), size=1, color=("#404040", "lightblue"), fill="enabled", - point_highlight="enabled", point_highlight_size=5, point_highlight_color=("#404040", "lightblue")) - -def loop(): - line_chart.show_data(line=line ,data=[random.choice(data)]) - root.after(100, loop) -loop() - - -frame = ctk.CTkScrollableFrame(master=root, width=1000, height=900, fg_color=("#FFFFFF","#151515")) -frame.pack(pady=100) - -def line_chart_configure(**kwrgs): - line_chart.configure(**kwrgs) - -def line_configure(**kwrgs): - line.configure(**kwrgs) - -row = 1 -ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Line Chart Attributes : ", font=("Arial",25,"bold")).grid(row=row, column=1) -row += 1 -ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Width : ").grid(row=row, column=1) -column = 2 -for width in range(900,1600,100): - ctk.CTkButton(master=frame, text="{}".format(width), width=90, height=30, command=lambda width_=width: line_chart_configure(width=width_)).grid(row=row, column=column, padx=10, pady=2) - column += 1 - -row += 1 -ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) -row += 1 -ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Height : ").grid(row=row, column=1) -column = 2 -for height in range(350,900,50): - ctk.CTkButton(master=frame, text="{}".format(height), width=90, height=30, command=lambda height_=height: line_chart_configure(height=height_)).grid(row=row, column=column, padx=10, pady=2) - column += 1 - -row += 1 -ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) -row += 1 -ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Axis Size : ").grid(row=row, column=1) -column = 2 -for axis_size in range(1,9,1): - ctk.CTkButton(master=frame, text="{}".format(axis_size), width=90, height=30, command=lambda axis_size_=axis_size: line_chart_configure(axis_size=axis_size_)).grid(row=row, column=column, padx=10, pady=2) - column += 1 - -row += 1 -ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) -row += 1 -ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Y Axis Labels : ").grid(row=row, column=1) -column = 2 -for y_axis_label_count in range(0,14,2): - ctk.CTkButton(master=frame, text="{}".format(y_axis_label_count), width=90, height=30, command=lambda y_axis_label_count_=y_axis_label_count: line_chart_configure(y_axis_label_count=y_axis_label_count_)).grid(row=row, column=column, padx=10, pady=2) - column += 1 - -row += 1 -ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) -row += 1 -ctk.CTkLabel(text_color=("black", "white"), master=frame, text="X Axis Labels : ").grid(row=row, column=1) -column = 2 -for x_axis_label_count in [0, 1, 2, 4, 5, 10, 20]: - ctk.CTkButton(master=frame, text="{}".format(x_axis_label_count), width=90, height=30, command=lambda x_axis_label_count_=x_axis_label_count: line_chart_configure(x_axis_label_count=x_axis_label_count_)).grid(row=row, column=column, padx=10, pady=2) - column += 1 - -row += 1 -ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) -row += 1 -ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Y Axis Precision : ").grid(row=row, column=1) -column = 2 -for y_axis_precision in range(0,9,1): - ctk.CTkButton(master=frame, text="{}".format(y_axis_precision), width=90, height=30, command=lambda y_axis_precision_=y_axis_precision: line_chart_configure(y_axis_precision=y_axis_precision_)).grid(row=row, column=column, padx=10, pady=2) - column += 1 - -row += 1 -ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) -row += 1 -ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Y Axis values : ").grid(row=row, column=1) -column = 2 -values = [(-1000, 1000), (0, 1000), (-2000, 1000), (0, 2000), (-5000,2000)] -for i in range(5): - ctk.CTkButton(master=frame, text="{}".format(values[i]), width=90, height=30, command=lambda y_axis_values_=values[i]: line_chart_configure(y_axis_values=y_axis_values_)).grid(row=row, column=column, padx=10, pady=2) - column += 1 - -row += 1 -ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) -row += 1 -ctk.CTkLabel(text_color=("black", "white"), master=frame, text="X Axis Values : ").grid(row=row, column=1) -column = 2 -for x_axis_values in range(1, 90, 10): - ctk.CTkButton(master=frame, text="range({},{})".format(x_axis_values,x_axis_values+20), width=90, height=30, - command=lambda x_axis_values_=[x for x in range(x_axis_values,x_axis_values+20)]: line_chart_configure(x_axis_values=tuple(x_axis_values_)) - ).grid(row=row, column=column, padx=10, pady=2) - column += 1 - -row += 1 -ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) -row += 1 -ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Y Axis Sections : ").grid(row=row, column=1) -column = 2 -for y_axis_section_count in range(0, 14, 2): - ctk.CTkButton(master=frame, text="{}".format(y_axis_section_count), width=90, height=30, command=lambda y_axis_section_count_=y_axis_section_count: line_chart_configure(y_axis_section_count=y_axis_section_count_)).grid(row=row, column=column, padx=10, pady=2) - column += 1 - -row += 1 -ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) -row += 1 -ctk.CTkLabel(text_color=("black", "white"), master=frame, text="X Axis Sections : ").grid(row=row, column=1) -column = 2 -for x_axis_section_count in range(0, 14, 2): - ctk.CTkButton(master=frame, text="{}".format(x_axis_section_count), width=90, height=30, command=lambda x_axis_section_count_=x_axis_section_count: line_chart_configure(x_axis_section_count=x_axis_section_count_)).grid(row=row, column=column, padx=10, pady=2) - column += 1 - -row += 1 -ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) -row += 1 -ctk.CTkLabel(text_color=("black", "white"), master=frame, text="x axis point spacing : ").grid(row=row, column=1) -ctk.CTkButton(master=frame, text="{}".format("Auto"), width=90, height=30, command=lambda : line_chart_configure(x_axis_point_spacing="auto")).grid(row=row, column=2, padx=10, pady=2) -column = 3 -for x_axis_point_spacing in range(10, 40, 5): - ctk.CTkButton(master=frame, text="{}".format(x_axis_point_spacing), width=90, height=30, command=lambda x_axis_point_spacing_=x_axis_point_spacing: line_chart_configure(x_axis_point_spacing=x_axis_point_spacing_)).grid(row=row, column=column, padx=10, pady=2) - column += 1 - -row += 1 -ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) -row += 1 -ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Y Space : ").grid(row=row, column=1) -column = 2 -for y_space in range(0, 90, 10): - ctk.CTkButton(master=frame, text="{}".format(y_space), width=90, height=30, command=lambda y_space_=y_space: line_chart_configure(y_space=y_space_)).grid(row=row, column=column, padx=10, pady=2) - column += 1 - -row += 1 -ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) -row += 1 -ctk.CTkLabel(text_color=("black", "white"), master=frame, text="X Space : ").grid(row=row, column=1) -column = 2 -for x_space in range(0, 90, 10): - ctk.CTkButton(master=frame, text="{}".format(x_space), width=90, height=30, command=lambda x_space_=x_space: line_chart_configure(x_space=x_space_)).grid(row=row, column=column, padx=10, pady=2) - column += 1 - -row += 1 -ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) -row += 1 -ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Y Axis Data : ").grid(row=row, column=1) -column = 2 -ctk.CTkButton(master=frame, text="{}".format("Y"), width=90, height=30, command=lambda:line_chart_configure(y_axis_data="Y")).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("Y-AXIS"), width=90, height=30, command=lambda:line_chart_configure(y_axis_data="Y-AXIS")).grid(row=row, column=column, padx=10, pady=2) - -row += 1 -ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) -row += 1 -ctk.CTkLabel(text_color=("black", "white"), master=frame, text="X Axis Data : ").grid(row=row, column=1) -column = 2 -ctk.CTkButton(master=frame, text="{}".format("X"), width=90, height=30, command=lambda:line_chart_configure(x_axis_data="X")).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("X-AXIS"), width=90, height=30, command=lambda:line_chart_configure(x_axis_data="X-AXIS")).grid(row=row, column=column, padx=10, pady=2) - -row += 1 -ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) -row += 1 -ctk.CTkLabel(text_color=("black", "white"), master=frame, text="X Axis Data Position : ").grid(row=row, column=1) -column = 2 -ctk.CTkButton(master=frame, text="{}".format("top"), width=90, height=30, command=lambda:line_chart_configure(x_axis_data_position="top")).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("side"), width=90, height=30, command=lambda:line_chart_configure(x_axis_data_position="side")).grid(row=row, column=column, padx=10, pady=2) - -row += 1 -ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) -row += 1 -ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Y Axis Data Position : ").grid(row=row, column=1) -column = 2 -ctk.CTkButton(master=frame, text="{}".format("top"), width=90, height=30, command=lambda:line_chart_configure(y_axis_data_position="top")).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("side"), width=90, height=30, command=lambda:line_chart_configure(y_axis_data_position="side")).grid(row=row, column=column, padx=10, pady=2) - -row += 1 -ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) -row += 1 -ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Data Font Style : ").grid(row=row, column=1) -column = 2 -ctk.CTkButton(master=frame, text="{}".format("('arial',10,'normal')"), width=90, height=30, command=lambda:line_chart_configure(data_font_style=("arial",10,"normal"))).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("('arial',10,'bold')"), width=90, height=30, command=lambda:line_chart_configure(data_font_style=("arial",10,"bold"))).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("('arial',15,'normal')"), width=90, height=30, command=lambda:line_chart_configure(data_font_style=("arial",15,"normal"))).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("('arial',15,'bold')"), width=90, height=30, command=lambda:line_chart_configure(data_font_style=("arial",15,"bold"))).grid(row=row, column=column, padx=10, pady=2) - -row += 1 -ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) -row += 1 -ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Axis Font Style : ").grid(row=row, column=1) -column = 2 -ctk.CTkButton(master=frame, text="{}".format("('arial',10,'normal')"), width=90, height=30, command=lambda:line_chart_configure(axis_font_style=("arial",10,"normal"))).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("('arial',10,'bold')"), width=90, height=30, command=lambda:line_chart_configure(axis_font_style=("arial",10,"bold"))).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("('arial',12,'normal')"), width=90, height=30, command=lambda:line_chart_configure(axis_font_style=("arial",12,"normal"))).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("('arial',12,'bold')"), width=90, height=30, command=lambda:line_chart_configure(axis_font_style=("arial",12,"bold"))).grid(row=row, column=column, padx=10, pady=2) - -row += 1 -ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) -row += 1 -ctk.CTkLabel(text_color=("black", "white"), master=frame, text="X Section Color : ").grid(row=row, column=1) -column = 2 -ctk.CTkButton(master=frame, text="{}".format("#000000"), width=90, height=30, command=lambda:line_chart_configure(x_axis_section_color="#000000")).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("#303030"), width=90, height=30, command=lambda:line_chart_configure(x_axis_section_color="#303030")).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("#454545"), width=90, height=30, command=lambda:line_chart_configure(x_axis_section_color="#454545")).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("#606060"), width=90, height=30, command=lambda:line_chart_configure(x_axis_section_color="#606060")).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("#757575"), width=90, height=30, command=lambda:line_chart_configure(x_axis_section_color="#757575")).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("#909090"), width=90, height=30, command=lambda:line_chart_configure(x_axis_section_color="#909090")).grid(row=row, column=column, padx=10, pady=2) -column += 1 - - -row += 1 -ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) -row += 1 -ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Y Section Color : ").grid(row=row, column=1) -column = 2 -ctk.CTkButton(master=frame, text="{}".format("#000000"), width=90, height=30, command=lambda:line_chart_configure(y_axis_section_color="#000000")).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("#303030"), width=90, height=30, command=lambda:line_chart_configure(y_axis_section_color="#303030")).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("#454545"), width=90, height=30, command=lambda:line_chart_configure(y_axis_section_color="#454545")).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("#606060"), width=90, height=30, command=lambda:line_chart_configure(y_axis_section_color="#606060")).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("#757575"), width=90, height=30, command=lambda:line_chart_configure(y_axis_section_color="#757575")).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("#909090"), width=90, height=30, command=lambda:line_chart_configure(y_axis_section_color="#909090")).grid(row=row, column=column, padx=10, pady=2) -column += 1 - - -row += 1 -ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) -row += 1 -ctk.CTkLabel(text_color=("black", "white"), master=frame, text="X Axis Section Style : ").grid(row=row, column=1) -column = 2 -ctk.CTkButton(master=frame, text="{}".format("normal"), width=90, height=30, command=lambda:line_chart_configure(x_axis_section_style="normal")).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("dashed"), width=90, height=30, command=lambda:line_chart_configure(x_axis_section_style="dashed")).grid(row=row, column=column, padx=10, pady=2) -column += 1 - -row += 1 -ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) -row += 1 -ctk.CTkLabel(text_color=("black", "white"), master=frame, text="X Axis Style Type : ").grid(row=row, column=1) -column = 2 -ctk.CTkButton(master=frame, text="{}".format("(10, 5)"), width=90, height=30, command=lambda:line_chart_configure(x_axis_section_style_type=(10, 5))).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("(20, 5)"), width=90, height=30, command=lambda:line_chart_configure(x_axis_section_style_type=(20, 5))).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("(20, 10)"), width=90, height=30, command=lambda:line_chart_configure(x_axis_section_style_type=(10, 20))).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("(20, 10)"), width=90, height=30, command=lambda:line_chart_configure(x_axis_section_style_type=(20, 10))).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("(5, 5)"), width=90, height=30, command=lambda:line_chart_configure(x_axis_section_style_type=(5, 5))).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("(20, 20)"), width=90, height=30, command=lambda:line_chart_configure(x_axis_section_style_type=(20, 20))).grid(row=row, column=column, padx=10, pady=2) -column += 1 - -row += 1 -ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) -row += 1 -ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Y Axis Section Style : ").grid(row=row, column=1) -column = 2 -ctk.CTkButton(master=frame, text="{}".format("normal"), width=90, height=30, command=lambda:line_chart_configure(y_axis_section_style="normal")).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("dashed"), width=90, height=30, command=lambda:line_chart_configure(y_axis_section_style="dashed")).grid(row=row, column=column, padx=10, pady=2) -column += 1 - -row += 1 -ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) -row += 1 -ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Y Axis Style Type : ").grid(row=row, column=1) -column = 2 -ctk.CTkButton(master=frame, text="{}".format("(10, 5)"), width=90, height=30, command=lambda:line_chart_configure(y_axis_section_style_type=(10, 5))).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("(20, 5)"), width=90, height=30, command=lambda:line_chart_configure(y_axis_section_style_type=(20, 5))).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("(20, 10)"), width=90, height=30, command=lambda:line_chart_configure(y_axis_section_style_type=(10, 20))).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("(20, 10)"), width=90, height=30, command=lambda:line_chart_configure(y_axis_section_style_type=(20, 10))).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("(5, 5)"), width=90, height=30, command=lambda:line_chart_configure(y_axis_section_style_type=(5, 5))).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("(20, 20)"), width=90, height=30, command=lambda:line_chart_configure(y_axis_section_style_type=(20, 20))).grid(row=row, column=column, padx=10, pady=2) -column += 1 - - -row += 1 -ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) -row += 1 -ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Axis Color : ").grid(row=row, column=1) -column = 2 -ctk.CTkButton(master=frame, text="{}".format("#000000"), width=90, height=30, command=lambda:line_chart_configure(axis_color="#000000")).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("#151515"), width=90, height=30, command=lambda:line_chart_configure(axis_color="#151515")).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("#252525"), width=90, height=30, command=lambda:line_chart_configure(axis_color="#252525")).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("#505050"), width=90, height=30, command=lambda:line_chart_configure(axis_color="#505050")).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("#909090"), width=90, height=30, command=lambda:line_chart_configure(axis_color="#909090")).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("#FFFFFF"), width=90, height=30, command=lambda:line_chart_configure(axis_color="#FFFFFF")).grid(row=row, column=column, padx=10, pady=2) -column += 1 - -row += 1 -ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) -row += 1 -ctk.CTkLabel(text_color=("black", "white"), master=frame, text="BG Color : ").grid(row=row, column=1) -column = 2 -ctk.CTkButton(master=frame, text="{}".format("#000000"), width=90, height=30, command=lambda:line_chart_configure(bg_color="#000000")).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("#151515"), width=90, height=30, command=lambda:line_chart_configure(bg_color="#151515")).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("#252525"), width=90, height=30, command=lambda:line_chart_configure(bg_color="#252525")).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("#505050"), width=90, height=30, command=lambda:line_chart_configure(bg_color="#505050")).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("#707070"), width=90, height=30, command=lambda:line_chart_configure(bg_color="#707070")).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("#FFFFFF"), width=90, height=30, command=lambda:line_chart_configure(bg_color="#FFFFFF")).grid(row=row, column=column, padx=10, pady=2) -column += 1 - -row += 1 -ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) -row += 1 -ctk.CTkLabel(text_color=("black", "white"), master=frame, text="FG Color : ").grid(row=row, column=1) -column = 2 -ctk.CTkButton(master=frame, text="{}".format("#000000"), width=90, height=30, command=lambda:line_chart_configure(fg_color="#000000")).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("#151515"), width=90, height=30, command=lambda:line_chart_configure(fg_color="#151515")).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("#252525"), width=90, height=30, command=lambda:line_chart_configure(fg_color="#252525")).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("#505050"), width=90, height=30, command=lambda:line_chart_configure(fg_color="#505050")).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("#707070"), width=90, height=30, command=lambda:line_chart_configure(fg_color="#707070")).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("#FFFFFF"), width=90, height=30, command=lambda:line_chart_configure(fg_color="#FFFFFF")).grid(row=row, column=column, padx=10, pady=2) -column += 1 - -row += 1 -ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) -row += 1 -ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Y Axis Font Color : ").grid(row=row, column=1) -column = 2 -ctk.CTkButton(master=frame, text="{}".format("#000000"), width=90, height=30, command=lambda:line_chart_configure(y_axis_font_color="#000000")).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("#151515"), width=90, height=30, command=lambda:line_chart_configure(y_axis_font_color="#151515")).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("#252525"), width=90, height=30, command=lambda:line_chart_configure(y_axis_font_color="#252525")).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("#505050"), width=90, height=30, command=lambda:line_chart_configure(y_axis_font_color="#505050")).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("#707070"), width=90, height=30, command=lambda:line_chart_configure(y_axis_font_color="#707070")).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("#FFFFFF"), width=90, height=30, command=lambda:line_chart_configure(y_axis_font_color="#FFFFFF")).grid(row=row, column=column, padx=10, pady=2) -column += 1 - -row += 1 -ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) -row += 1 -ctk.CTkLabel(text_color=("black", "white"), master=frame, text="X Axis Font Color : ").grid(row=row, column=1) -column = 2 -ctk.CTkButton(master=frame, text="{}".format("#000000"), width=90, height=30, command=lambda:line_chart_configure(x_axis_font_color="#000000")).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("#151515"), width=90, height=30, command=lambda:line_chart_configure(x_axis_font_color="#151515")).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("#252525"), width=90, height=30, command=lambda:line_chart_configure(x_axis_label_count_axis_font_color="#252525")).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("#505050"), width=90, height=30, command=lambda:line_chart_configure(x_axis_font_color="#505050")).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("#707070"), width=90, height=30, command=lambda:line_chart_configure(x_axis_font_color="#707070")).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("#FFFFFF"), width=90, height=30, command=lambda:line_chart_configure(x_axis_font_color="#FFFFFF")).grid(row=row, column=column, padx=10, pady=2) -column += 1 - -row += 1 -ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) -row += 1 -ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Y Axis Data Font Color : ").grid(row=row, column=1) -column = 2 -ctk.CTkButton(master=frame, text="{}".format("#000000"), width=90, height=30, command=lambda:line_chart_configure(y_axis_data_font_color="#000000")).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("#151515"), width=90, height=30, command=lambda:line_chart_configure(y_axis_data_font_color="#151515")).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("#252525"), width=90, height=30, command=lambda:line_chart_configure(y_axis_data_font_color="#252525")).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("#505050"), width=90, height=30, command=lambda:line_chart_configure(y_axis_data_font_color="#505050")).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("#707070"), width=90, height=30, command=lambda:line_chart_configure(y_axis_data_font_color="#707070")).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("#FFFFFF"), width=90, height=30, command=lambda:line_chart_configure(y_axis_data_font_color="#FFFFFF")).grid(row=row, column=column, padx=10, pady=2) -column += 1 - -row += 1 -ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) -row += 1 -ctk.CTkLabel(text_color=("black", "white"), master=frame, text="X Axis Data Font Color : ").grid(row=row, column=1) -column = 2 -ctk.CTkButton(master=frame, text="{}".format("#000000"), width=90, height=30, command=lambda:line_chart_configure(x_axis_data_font_color="#000000")).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("#151515"), width=90, height=30, command=lambda:line_chart_configure(x_axis_data_font_color="#151515")).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("#252525"), width=90, height=30, command=lambda:line_chart_configure(x_axis_data_font_color="#252525")).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("#505050"), width=90, height=30, command=lambda:line_chart_configure(x_axis_data_font_color="#505050")).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("#707070"), width=90, height=30, command=lambda:line_chart_configure(x_axis_data_font_color="#707070")).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("#FFFFFF"), width=90, height=30, command=lambda:line_chart_configure(x_axis_data_font_color="#FFFFFF")).grid(row=row, column=column, padx=10, pady=2) -column += 1 - -row += 1 -ctk.CTkFrame(master=frame ,height=10, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) - -row += 1 -ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Line Attributes : ", font=("Arial",25,"bold")).grid(row=row, column=1) - -row += 1 -ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) -row += 1 -ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Size : ").grid(row=row, column=1) -column = 2 -ctk.CTkButton(master=frame, text="{}".format(1), width=90, height=30, command=lambda:line_configure(size=1)).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format(2), width=90, height=30, command=lambda:line_configure(size=2)).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format(4), width=90, height=30, command=lambda:line_configure(size=4)).grid(row=row, column=column, padx=10, pady=2) - -row += 1 -ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) -row += 1 -ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Style : ").grid(row=row, column=1) -column = 2 -ctk.CTkButton(master=frame, text="{}".format("line"), width=90, height=30, command=lambda:line_configure(style="normal")).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("dashed"), width=90, height=30, command=lambda:line_configure(style="dashed")).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("dotted"), width=90, height=30, command=lambda:line_configure(style="dotted")).grid(row=row, column=column, padx=10, pady=2) - - -row += 1 -ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) -row += 1 -ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Style Type : ").grid(row=row, column=1) -column = 2 -ctk.CTkButton(master=frame, text="{}".format("(5,10)"), width=90, height=30, command=lambda:line_configure(style_type=(5,10))).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("(20,10)"), width=90, height=30, command=lambda:line_configure(style_type=(20,10))).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("(10,5)"), width=90, height=30, command=lambda:line_configure(style_type=(10,5))).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("(10,30)"), width=90, height=30, command=lambda:line_configure(style_type=(10,30))).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("(1,1)"), width=90, height=30, command=lambda:line_configure(style_type=(1,1))).grid(row=row, column=column, padx=10, pady=2) - - - -row += 1 -ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) -row += 1 -ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Color : ").grid(row=row, column=1) -column = 2 -ctk.CTkButton(master=frame, text="{}".format("#FF0000"), width=90, height=30, command=lambda:line_configure(color="#FF0000")).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("00FF00"), width=90, height=30, command=lambda:line_configure(color="#00FF00")).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("#0000FF"), width=90, height=30, command=lambda:line_configure(color="#0000FF")).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("#FF00FF"), width=90, height=30, command=lambda:line_configure(color="#FF00FF")).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("#00FFFF"), width=90, height=30, command=lambda:line_configure(color="#00FFFF")).grid(row=row, column=column, padx=10, pady=2) - - - -row += 1 -ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) -row += 1 -ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Point Hightlight : ").grid(row=row, column=1) -column = 2 -ctk.CTkButton(master=frame, text="{}".format("enabled"), width=90, height=30, command=lambda:line_configure(point_highlight="enabled")).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("disabled"), width=90, height=30, command=lambda:line_configure(point_highlight="disabled")).grid(row=row, column=column, padx=10, pady=2) -column += 1 - - - -row += 1 -ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) -row += 1 -ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Point Hightlight Size : ").grid(row=row, column=1) -column = 2 -ctk.CTkButton(master=frame, text="{}".format("5"), width=90, height=30, command=lambda:line_configure(point_highlight_size=5)).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("10"), width=90, height=30, command=lambda:line_configure(point_highlight_size=10)).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("15"), width=90, height=30, command=lambda:line_configure(point_highlight_size=15)).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("20"), width=90, height=30, command=lambda:line_configure(point_highlight_size=20)).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("25"), width=90, height=30, command=lambda:line_configure(point_highlight_size=25)).grid(row=row, column=column, padx=10, pady=2) - - - -row += 1 -ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) -row += 1 -ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Point Hightlight Color : ").grid(row=row, column=1) -column = 2 -ctk.CTkButton(master=frame, text="{}".format("#FF0000"), width=90, height=30, command=lambda:line_configure(point_highlight_color="#FF0000")).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("00FF00"), width=90, height=30, command=lambda:line_configure(point_highlight_color="#00FF00")).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("#0000FF"), width=90, height=30, command=lambda:line_configure(point_highlight_color="#0000FF")).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("#FF00FF"), width=90, height=30, command=lambda:line_configure(point_highlight_color="#FF00FF")).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("#00FFFF"), width=90, height=30, command=lambda:line_configure(point_highlight_color="#00FFFF")).grid(row=row, column=column, padx=10, pady=2) - - -row += 1 -ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) -row += 1 -ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Fill : ").grid(row=row, column=1) -column = 2 -ctk.CTkButton(master=frame, text="{}".format("enabled"), width=90, height=30, command=lambda:line_configure(fill="enabled")).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("disabled"), width=90, height=30, command=lambda:line_configure(fill="disabled")).grid(row=row, column=column, padx=10, pady=2) -column += 1 - -row += 1 -ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) -row += 1 -ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Point Hightlight Color : ").grid(row=row, column=1) -column = 2 -ctk.CTkButton(master=frame, text="{}".format("#FF0000"), width=90, height=30, command=lambda:line_configure(fill_color="#FF0000")).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("00FF00"), width=90, height=30, command=lambda:line_configure(fill_color="#00FF00")).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("#0000FF"), width=90, height=30, command=lambda:line_configure(fill_color="#0000FF")).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("#FF00FF"), width=90, height=30, command=lambda:line_configure(fill_color="#FF00FF")).grid(row=row, column=column, padx=10, pady=2) -column += 1 -ctk.CTkButton(master=frame, text="{}".format("#00FFFF"), width=90, height=30, command=lambda:line_configure(fill_color="#00FFFF")).grid(row=row, column=column, padx=10, pady=2) - - -root.mainloop() \ No newline at end of file