├── .gitignore ├── SECURITY.md ├── requirements.txt ├── PULL_REQUEST_TEMPLATE.md ├── .github └── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── src └── ctkchart │ ├── __init__.py │ ├── FontStyle.py │ ├── ThemeManager.py │ ├── Utils.py │ ├── Validate.py │ └── CTkLine.py ├── template(s) ├── template (1).py ├── template (3).py ├── template (2).py ├── template (6).py ├── template (5).py ├── template (4).py ├── template (7).py └── Template (8).py ├── setup.py ├── LICENSE ├── CONTRIBUTING.md ├── CODE_OF_CONDUCT.md ├── CHANGES_zh.md ├── CHANGES_en.md ├── README_zh.md ├── README.md ├── documentation ├── DOCUMENTATION_zh.md └── DOCUMENTATION_en.md └── Tests └── Main - Test.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *.pyd -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | customtkinter -------------------------------------------------------------------------------- /PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Pull Request Checklist 2 | 3 | - [ ] Have you tested your changes? 4 | - [ ] Have you updated the documentation? 5 | - [ ] ... 6 | 7 | ## Description 8 | 9 | Briefly describe the changes introduced by this pull request. 10 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Additional context** 27 | Add any other context about the problem here. 28 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /src/ctkchart/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | ctkchart: a library for create live update chart for customtkinter guis. 3 | """ 4 | 5 | from .CTkLineChart import CTkLineChart 6 | from .CTkLine import CTkLine 7 | 8 | # Constants for common string values 9 | ENABLED = "enabled" 10 | DISABLED = "disabled" 11 | 12 | NORMAL = "normal" 13 | DASHED = "dashed" 14 | DOTTED = "dotted" 15 | 16 | TOP = "top" 17 | SIDE = "side" 18 | 19 | AUTO = "auto" 20 | 21 | __title__ = "ctkchart" 22 | __version__ = "2.1.9" 23 | __authors__ = ("Thisal Dilmith", "childeyouyu (有语)") 24 | 25 | __all__ = [ 26 | "CTkLineChart", 27 | "CTkLine", 28 | "ENABLED", 29 | "DISABLED", 30 | "NORMAL", 31 | "DASHED", 32 | "DOTTED", 33 | "TOP", 34 | "SIDE", 35 | "AUTO", 36 | ] 37 | -------------------------------------------------------------------------------- /template(s)/template (1).py: -------------------------------------------------------------------------------- 1 | import customtkinter as ctk 2 | import ctkchart 3 | import random 4 | 5 | root = ctk.CTk() 6 | root.geometry("600+300") 7 | root.title("Line Chart") 8 | chart = ctkchart.CTkLineChart(master=root, 9 | y_axis_values = (-100,100), 10 | x_axis_values = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10), 11 | pointer_state="enabled" 12 | ) 13 | chart.pack() 14 | 15 | line = ctkchart.CTkLine(master=chart, 16 | size=1) 17 | #point_highlight="enabled", 18 | #fill="enabled") 19 | 20 | 21 | 22 | data = [x for x in range(-100,100)] 23 | def loop(): 24 | chart.show_data(line=line, data=[0, -80, -40, 100, 0, 80, 50, -50, -10,80,50,100]) 25 | loop() 26 | 27 | root.mainloop() -------------------------------------------------------------------------------- /template(s)/template (3).py: -------------------------------------------------------------------------------- 1 | import customtkinter as ctk 2 | import ctkchart 3 | import random 4 | 5 | root = ctk.CTk() 6 | root.geometry("600+300") 7 | root.title("Line Chart") 8 | chart = ctkchart.CTkLineChart(master=root, 9 | y_axis_values = (-100,100), 10 | x_axis_values = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10), 11 | pointer_state="enabled" 12 | ) 13 | chart.pack() 14 | 15 | line = ctkchart.CTkLine(master=chart, 16 | size=1, 17 | point_highlight="enabled", 18 | fill="enabled") 19 | 20 | 21 | 22 | data = [x for x in range(-100,100)] 23 | def loop(): 24 | chart.show_data(line=line, data=[0, -80, -40, 100, 0, 80, 50, -50, -10,80,50,100]) 25 | 26 | 27 | loop() 28 | 29 | root.mainloop() -------------------------------------------------------------------------------- /template(s)/template (2).py: -------------------------------------------------------------------------------- 1 | import customtkinter as ctk 2 | import ctkchart 3 | import random 4 | 5 | root = ctk.CTk() 6 | root.geometry("600+300") 7 | root.title("Line Chart") 8 | chart = ctkchart.CTkLineChart(master=root, 9 | y_axis_values = (-100,100), 10 | x_axis_values = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10), 11 | pointer_state="enabled" 12 | ) 13 | chart.pack() 14 | 15 | line = ctkchart.CTkLine(master=chart, 16 | size=1, 17 | point_highlight="enabled",) 18 | #fill="enabled") 19 | 20 | 21 | 22 | data = [x for x in range(-100,100)] 23 | def loop(): 24 | chart.show_data(line=line, data=[0, -80, -40, 100, 0, 80, 50, -50, -10,80,50,100]) 25 | 26 | 27 | loop() 28 | 29 | root.mainloop() -------------------------------------------------------------------------------- /template(s)/template (6).py: -------------------------------------------------------------------------------- 1 | import customtkinter as ctk 2 | import ctkchart 3 | import random 4 | 5 | root = ctk.CTk() 6 | root.geometry("600+300") 7 | root.title("Line Chart") 8 | chart = ctkchart.CTkLineChart(master=root, 9 | y_axis_values = (-100,100), 10 | x_axis_values = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10), 11 | 12 | ) 13 | chart.pack() 14 | 15 | line = ctkchart.CTkLine(master=chart, 16 | size=3, 17 | point_highlight="enabled", 18 | style="dashed", 19 | style_type=(20,5), 20 | fill="enabled") 21 | 22 | 23 | 24 | data = [x for x in range(-100,100)] 25 | def loop(): 26 | chart.show_data(line=line, data=[0, -80, -40, 100, 0, 80, 50, -50, -10,80,50,100]) 27 | 28 | 29 | loop() 30 | 31 | root.mainloop() -------------------------------------------------------------------------------- /template(s)/template (5).py: -------------------------------------------------------------------------------- 1 | import customtkinter as ctk 2 | import ctkchart 3 | import random 4 | 5 | root = ctk.CTk() 6 | root.geometry("600+300") 7 | root.title("Line Chart") 8 | chart = ctkchart.CTkLineChart(master=root, 9 | y_axis_values = (-100,100), 10 | x_axis_values = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10), 11 | 12 | 13 | ) 14 | chart.pack() 15 | 16 | line = ctkchart.CTkLine(master=chart, 17 | size=1, 18 | style="dotted", 19 | style_type=(4,5), 20 | point_highlight="enabled",) 21 | #fill="enabled") 22 | 23 | 24 | 25 | data = [x for x in range(-100,100)] 26 | def loop(): 27 | chart.show_data(line=line, data=[0, -80, -40, 100, 0, 80, 50, -50, -10,80,50,100]) 28 | 29 | 30 | loop() 31 | 32 | root.mainloop() -------------------------------------------------------------------------------- /template(s)/template (4).py: -------------------------------------------------------------------------------- 1 | import customtkinter as ctk 2 | import ctkchart 3 | import random 4 | 5 | root = ctk.CTk() 6 | root.geometry("600+300") 7 | root.title("Line Chart") 8 | chart = ctkchart.CTkLineChart(master=root, 9 | y_axis_values = (-100,100), 10 | x_axis_values = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10), 11 | 12 | 13 | ) 14 | chart.pack() 15 | 16 | line = ctkchart.CTkLine(master=chart, 17 | size=1, 18 | style="dashed", 19 | style_type=(10,5), 20 | point_highlight="enabled",) 21 | #fill="enabled") 22 | 23 | 24 | 25 | data = [x for x in range(-100,100)] 26 | def loop(): 27 | chart.show_data(line=line, data=[0, -80, -40, 100, 0, 80, 50, -50, -10,80,50,100]) 28 | 29 | 30 | loop() 31 | 32 | root.mainloop() -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | 3 | setup( 4 | name='ctkchart', # Replace with your package name 5 | version='2.1.9', # Replace with your package version 6 | author='Thisal-D', # Replace with your name 7 | author_email='', # Replace with your email 8 | description='Line-chart Widget for customtkinter, Python library for creating live updating line charts in CustomTkinter.', 9 | long_description=open('README.md').read(), # Ensure you have a README.md file 10 | long_description_content_type='text/markdown', 11 | url='https://github.com/Thisal-D/ctkchart', 12 | packages=find_packages(), 13 | classifiers=[ 14 | 'Programming Language :: Python :: 3', 15 | 'License :: OSI Approved :: MIT License', 16 | 'Operating System :: OS Independent', 17 | ], 18 | python_requires='>=3.0', 19 | install_requires=[ 20 | 'customtkinter', # List your package dependencies here 21 | ], 22 | include_package_data=True, 23 | ) 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2024 The Python Packaging Authority 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. -------------------------------------------------------------------------------- /template(s)/template (7).py: -------------------------------------------------------------------------------- 1 | import customtkinter as ctk 2 | import ctkchart 3 | import random 4 | 5 | root = ctk.CTk() 6 | root.geometry("600+300") 7 | root.title("Line Chart") 8 | chart = ctkchart.CTkLineChart(master=root, 9 | y_axis_values = (-100,100), 10 | x_axis_values = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10), 11 | 12 | ) 13 | chart.pack() 14 | 15 | line = ctkchart.CTkLine(master=chart, 16 | size=2, 17 | point_highlight="enabled", 18 | style="dashed", 19 | style_type=(20,5), 20 | fill="disabled") 21 | 22 | line2 = ctkchart.CTkLine(master=chart, 23 | size=3,style="normal", 24 | style_type=(15,7), 25 | color=("#5dffb6","#5dffb6"), 26 | fill="enabled", 27 | fill_color = ("#5dffb6","#5dffb6") 28 | ) 29 | 30 | data = [x for x in range(-100,100)] 31 | def loop(): 32 | chart.show_data(line=line, data=[0, -80, -40, 100, 0, 80, 50, -50, -10,80,50,100]) 33 | chart.show_data(line=line2, data=[100, -10, -90, 40, -30, 40, 90,-90, -40,-100,40,0]) 34 | 35 | loop() 36 | 37 | root.mainloop() -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to ctkchart 2 | 3 | Thank you for considering contributing to ctkchart! Please follow these guidelines to contribute effectively. 4 | 5 | ## Getting Started 6 | 7 | 1. Fork the repository. 8 | 2. Clone your forked repository: `git clone https://github.com/Thisal-D/ctkchart.git` 9 | 3. Create a new branch for your changes: `git checkout -b feature-branch` 10 | 11 | ## Making Changes 12 | 13 | 1. Make your changes and ensure they follow the project's coding standards. 14 | 2. Test your changes locally. 15 | 3. Commit your changes: `git commit -m "Brief description of your changes"` 16 | 17 | ## Submitting Changes 18 | 19 | 1. Push your changes to your forked repository: `git push origin feature-branch` 20 | 2. Create a pull request on the main repository. 21 | 22 | ## Code of Conduct 23 | 24 | Please adhere to the [Code of Conduct](CODE_OF_CONDUCT.md) to maintain a respectful and inclusive community. 25 | 26 | ## Issues and Discussions 27 | 28 | 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. 29 | 30 | ## License 31 | 32 | By contributing, you agree that your contributions will be licensed under the project's [LICENSE](LICENSE). 33 | 34 | Thank you for your contribution! -------------------------------------------------------------------------------- /template(s)/Template (8).py: -------------------------------------------------------------------------------- 1 | import customtkinter as ctk 2 | import ctkchart 3 | import random 4 | 5 | #root 6 | root = ctk.CTk() 7 | root.geometry("700x400+500+300") 8 | #creating a chart 9 | chart = ctkchart.CTkLineChart(master=root, 10 | width=1700, 11 | height=800, 12 | axis_size=5, 13 | x_axis_values = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10), 14 | y_axis_values = (-1000,1000), 15 | y_axis_label_count=10, 16 | 17 | x_axis_section_color=("#aaaaaa","#555555"), 18 | y_axis_section_color=("#aaaaaa","#555555"), 19 | 20 | y_axis_font_color=("#454545", "#aaaaaa"), 21 | x_axis_font_color=("#454545", "#aaaaaa"), 22 | data_font_style=("arial", 17, "bold"), 23 | axis_font_style=("arial", 13, "bold"), 24 | x_axis_data_font_color=("#505050","#efefef"), 25 | y_axis_data_font_color=("#505050","#efefef"), 26 | 27 | y_space=20, 28 | x_space=20, 29 | ) 30 | chart.pack(pady=40) 31 | 32 | #creating a line 33 | line1 = ctkchart.CTkLine(master=chart, 34 | size=3, 35 | style="normal", 36 | 37 | fill="enabled", 38 | point_highlight="enabled", 39 | point_highlight_size=15, 40 | ) 41 | 42 | 43 | 44 | 45 | data = [x for x in range(-1000,1000)] 46 | #dipslay data (random) 47 | def loop(): 48 | chart.show_data(line=line1, data=random.choices(data, k=1)) 49 | root.after(500, loop) 50 | loop() 51 | 52 | root.mainloop() -------------------------------------------------------------------------------- /src/ctkchart/FontStyle.py: -------------------------------------------------------------------------------- 1 | class FontStyle: 2 | _colors = { 3 | "black": ("30", "40"), 4 | "gray": ("90", "100"), 5 | "red": ("31", "41"), 6 | "green": ("32", "42"), 7 | "yellow": ("33", "43"), 8 | "blue": ("34", "44"), 9 | "magenta": ("35", "45"), 10 | "cyan": ("36", "46"), 11 | "white": ("37", "47"), 12 | "bright red": ("91", "101"), 13 | "bright green": ("92", "102"), 14 | "bright yellow": ("93", "103"), 15 | "bright blue": ("94", "104"), 16 | "bright magenta": ("95", "105"), 17 | "bright cyan": ("96", "106"), 18 | "bright white": ("97", "107"), 19 | } 20 | 21 | _styles = { 22 | "normal": "0", 23 | "italic": "3", 24 | "underline": "4" 25 | } 26 | 27 | @staticmethod 28 | def _get_font_style_code(fg_color: str, bg_color: str, style: str) -> str: 29 | """ 30 | Returns the ANSI escape code for the given foreground color, 31 | background color, and style. 32 | 33 | Raises: 34 | ValueError: If any of the colors or style are invalid. 35 | """ 36 | fg_color = fg_color.lower() 37 | bg_color = bg_color.lower() 38 | style = style.lower() 39 | 40 | if fg_color not in FontStyle._colors: 41 | raise ValueError(f"Invalid foreground color: {fg_color}") 42 | if bg_color not in FontStyle._colors: 43 | raise ValueError(f"Invalid background color: {bg_color}") 44 | if style not in FontStyle._styles: 45 | raise ValueError(f"Invalid style: {style}") 46 | 47 | fg_code = FontStyle._colors[fg_color][0] 48 | bg_code = FontStyle._colors[bg_color][1] 49 | style_code = FontStyle._styles[style] 50 | 51 | return f"\x1b[{style_code};{fg_code};{bg_code}m" 52 | 53 | @staticmethod 54 | def _apply(value: str, fg_color: str, bg_color: str, style: str = "normal") -> str: 55 | """ 56 | Apply the font style to the given string. 57 | 58 | Args: 59 | value (str): The text to style. 60 | fg_color (str): Foreground color name. 61 | bg_color (str): Background color name. 62 | style (str, optional): Style name. Defaults to "normal". 63 | 64 | Returns: 65 | str: The styled text with ANSI escape codes. 66 | """ 67 | code = FontStyle._get_font_style_code(fg_color, bg_color, style) 68 | reset = "\x1b[0m" 69 | return f"{code}{value}{reset}" 70 | -------------------------------------------------------------------------------- /src/ctkchart/ThemeManager.py: -------------------------------------------------------------------------------- 1 | import customtkinter as ctk 2 | import time 3 | import threading 4 | from typing import List, Tuple, Any, Union 5 | 6 | 7 | class ThemeManager: 8 | running_state: bool = False 9 | child_objects: List[Any] = [] 10 | theme: str = "-" 11 | 12 | @staticmethod 13 | def get_color_by_theme(color: Union[Tuple[str, str], str]) -> str: 14 | """ 15 | Returns the appropriate color based on the current theme. 16 | 17 | Args: 18 | color (Tuple[str, str] | str): A tuple of (light_color, dark_color) or a single color string. 19 | 20 | Returns: 21 | str: The color corresponding to the current theme. 22 | """ 23 | if isinstance(color, tuple): 24 | return color[0] if ThemeManager.theme == "Light" else color[1] 25 | return color 26 | 27 | @staticmethod 28 | def theme_tracker() -> None: 29 | """ 30 | Monitors and applies theme changes across all registered widgets. 31 | """ 32 | while ThemeManager.child_objects: 33 | current_theme = ctk.get_appearance_mode() 34 | if current_theme != ThemeManager.theme: 35 | ThemeManager.theme = current_theme 36 | for widget in ThemeManager.child_objects: 37 | try: 38 | widget._CTkLineChart__configure_theme_mode() 39 | except Exception as e: 40 | print(f"[ThemeManager] Theme update failed for widget: {e}") 41 | time.sleep(1) 42 | 43 | ThemeManager.running_state = False 44 | 45 | @staticmethod 46 | def run() -> None: 47 | """ 48 | Starts the background theme tracking thread if not already running. 49 | """ 50 | if not ThemeManager.running_state: 51 | ThemeManager.running_state = True 52 | thread = threading.Thread(target=ThemeManager.theme_tracker, daemon=True) 53 | thread.start() 54 | 55 | @staticmethod 56 | def bind_widget(widget: Any) -> None: 57 | """ 58 | Registers a widget with the theme manager. 59 | 60 | Args: 61 | widget (Any): Widget instance with a `_CTkLineChart__configure_theme_mode` method. 62 | """ 63 | ThemeManager.child_objects.append(widget) 64 | if not ThemeManager.running_state: 65 | ThemeManager.run() 66 | 67 | @staticmethod 68 | def unbind_widget(widget: Any) -> None: 69 | """ 70 | Unregisters a widget from the theme manager. 71 | 72 | Args: 73 | widget (Any): The widget to remove. 74 | """ 75 | try: 76 | ThemeManager.child_objects.remove(widget) 77 | except ValueError: 78 | print(f"[ThemeManager] Widget not found.") 79 | except Exception as e: 80 | print(f"[ThemeManager] Error removing widget: {e}") 81 | -------------------------------------------------------------------------------- /src/ctkchart/Utils.py: -------------------------------------------------------------------------------- 1 | import tkinter 2 | from typing import Union, Tuple, Any, List 3 | 4 | 5 | class Utils: 6 | __scaling_factor = 1 # Private class variable to scale dimensions (can be adjusted if needed) 7 | 8 | @staticmethod 9 | def _required_width(text: Any, font: Tuple[str, int, str]) -> float: 10 | """ 11 | Calculate the required width for a given text and font. 12 | 13 | Args: 14 | text (Any): The text to measure. 15 | font (Tuple[str, int, str]): The font used for the label. 16 | 17 | Returns: 18 | float: The required width. 19 | """ 20 | label = tkinter.Label(font=font, text=str(text)) 21 | return label.winfo_reqwidth() / Utils.__scaling_factor 22 | 23 | @staticmethod 24 | def _required_height(text: Any, font: Tuple[str, int, str]) -> float: 25 | """ 26 | Calculate the required height for a given text and font. 27 | 28 | Args: 29 | text (Any): The text to measure. 30 | font (Tuple[str, int, str]): The font used for the label. 31 | 32 | Returns: 33 | float: The required height. 34 | """ 35 | label = tkinter.Label(font=font, text=str(text)) 36 | return label.winfo_reqheight() / Utils.__scaling_factor 37 | 38 | @staticmethod 39 | def _format_float_with_precision(value: Union[float, int], decimals: int) -> str: 40 | """ 41 | Format a float value to a fixed number of decimal places with trailing zeros. 42 | 43 | Args: 44 | value (float | int): The value to format. 45 | decimals (int): The number of decimal places. 46 | 47 | Returns: 48 | str: The formatted string. 49 | """ 50 | if decimals > 0: 51 | value = round(float(value), decimals) 52 | value_str = str(value) 53 | decimals_part = value_str.split(".")[-1] 54 | padded = value_str + "0" * (decimals - len(decimals_part)) 55 | return padded 56 | return str(int(value)) 57 | 58 | @staticmethod 59 | def _get_max_required_label_width(data: List[Any], font: Tuple[str, int, str]) -> float: 60 | """ 61 | Get the maximum required width among multiple text labels. 62 | 63 | Args: 64 | data (List[Any]): A list of text values. 65 | font (Tuple[str, int, str]): Font for the labels. 66 | 67 | Returns: 68 | float: Maximum required width. 69 | """ 70 | return max(Utils._required_width(d, font) for d in data) 71 | 72 | @staticmethod 73 | def _get_max_required_label_height(data: List[Any], font: Tuple[str, int, str]) -> float: 74 | """ 75 | Get the maximum required height among multiple text labels. 76 | 77 | Args: 78 | data (List[Any]): A list of text values. 79 | font (Tuple[str, int, str]): Font for the labels. 80 | 81 | Returns: 82 | float: Maximum required height. 83 | """ 84 | return max(Utils._required_height(d, font) for d in data) 85 | 86 | @staticmethod 87 | def _sort_tuple(values: Tuple[int, ...]) -> Tuple[int, ...]: 88 | """ 89 | Sort and deduplicate a tuple of integers. 90 | 91 | Args: 92 | values (Tuple[int, ...]): The input tuple. 93 | 94 | Returns: 95 | Tuple[int, ...]: A sorted, unique tuple. 96 | """ 97 | return tuple(sorted(set(values))) 98 | 99 | @staticmethod 100 | def _to_int(value: Union[int, str]) -> int: 101 | """ 102 | Convert a value to integer. 103 | 104 | Args: 105 | value (int | str): The value to convert. 106 | 107 | Returns: 108 | int: The integer result. 109 | """ 110 | return int(value) 111 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, religion, or sexual identity 10 | and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | * Demonstrating empathy and kindness toward other people 21 | * Being respectful of differing opinions, viewpoints, and experiences 22 | * Giving and gracefully accepting constructive feedback 23 | * Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | * Focusing on what is best not just for us as individuals, but for the 26 | overall community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | * The use of sexualized language or imagery, and sexual attention or 31 | advances of any kind 32 | * Trolling, insulting or derogatory comments, and personal or political attacks 33 | * Public or private harassment 34 | * Publishing others' private information, such as a physical or email 35 | address, without their explicit permission 36 | * Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies when 54 | an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official e-mail address, 56 | posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported to the community leaders responsible for enforcement at 63 | . 64 | All complaints will be reviewed and investigated promptly and fairly. 65 | 66 | All community leaders are obligated to respect the privacy and security of the 67 | reporter of any incident. 68 | 69 | ## Enforcement Guidelines 70 | 71 | Community leaders will follow these Community Impact Guidelines in determining 72 | the consequences for any action they deem in violation of this Code of Conduct: 73 | 74 | ### 1. Correction 75 | 76 | **Community Impact**: Use of inappropriate language or other behavior deemed 77 | unprofessional or unwelcome in the community. 78 | 79 | **Consequence**: A private, written warning from community leaders, providing 80 | clarity around the nature of the violation and an explanation of why the 81 | behavior was inappropriate. A public apology may be requested. 82 | 83 | ### 2. Warning 84 | 85 | **Community Impact**: A violation through a single incident or series 86 | of actions. 87 | 88 | **Consequence**: A warning with consequences for continued behavior. No 89 | interaction with the people involved, including unsolicited interaction with 90 | those enforcing the Code of Conduct, for a specified period of time. This 91 | includes avoiding interactions in community spaces as well as external channels 92 | like social media. Violating these terms may lead to a temporary or 93 | permanent ban. 94 | 95 | ### 3. Temporary Ban 96 | 97 | **Community Impact**: A serious violation of community standards, including 98 | sustained inappropriate behavior. 99 | 100 | **Consequence**: A temporary ban from any sort of interaction or public 101 | communication with the community for a specified period of time. No public or 102 | private interaction with the people involved, including unsolicited interaction 103 | with those enforcing the Code of Conduct, is allowed during this period. 104 | Violating these terms may lead to a permanent ban. 105 | 106 | ### 4. Permanent Ban 107 | 108 | **Community Impact**: Demonstrating a pattern of violation of community 109 | standards, including sustained inappropriate behavior, harassment of an 110 | individual, or aggression toward or disparagement of classes of individuals. 111 | 112 | **Consequence**: A permanent ban from any sort of public interaction within 113 | the community. 114 | 115 | ## Attribution 116 | 117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 118 | version 2.0, available at 119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. 120 | 121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct 122 | enforcement ladder](https://github.com/mozilla/diversity). 123 | 124 | [homepage]: https://www.contributor-covenant.org 125 | 126 | For answers to common questions about this code of conduct, see the FAQ at 127 | https://www.contributor-covenant.org/faq. Translations are available at 128 | https://www.contributor-covenant.org/translations. 129 | -------------------------------------------------------------------------------- /CHANGES_zh.md: -------------------------------------------------------------------------------- 1 | [![Language](https://img.shields.io/badge/Language-English-blue)](CHANGES_en.md) 2 | 3 | ## v2.1.7 4 | 5 | - ### 新方法添加到 `CTkLineChart` 对象 6 | | 方法名 | 描述 | 参数 | 返回类型 | 7 | |------------------------------|------------------------------------------------------------|------------------------------------------|-----------------| 8 | | `get_lines_data` | 获取指定范围内所有线条的数据点,可以选择步长值。 | start: `int`
end: `int`
step: `int` | `Dict[ctkchart.CTkLine, Tuple[int]]` | 9 | | `get_line_data` | 获取指定范围和步长值下某一条线的数据点。 | line: `ctkchart.CTkLine`
start: `int`
end: `int`
step: `int` | `Tuple[int \| float]` | 10 | | `get_x_axis_visible_point_count` | 获取X轴上可见数据点的最大数量。 | - | `int` | 11 | | `get_lines_visible_data` | 获取所有线条当前可见的数据点,基于最大数据长度和可见点数。 | - | `Dict[ctkchart.CTkLine, Tuple[int \| float]]` | 12 | | `get_line_visible_data` | 获取某一条线当前可见的数据点。 | line: `ctkchart.CTkLine` | `Tuple[int \| float]` | 13 | 14 | - ### 新方法添加到 `CTkLine` 对象 15 | | 方法名 | 描述 | 参数 | 返回类型 | 16 | |------------------------------|------------------------------------------------------------|------------------------------------------|-----------------| 17 | | `get_data` | 获取指定范围的数据点,可以选择步长值。如果没有提供参数,将返回所有可用数据。 | start: `int`
end: `int`
step: `int` | `Tuple[int \| float]` | 18 | | `get_current_visible_data` | 根据所有线条的最大数据长度和最大可见点数,返回当前可见的数据点。 | - | `Tuple[int \| float]` | 19 | | `get_x_axis_visible_point_count` | 获取X轴上可见数据点的最大数量。 | - | `int` | 20 | 21 | 22 | ## v2.1.5 23 | 24 | - ### 新增方法到 `CTkLineChart` 对象 25 | | 方法名称 | 描述 | 参数 | 返回类型 | 26 | |------------------|------------------------------------------------------------|----------------|-------------| 27 | | `clear_data` | 清除图表中所有线的数据,确保只保留最新的可见数据点。如果数据点总数超过最大可见点,则会从每条线的数据中移除旧数据。此方法确保图表仅显示基于最大可见范围的相关数据部分。 | - | `None` | 28 | 29 | - ### 新增方法到 `CTkLine` 对象 30 | | 方法名称 | 描述 | 参数 | 返回类型 | 31 | |------------------|------------------------------------------------------------|----------------|-------------| 32 | | `clear_data` | 清除特定线的数据,确保只保留最新的可见数据点。如果线的数据超过最大可见点,则会修剪旧数据。此方法允许每条线独立清除其数据,确保它始终保持在可见范围内。 | - | `None` | 33 | 34 | --- 35 | 36 | ## v2.1.4 37 | 38 | - ### 新增方法到 `CTkLineChart` 对象 39 | | 方法名称 | 描述 | 参数 | 返回类型 | 40 | |------------------|------------------------------------------------------------|----------------|-------------| 41 | | `get_line_area` | 获取特定线的区域大小 | line: `ctkchart.CTkLine` | `float` | 42 | | `get_lines_area` | 获取所有线的区域大小 | - | `float` | 43 | 44 | --- 45 | 46 | ## v2.1.3 47 | 48 | - ### 新增方法到 `CTkLineChart` 对象 49 | | 方法名称 | 描述 | 参数 | 返回类型 | 50 | |------------------|------------------------------------------------------------|----------------|-------------| 51 | | `destroy` | 销毁线图及其所有线 | - | `None` | 52 | 53 | - ### 新增方法到 `CTkLine` 对象 54 | | 方法名称 | 描述 | 参数 | 返回类型 | 55 | |------------------|------------------------------------------------------------|----------------|-------------| 56 | | `destroy` | 销毁线对象 | - | `None` | 57 | 58 | --- 59 | 60 | ## v2.1.2 61 | 62 | - ### 新增方法到 `CTkLine` 对象 63 | 64 | | 方法名称 | 描述 | 参数 | 返回类型 | 65 | |------------------|------------------------------------------------|------------------------------------------|-------------| 66 | | `cget` | 获取指定参数的值 | attribute_name: `str \| "__all__"` | `any` | 67 | | `set_visible` | 更改线的可见性 | state: `bool` | `None` | 68 | | `get_visibility` | 获取线的可见性 | - | `bool` | 69 | 70 | - ### 新增方法到 `CTkLineChart` 对象 71 | 72 | | 方法名称 | 描述 | 参数 | 返回类型 | 73 | |------------------------|------------------------------------------------|--------------------------------------------------|-------------| 74 | | `set_lines_visibility` | 更改所有线的可见性 | state: `bool` | `None` | 75 | | `set_line_visibility` | 更改特定线的可见性 | line: `ctkchart.CTkLine`
state: `bool` | `None` | 76 | | `get_line_visibility` | 获取特定线的可见性 | line: `ctkchart.CTkLine` | `bool` | 77 | | `cget` | 获取指定参数的值 | attribute_name: `str \| "__all__"` | `any` | 78 | | `place_info` | 获取位置相关信息 | attribute_name: `str \| "__all__"` | `any` | 79 | | `pack_info` | 获取打包相关信息 | attribute_name: `str \| "__all__"` | `any` | 80 | | `grid_info` | 获取网格相关信息 | attribute_name: `str \| "__all__"` | `any` | 81 | 82 | - ### 移除 `CTkLineChart` 对象的方法 83 | 84 | | 方法名称 | 描述 | 参数 | 返回类型 | 85 | |-------------|----------------------|----------------------------------------------|-------------| 86 | | hide_all | 隐藏所有的线 | state: `bool` | None | 87 | | hide | 隐藏特定的线 | line: `ctkchart.CTkLine`
state: `bool` | None | 88 | -------------------------------------------------------------------------------- /CHANGES_en.md: -------------------------------------------------------------------------------- 1 | [![Chinese](https://img.shields.io/badge/Language-中文-red)](CHANGES_zh.md) 2 | 3 | 4 | ## v2.1.7 5 | 6 | - ### New Methods Added to `CTkLineChart` Object 7 | | Method Name | Description | Parameters | Return Type | 8 | |------------------------------|------------------------------------------------------------|------------------------------------------|-----------------| 9 | | `get_lines_data` | Retrieves data points for all lines within a specified range with an optional step value. | start: `int`
end: `int`
step: `int` | `Dict[ctkchart.CTkLine, Tuple[int]]` | 10 | `get_line_data` | Retrieves data points for a specific line within a specified range and step. | line: `ctkchart.CTkLine`
start: `int`
end: `int`
step: `int` | `Tuple[int \| float]` | 11 | | `get_x_axis_visible_point_count` | Retrieves the maximum number of data points that can be visible along the X-axis. | - | `int` | 12 | | `get_lines_visible_data` | Retrieves currently visible data points for all lines based on the maximum data length and visible points. | - | `Dict[ctkchart.CTkLine, Tuple[int \| float]]` | 13 | | `get_line_visible_data` | Retrieves currently visible data points for a specific line. | line: `ctkchart.CTkLine` | `Tuple[int \| float]` | 14 | 15 | 16 | 17 | - ### New Methods Added to `CTkLine` Object 18 | | Method Name | Description | Parameters | Return Type | 19 | |------------------------------|------------------------------------------------------------|---------------------|-----------------| 20 | | `get_data` | Retrieves data points from a specified range with an optional step value. If no parameters are given, it returns all available data. | start: `int`
end: `int`
step: `int` | `Tuple[int \| float]` | 21 | | `get_current_visible_data` | Returns the currently visible data points based on the maximum data length across all lines and the maximum number of visible points. | - | `Tuple[int \| float]` | 22 | | `get_x_axis_visible_point_count` | Retrieves the maximum number of data points that can be visible along the X-axis. | - | `int` | 23 | 24 | 25 | ## v2.1.5 26 | 27 | - ### New Method Added to `CTkLineChart` Object 28 | | Method Name | Description | Parameters | Return Type | 29 | |------------------|------------------------------------------------------------|----------------|-------------| 30 | | `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` | 31 | 32 | - ### New Method Added to `CTkLine` Object 33 | | Method Name | Description | Parameters | Return Type | 34 | |------------------|------------------------------------------------------------|----------------|-------------| 35 | | `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` | 36 | 37 | --- 38 | 39 | ## v2.1.4 40 | 41 | - ### New Method Added to `CTkLineChart` Object 42 | | Method Name | Description | Parameters | Return Type | 43 | |------------------|------------------------------------------------------------|----------------|-------------| 44 | | `get_line_area` | Get the are of specific line | line: `ctkchart.CTkLine` | `float` | 45 | | `get_lines_area` | Get the are of all lines | - | `float` | 46 | 47 | --- 48 | 49 | ## v2.1.3 50 | 51 | - ### New Method Added to `CTkLineChart` Object 52 | | Method Name | Description | Parameters | Return Type | 53 | |------------------|------------------------------------------------------------|----------------|-------------| 54 | | `destroy` | Destroy the line chart, along with its lines | - | `None` | 55 | 56 | - ### New Method Added to `CTkLine` Object 57 | | Method Name | Description | Parameters | Return Type | 58 | |------------------|------------------------------------------------------------|----------------|-------------| 59 | | `destroy` | Destroy the line object | - | `None` | 60 | 61 | --- 62 | 63 | ## v2.1.2 64 | 65 | - ### New Method Added to `CTkLine` Object 66 | 67 | | Method Name | Description | Parameters | Return Type | 68 | |------------------|------------------------------------------------|------------------------------------------|-------------| 69 | | `cget` | Get the value of the specified parameter | attribute_name: `str \| "__all__"` | `any` | 70 | | `set_visible` | Change the visibility of the line | state: `bool` | `None` | 71 | | `get_visibility` | Get the visibility of the line | - | `bool` | 72 | 73 | - ### New Methods Added to CTkLineChart Object 74 | 75 | | Method Name | Description | Parameters | Return Type | 76 | |------------------------|------------------------------------------------|--------------------------------------------------|-------------| 77 | | `set_lines_visibility` | Change the visibility of all the lines | state: `bool` | `None` | 78 | | `set_line_visibility` | Change the visibility of a specific line | line: `ctkchart.CTkLine`
state: `bool` | `None` | 79 | | `get_line_visibility` | Get the visibility of a specific line | line: `ctkchart.CTkLine` | `bool` | 80 | | `cget` | Get the value of the specified parameter | attribute_name: `str \| "__all__"` | `any` | 81 | | `place_info` | Get info about place | attribute_name: `str \| "__all__"` | `any` | 82 | | `pack_info` | Get info about pack | attribute_name: `str \| "__all__"` | `any` | 83 | | `grid_info` | Get info about grid | attribute_name: `str \| "__all__"` | `any` | 84 | 85 | - ### Removed Methods in CTkLineChart Object 86 | 87 | | Method Name | Description | Parameters | Return Type | 88 | |-------------|----------------------|----------------------------------------------|-------------| 89 | | hide_all | Hide all the lines | state: `bool` | None | 90 | | hide | hide a specific line | line: `ctkchart.CTkLine`
state: `bool` | None | -------------------------------------------------------------------------------- /src/ctkchart/Validate.py: -------------------------------------------------------------------------------- 1 | from typing import Tuple, Any 2 | from .FontStyle import FontStyle 3 | import tkinter 4 | 5 | 6 | class Validate: 7 | @staticmethod 8 | def _error_font(value: str) -> str: 9 | """Return a formatted error message.""" 10 | return FontStyle._apply(value, "red", "black", "underline") 11 | 12 | @staticmethod 13 | def _var_font(value: str) -> str: 14 | """Return a formatted variable name.""" 15 | return FontStyle._apply(value, "green", "black", "italic") 16 | 17 | @staticmethod 18 | def _is_tuple(value: Any, var: str) -> None: 19 | """Check if value is a tuple.""" 20 | if type(value) is not tuple: 21 | raise TypeError(f"{Validate._var_font(var)} {Validate._error_font('must be tuple.')}") 22 | 23 | @staticmethod 24 | def _is_list(value: Any, var: str) -> None: 25 | """Check if value is a list.""" 26 | if type(value) is not list: 27 | raise TypeError(f"{Validate._var_font(var)} {Validate._error_font('must be list.')}") 28 | 29 | @staticmethod 30 | def _is_int(value: Any, var: str) -> None: 31 | """Check if value is an integer.""" 32 | if type(value) is not int: 33 | raise TypeError(f"{Validate._var_font(var)} {Validate._error_font('must be int.')}") 34 | 35 | @staticmethod 36 | def _is_bool(value: Any, var: str) -> None: 37 | """Check if value is a boolean.""" 38 | if type(value) is not bool: 39 | raise TypeError(f"{Validate._var_font(var)} {Validate._error_font('must be bool.')}") 40 | 41 | @staticmethod 42 | def _is_str(value: Any, var: str) -> None: 43 | """Check if value is a string.""" 44 | if type(value) is not str: 45 | raise TypeError(f"{Validate._var_font(var)} {Validate._error_font('must be str.')}") 46 | 47 | @staticmethod 48 | def _is_valid_color(value: Any, var: str) -> None: 49 | """Check if value is a valid color string or tuple.""" 50 | valid = True 51 | if type(value) is tuple and len(value) == 2: 52 | try: 53 | tkinter.Label(bg=value[0]) 54 | tkinter.Label(bg=value[1]) 55 | except: 56 | valid = False 57 | elif type(value) is str: 58 | try: 59 | tkinter.Label(bg=value) 60 | except: 61 | valid = False 62 | else: 63 | valid = False 64 | if not valid: 65 | raise ValueError(f'''{Validate._var_font(var)} {Validate._error_font("must be valid color. eg:- '#ff0000'/ 'red'/ ('#ffffff', '#000000')")}''') 66 | 67 | @staticmethod 68 | def _is_valid_font(value: Any, var: str) -> None: 69 | """Check if value is a valid font tuple.""" 70 | Validate._is_tuple(value, var) 71 | try: 72 | tkinter.Label(font=value) 73 | except: 74 | raise ValueError(f'''{Validate._var_font(var)} {Validate._error_font("must be valid font. eg:- ('arial',10,'bold')")}''') 75 | 76 | @staticmethod 77 | def _is_valid_function(value: Any, var: str) -> None: 78 | """Check if value is a callable function or None.""" 79 | if not callable(value) and value is not None: 80 | raise TypeError(f'''{Validate._var_font(var)} {Validate._error_font("must be function with two parameters or *args.")}''') 81 | 82 | @staticmethod 83 | def _is_valid_x_axis_indices(values: Tuple[Any, ...], indices: Tuple[int, ...], var: str) -> None: 84 | """Validate x-axis indices within bounds.""" 85 | if indices is not None: 86 | Validate._is_tuple(indices, var) 87 | Validate._is_valid_indices(indices, var) 88 | for index in indices: 89 | if index >= len(values): 90 | raise IndexError(f'''{Validate._var_font(var)} {Validate._error_font("values must be lower than length of x_axis_values.")}''') 91 | 92 | @staticmethod 93 | def _is_valid_x_axis_label_count(values: Any, var: str) -> None: 94 | """Check x-axis label count is an int.""" 95 | if values is not None: 96 | Validate._is_int(values, var) 97 | 98 | @staticmethod 99 | def _is_valid_style_type(value: Any, var: str) -> None: 100 | """Check style type as a tuple of two integers.""" 101 | Validate._is_tuple(value, var) 102 | if len(value) == 2 and isinstance(value[0], int) and isinstance(value[1], int): 103 | return 104 | elif len(value) != 2: 105 | raise ValueError(f'''{Validate._var_font(var)} {Validate._error_font("length must be two.")}''') 106 | else: 107 | raise TypeError(f'''{Validate._var_font(var)} {Validate._error_font("values must be integers.")}''') 108 | 109 | @staticmethod 110 | def _is_valid_data_position(value: Any, var: str) -> None: 111 | """Check if data position is 'top' or 'side'.""" 112 | Validate._is_str(value, var) 113 | if value not in ("top", "side"): 114 | raise ValueError(f'''{Validate._var_font(var)} {Validate._error_font("must be 'top' or 'side'.")}''') 115 | 116 | @staticmethod 117 | def _is_valid_line_style(value: Any, var: str) -> None: 118 | """Check line style is 'normal', 'dotted' or 'dashed'.""" 119 | Validate._is_str(value, var) 120 | if value not in ("normal", "dotted", "dashed"): 121 | raise ValueError(f'''{Validate._var_font(var)} {Validate._error_font("must be 'normal' or 'dotted' or 'dashed'.")}''') 122 | 123 | @staticmethod 124 | def _is_valid_section_style(value: Any, var: str) -> None: 125 | """Check section style is 'normal' or 'dashed'.""" 126 | Validate._is_str(value, var) 127 | if value not in ("normal", "dashed"): 128 | raise ValueError(f'''{Validate._var_font(var)} {Validate._error_font("must be 'normal' or 'dashed'.")}''') 129 | 130 | @staticmethod 131 | def _is_valid_x_axis_point_spacing(value: Any, var: str) -> None: 132 | """Check point spacing is integer or 'auto'.""" 133 | if isinstance(value, int) or (isinstance(value, str) and value == "auto"): 134 | return 135 | raise TypeError(f'''{Validate._var_font(var)} {Validate._error_font("must be integer or 'auto'.")}''') 136 | 137 | @staticmethod 138 | def _is_valid_pointer_state_lock(value: Any, var: str) -> None: 139 | """Check if pointer lock state is valid.""" 140 | Validate._is_str(value, var) 141 | if value not in ("enabled", "disabled"): 142 | raise ValueError(f'''{Validate._var_font(var)} {Validate._error_font("must be 'disabled' or 'enabled'.")}''') 143 | 144 | @staticmethod 145 | def _is_valid_line_highlight(value: Any, var: str) -> None: 146 | """Check if line highlight is enabled or disabled.""" 147 | Validate._is_str(value, var) 148 | if value not in ("enabled", "disabled"): 149 | raise ValueError(f'''{Validate._var_font(var)} {Validate._error_font("must be 'disabled' or 'enabled'.")}''') 150 | 151 | @staticmethod 152 | def _is_valid_line_fill(value: Any, var: str) -> None: 153 | """Check if line fill is enabled or disabled.""" 154 | Validate._is_str(value, var) 155 | if value not in ("enabled", "disabled"): 156 | raise ValueError(f'''{Validate._var_font(var)} {Validate._error_font("must be 'disabled' or 'enabled'.")}''') 157 | 158 | @staticmethod 159 | def _is_valid_y_axis_values(value: Any, var: str) -> None: 160 | """Validate y-axis value tuple with two ascending numbers.""" 161 | Validate._is_tuple(value, var) 162 | if value == (None, None): 163 | raise ValueError(f'''{Validate._var_font(var)} {Validate._error_font("must be provide.")}''') 164 | if len(value) != 2: 165 | raise ValueError(f'''{Validate._var_font(var)} {Validate._error_font("length must be two.")}''') 166 | if not all(isinstance(v, (int, float)) for v in value): 167 | raise TypeError(f'''{Validate._var_font(var)} {Validate._error_font("values must be integer or float.")}''') 168 | if value[0] >= value[1]: 169 | raise ValueError(f'''{Validate._var_font(var)} {Validate._error_font("first value must be less than second value.")}''') 170 | 171 | @staticmethod 172 | def _is_valid_x_axis_values(value: Any, var: str) -> None: 173 | """Check x-axis values are valid and not placeholders.""" 174 | if value == (None, "None", None, "None"): 175 | raise ValueError(f'''{Validate._var_font(var)} {Validate._error_font("must be provide.")}''') 176 | Validate._is_tuple(value, var) 177 | 178 | @staticmethod 179 | def _is_valid_ctk_line(value: Any, var: str) -> None: 180 | """Check if value is instance of CTkLine.""" 181 | from .CTkLine import CTkLine 182 | if type(value) is not CTkLine: 183 | raise TypeError(f'''{Validate._var_font(var)} {Validate._error_font("type must be ctkchart.CTkLine")}''') 184 | 185 | @staticmethod 186 | def _is_valid_ctk_line_chart(value: Any, var: str) -> None: 187 | """Check if value is instance of CTkLineChart.""" 188 | from .CTkLineChart import CTkLineChart 189 | if type(value) is not CTkLineChart: 190 | raise TypeError(f'''{Validate._var_font(var)} {Validate._error_font("type must be ctkchart.CTkLineChart")}''') 191 | 192 | @staticmethod 193 | def _is_valid_data(value: Any, var: str) -> None: 194 | """Ensure list contains only numeric values.""" 195 | Validate._is_list(value, var) 196 | if not all(isinstance(v, (int, float)) for v in value): 197 | raise TypeError(f'''{Validate._var_font(var)} {Validate._error_font("all values in the list should be either int or float.")}''') 198 | 199 | @staticmethod 200 | def _is_valid_indices(value: Any, var: str) -> None: 201 | """Ensure all indices are integers.""" 202 | if not all(isinstance(v, int) for v in value): 203 | raise TypeError(f'''{Validate._var_font(var)} {Validate._error_font("all values should be int.")}''') 204 | 205 | @staticmethod 206 | def _invalid_cget(var: str) -> None: 207 | """Raise error for invalid attribute access.""" 208 | raise TypeError(f'''{Validate._var_font(str(var))} {Validate._error_font("Invalid attribute.")}''') 209 | 210 | @staticmethod 211 | def _invalid_ctk_line(line) -> None: 212 | """Raise error when line not part of chart.""" 213 | raise ValueError(f'''{Validate._var_font(str(line))} {Validate._error_font("The line is not part of this line chart.")}''') 214 | 215 | @staticmethod 216 | def _invalid_master(value): 217 | """Raise error for invalid chart master.""" 218 | raise ValueError(f'''{Validate._var_font(str(value))} {Validate._error_font("Invalid Master for chart.")}''') 219 | 220 | @staticmethod 221 | def _master_att_not_provide_for_line(value): 222 | """Raise error when master not provided for line.""" 223 | raise ValueError(f'''{Validate._var_font(str(value))} {Validate._error_font("master must be provide for CTkLine")}''') 224 | -------------------------------------------------------------------------------- /README_zh.md: -------------------------------------------------------------------------------- 1 | [![Language](https://img.shields.io/badge/Language-English-blue)](README.md) 2 | 3 |
4 | 5 | [![ctkchart](https://snyk.io/advisor/python/ctkchart/badge.svg)](https://snyk.io/advisor/python/ctkchart) 6 | 7 | # ctkchart 8 | 9 | [![PyPI version](https://badge.fury.io/py/ctkchart.svg)](https://pypi.org/project/ctkchart/) 10 | 11 | [![Downloads](https://static.pepy.tech/badge/ctkchart)](https://pepy.tech/project/ctkchart) ![Downloads last 6 month](https://static.pepy.tech/personalized-badge/ctkchart?period=total&units=international_system&left_color=grey&right_color=BLUE&left_text=downloads%20last%206%20month) [![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) 12 | 13 | 14 | ![PyPI - License](https://img.shields.io/badge/license-MIT-blue) 15 | ![LOC](https://tokei.rs/b1/github/Thisal-D/ctkchart?category=lines) 16 | 17 |
18 | 19 | **
  • ctkchart 是一个用于在 customtkinter 中创建实时更新折线图的 Python 库。
  • ** 20 | 21 | --- 22 | 23 | ### 特性 24 | 25 | - **实时更新**: 显示带有实时数据的折线图。 26 | - **多条线**: 支持在同一图表上绘制多条线,便于比较。 27 | - **颜色定制**: 自定义颜色以匹配您的应用程序设计或数据表示。 28 | - **动态颜色变化**: 实现暗模式和亮模式下的动态颜色变化。 29 | - **字体定制**: 调整文本元素的字体以增强可读性。 30 | - **尺寸定制**: 根据不同显示尺寸和布局自定义图表尺寸。 31 | 32 | [**查看最新更新 | 更改**](CHANGES_zh.md) 33 | 34 | --- 35 | 36 | ### 导入与安装 37 | * **安装** 38 | ``` 39 | pip install ctkchart 40 | ``` 41 | 42 | * **导入** 43 | ``` python 44 | import ctkchart 45 | ``` 46 | 47 | --- 48 | 49 | ### 简单示例 50 | - **导入库** 51 | ``` python 52 | import tkchart 53 | ``` 54 | 55 | - **创建折线图并放置图表** 56 | ``` python 57 | chart = ctkchart.CTkLineChart( 58 | master=root, 59 | x_axis_values=("a", "b", "c", "d", "e", "f"), 60 | y_axis_values=(100, 900) 61 | ) 62 | chart.place(x=10, y=10) 63 | ``` 64 | 65 | - **创建折线** 66 | ``` python 67 | line = ctkchart.CTkLine(master=chart) 68 | ``` 69 | 70 | - **显示数据** 71 | 使用循环显示数据 72 | ``` python 73 | def loop(): 74 | while True: 75 | random_data = random.choice(range(100, 900)) 76 | chart.show_data(line=line, data=[random_data]) 77 | time.sleep(1) 78 | 79 | #调用线程 80 | theading.Thread(target=loop).start() 81 | ``` 82 | 83 | --- 84 | 85 | ### 链接 86 | 87 | - **文档 :** [文档](documentation) 88 | - [英文文档](documentation/DOCUMENTATION_en.md) 89 | - [中文文档](documentation/DOCUMENTATION_zh.md) 90 | - **Python 官方 :** [ctkchart](https://pypi.org/project/ctkchart/) 91 | 92 | --- 93 | 94 | ### 您可以完成的任务 95 | 96 | - **简单示例** 97 | 98 | https://github.com/Thisal-D/ctkchart/assets/93121062/6f1e844f-d51c-467a-a3dc-ee03fea78fc9 99 | 100 | ``` python 101 | import customtkinter as ctk # 导入 customtkinter 库作为 ctk 102 | import ctkchart # 导入 ctkchart 模块用于创建图表 103 | import random # 导入 random 模块用于生成随机数据 104 | import threading # 导入 threading 模块用于并发执行任务 105 | import time # 导入 time 模块用于添加延时 106 | 107 | # 创建根窗口并配置 108 | root = ctk.CTk() 109 | root.configure(fg_color="#0d1117") 110 | root.geometry("720x430+200+200") 111 | 112 | # 创建折线图控件 113 | line_chart = ctkchart.CTkLineChart( 114 | master=root, # 设置根窗口为父容器 115 | x_axis_values=("01-01", "01-02", "01-03", "01-04", "01-05", "01-06", "01-07", "01-08", "01-09", "01-10"), # X轴值 116 | y_axis_values=(0, 1000) # Y轴值(范围) 117 | ) 118 | 119 | line_chart.pack(pady=15) # 将折线图控件放入根窗口 120 | 121 | # 创建折线 122 | line = ctkchart.CTkLine(master=line_chart) # 设置折线图为父容器 123 | 124 | def display_data(): 125 | """函数用于持续在折线图上显示随机数据。""" 126 | while True: 127 | random_data = [random.choice(range(0, 1000))] # 生成 0 到 1000 之间的随机数据 128 | line_chart.show_data(line=line, data=random_data) # 在折线图上显示随机数据 129 | time.sleep(0.5) # 在下一次迭代之前暂停 0.5 秒 130 | 131 | # 在新线程中调用 display_data 函数 132 | threading.Thread(target=display_data).start() 133 | 134 | # 启动主事件循环 135 | root.mainloop() 136 | ``` 137 | --- 138 | 139 | - **简单风格** 140 | 141 | https://github.com/Thisal-D/ctkchart/assets/93121062/afe56452-68c3-44f0-9c67-2ab6f6910f6e 142 | 143 | ``` python 144 | import customtkinter as ctk # 导入 customtkinter 库作为 ctk 145 | import ctkchart # 导入 ctkchart 模块用于创建图表 146 | import random # 导入 random 模块用于生成随机数据 147 | import threading # 导入 threading 模块用于并发执行任务 148 | import time # 导入 time 模块用于添加延时 149 | 150 | # 创建根窗口并配置 151 | root = ctk.CTk() 152 | root.configure(fg_color="#0d1117") 153 | root.geometry("720x430+200+200") 154 | 155 | # 创建折线图控件 156 | line_chart = ctkchart.CTkLineChart( 157 | master=root, # 设置根窗口为父容器 158 | x_axis_values=("01-01", "01-02", "01-03", "01-04", "01-05", "01-06", "01-07", "01-08", "01-09", "01-10"), # X轴值 159 | y_axis_values=(0, 1000), # Y轴值(范围) 160 | y_axis_label_count=10, # 设置Y轴标签数量为10 161 | ) 162 | 163 | line_chart.pack(pady=15) # 将折线图控件放入根窗口 164 | 165 | # 创建折线 166 | line = ctkchart.CTkLine( 167 | master=line_chart, # 设置折线图为父容器 168 | size=2, # 设置折线宽度为 2 169 | fill="enabled" # 启用填充效果 170 | ) 171 | 172 | def display_data(): 173 | """函数用于持续在折线图上显示随机数据。""" 174 | while True: 175 | random_data = [random.choice(range(0, 1000))] # 生成 0 到 1000 之间的随机数据 176 | line_chart.show_data(line=line, data=random_data) # 在折线图上显示随机数据 177 | time.sleep(0.5) # 在下一次迭代之前暂停 0.5 秒 178 | 179 | # 在新线程中调用 display_data 函数 180 | threading.Thread(target=display_data).start() 181 | 182 | # 启动主事件循环 183 | root.mainloop() 184 | ``` 185 | --- 186 | 187 | - **两条线,不同的线型** 188 | 189 | https://github.com/Thisal-D/ctkchart/assets/93121062/9bc35a39-a8ca-4942-9fc7-a1c89d1bd1bc 190 | 191 | ```python 192 | import customtkinter as ctk # 导入 customtkinter 库作为 ctk 193 | import ctkchart # 导入 ctkchart 模块用于创建图表 194 | import random # 导入 random 模块用于生成随机数据 195 | import threading # 导入 threading 模块用于并发运行任务 196 | import time # 导入 time 模块用于添加延迟 197 | 198 | # 创建根窗口并配置 199 | root = ctk.CTk() 200 | root.configure(fg_color=("#ffffff", "#0d1117")) 201 | root.geometry("720x430+200+200") 202 | 203 | # 创建线性图表小部件 204 | line_chart = ctkchart.CTkLineChart( 205 | master=root, # 设置根窗口为主窗口 206 | x_axis_values=("01-01", "01-02", "01-03", "01-04", "01-05", "01-06", "01-07", "01-08", "01-09", "01-10"), # X轴的值 207 | y_axis_values=(0, 1000), # Y轴的值(范围) 208 | y_axis_label_count=10, # 设置Y轴标签数量为10 209 | ) 210 | 211 | line_chart.pack(pady=15) # 将线图部件打包到根窗口中 212 | 213 | line1 = ctkchart.CTkLine( 214 | master=line_chart, # 设置线图的主窗口 215 | color=("#5dffb6", "#5dffb6"), # 轻主题为#5dffb6,暗主题为#5dffb6 216 | size=2, # 设置线的大小为2 217 | style="dashed", # 将线的样式更改为虚线 218 | style_type=(10, 5), # 设置虚线的宽度和虚线之间的间隔 219 | ) 220 | 221 | line2 = ctkchart.CTkLine( 222 | master=line_chart, # 设置线图的主窗口 223 | color=("#FFBAD2", "#FFBAD2"), # 轻主题为#FFBAD2,暗主题为#FFBAD2 224 | size=2, # 设置线的大小为2 225 | point_highlight="enabled", # 启用点高亮 226 | point_highlight_color=("#FFBAD2", "#FFBAD2"), # 设置高亮颜色 227 | ) 228 | 229 | def display_data(): 230 | """函数:持续在图表上显示随机数据。""" 231 | while True: 232 | random_data = [random.choice(range(0, 1000))] # 生成 0 到 1000 之间的随机数据 233 | line_chart.show_data(line=line1, data=random_data) # 显示数据在 line1 上 234 | random_data = [random.choice(range(0, 1000))] # 生成新的随机数据 235 | line_chart.show_data(line=line2, data=random_data) # 显示数据在 line2 上 236 | time.sleep(0.5) # 暂停 0.5 秒钟再进行下一次迭代 237 | 238 | # 以独立线程运行 display_data 函数 239 | threading.Thread(target=display_data).start() 240 | 241 | # 启动主事件循环 242 | root.mainloop() 243 | ``` 244 | 245 | --- 246 | 247 | - **三条线,不同的线型** 248 | 249 | https://github.com/Thisal-D/ctkchart/assets/93121062/6d568b70-2ceb-42d0-b93c-0096f2745134 250 | 251 | ```python 252 | import customtkinter as ctk # 导入 customtkinter 库作为 ctk 253 | import ctkchart # 导入 ctkchart 模块用于创建图表 254 | import random # 导入 random 模块用于生成随机数据 255 | import threading # 导入 threading 模块用于并发运行任务 256 | import time # 导入 time 模块用于添加延迟 257 | 258 | # 创建根窗口并配置 259 | root = ctk.CTk() 260 | root.configure(fg_color=("#ffffff", "#0d1117")) 261 | root.geometry("720x430+200+200") 262 | 263 | # 创建线性图表小部件 264 | line_chart = ctkchart.CTkLineChart( 265 | master=root, # 设置根窗口为主窗口 266 | x_axis_values=("01-01", "01-02", "01-03", "01-04", "01-05", "01-06", "01-07", "01-08", "01-09", "01-10"), # X轴的值 267 | y_axis_values=(0, 1000), # Y轴的值(范围) 268 | y_axis_label_count=10, # 设置Y轴标签数量为10 269 | ) 270 | 271 | line_chart.pack(pady=15) # 将线图部件打包到根窗口中 272 | 273 | # 创建线1 274 | line1 = ctkchart.CTkLine( 275 | master=line_chart, # 设置线图的主窗口 276 | size=2, # 设置线的大小为2 277 | fill="enabled" # 启用线填充 278 | ) 279 | 280 | line2 = ctkchart.CTkLine( 281 | master=line_chart, # 设置线图的主窗口 282 | color=("#5dffb6", "#5dffb6"), # 轻主题为#5dffb6,暗主题为#5dffb6 283 | size=2, # 设置线的大小为2 284 | style="dashed", # 将线的样式更改为虚线 285 | style_type=(10, 5), # 设置虚线的宽度和虚线之间的间隔 286 | ) 287 | 288 | line3 = ctkchart.CTkLine( 289 | master=line_chart, # 设置线图的主窗口 290 | color=("#FFBAD2", "#FFBAD2"), # 轻主题为#FFBAD2,暗主题为#FFBAD2 291 | size=2, # 设置线的大小为2 292 | point_highlight="enabled", # 启用点高亮 293 | point_highlight_color=("#FFBAD2", "#FFBAD2"), # 设置高亮颜色 294 | ) 295 | 296 | def display_data(): 297 | """函数:持续在图表上显示随机数据。""" 298 | while True: 299 | random_data = [random.choice(range(0, 1000))] # 生成 0 到 1000 之间的随机数据 300 | line_chart.show_data(line=line1, data=random_data) # 显示数据在 line1 上 301 | random_data = [random.choice(range(0, 1000))] # 生成新的随机数据 302 | line_chart.show_data(line=line2, data=random_data) # 显示数据在 line2 上 303 | random_data = [random.choice(range(0, 1000))] # 生成新的随机数据 304 | line_chart.show_data(line=line3, data=random_data) # 显示数据在 line3 上 305 | time.sleep(0.5) # 暂停 0.5 秒钟再进行下一次迭代 306 | 307 | # 以独立线程运行 display_data 函数 308 | threading.Thread(target=display_data).start() 309 | 310 | # 启动主事件循环 311 | root.mainloop() 312 | ``` 313 | 314 | --- 315 | 316 | - **进阶**(实际上只是添加了两个属性) 317 | 318 | https://github.com/Thisal-D/ctkchart/assets/93121062/c2838fd6-3a0f-45be-bb39-9953d007067d 319 | 320 | ```python 321 | import customtkinter as ctk # 导入 customtkinter 库作为 ctk 322 | import ctkchart # 导入 ctkchart 模块用于创建图表 323 | import random # 导入 random 模块用于生成随机数据 324 | import threading # 导入 threading 模块用于并发运行任务 325 | import time # 导入 time 模块用于添加延迟 326 | 327 | # 创建根窗口并配置 328 | root = ctk.CTk() 329 | root.configure(fg_color=("#ffffff", "#0d1117")) 330 | root.geometry("720x430+200+200") 331 | 332 | # 创建线性图表小部件 333 | line_chart = ctkchart.CTkLineChart( 334 | master=root, # 设置根窗口为主窗口 335 | x_axis_values=("01-01", "01-02", "01-03", "01-04", "01-05", "01-06", "01-07", "01-08", "01-09", "01-10"), # X轴的值 336 | y_axis_values=(0, 1000), # Y轴的值(范围) 337 | y_axis_label_count=10, # 设置Y轴标签数量为1 338 | y_axis_section_count=10, 339 | x_axis_section_count=10, 340 | ) 341 | 342 | line_chart.pack(pady=15) # 将线图部件打包到根窗口中 343 | 344 | line1 = ctkchart.CTkLine( 345 | master=line_chart, # 设置线图的主窗口 346 | color=("#5dffb6", "#5dffb6"), # 轻主题为#5dffb6,暗主题为#5dffb6 347 | size=2, # 设置线的大小为2 348 | style="dashed", # 将线的样式更改为虚线 349 | style_type=(10, 5), # 设置虚线的宽度和虚线之间的间隔 350 | ) 351 | 352 | line2 = ctkchart.CTkLine( 353 | master=line_chart, # 设置线图的主窗口 354 | color=("#FFBAD2", "#FFBAD2"), # 轻主题为#FFBAD2,暗主题为#FFBAD2 355 | size=2, # 设置线的大小为2 356 | point_highlight="enabled", # 启用点高亮 357 | point_highlight_color=("#FFBAD2", "#FFBAD2"), # 设置高亮颜色 358 | ) 359 | 360 | def display_data(): 361 | """函数:持续在图表上显示随机数据。""" 362 | while True: 363 | random_data = [random.choice(range(0, 1000))] # 生成 0 到 1000 之间的随机数据 364 | line_chart.show_data(line=line1, data=random_data) # 显示数据在 line1 上 365 | random_data = [random.choice(range(0, 1000))] # 生成新的随机数据 366 | line_chart.show_data(line=line2, data=random_data) # 显示数据在 line2 上 367 | time.sleep(0.5) # 暂停 0.5 秒钟再进行下一次迭代 368 | 369 | # 以独立线程运行 display_data 函数 370 | threading.Thread(target=display_data).start() 371 | 372 | # 启动主事件循环 373 | root.mainloop() 374 | ``` 375 | 376 | --- 377 | 378 | - #### 轻主题和暗主题 379 | 380 | **对于 ctkchart 中涉及颜色的每个参数,您可以提供以下任意一种**: 381 | - 一个字符串表示颜色。 382 | - 一个包含两个字符串的元组,第一个字符串表示轻主题颜色,第二个字符串表示暗主题颜色。 383 | 384 | https://github.com/user-attachments/assets/9fed4b83-5b03-4ea0-82a0-36029dfc93dd 385 | 386 | --- 387 | 388 | **探索可自定义的功能,如颜色、字体等,详细内容请参考文档。** 389 | 390 | #### 请参考完整文档 391 | - [**英文文档**](documentation/DOCUMENTATION_en.md) 392 | - [**中文文档**](documentation/DOCUMENTATION_zh.md) 393 | 394 | --- 395 | 396 | #### 贡献者 397 | - [](https://github.com/childeyouyu) [youyu](https://github.com/childeyouyu) 398 | -------------------------------------------------------------------------------- /src/ctkchart/CTkLine.py: -------------------------------------------------------------------------------- 1 | from typing import Union, Tuple, Literal 2 | from .Validate import Validate 3 | 4 | 5 | class CTkLine: 6 | current_usable_id = 1 7 | def __init__( 8 | self, 9 | master: any = None, 10 | color: Union[Tuple[str, str], str] = ("#768df1", "#768df1"), 11 | size: int = 1, 12 | style: Literal["normal", "dashed", "dotted"] = "normal", 13 | style_type: Tuple[int, int] = (4, 4), 14 | point_highlight: Literal["enabled", "disabled"] = "disabled", 15 | point_highlight_size: int = 8, 16 | point_highlight_color: Union[Tuple[str, str], str] = ("#768df1", "#768df1"), 17 | fill: Literal["enabled", "disabled"] = "disabled", 18 | fill_color: Union[Tuple[str, str], str] = ("#bdc6ed", "#5d6db6"), 19 | *args: any 20 | ) -> None: 21 | """ 22 | Initialize a CTkLine object. 23 | 24 | Args: 25 | master (any): The master object. 26 | color (Union[Tuple[str, str], str]): The color of the line. 27 | size (int): The size/thickness of the line. 28 | style (str): The style of the line (e.g., 'normal', 'dashed', 'dotted'). 29 | style_type (Tuple[int, int]): The style type for dashed or dotted lines. 30 | point_highlight (str): Whether point highlighting is enabled or disabled. 31 | point_highlight_size (int): The size of points used for highlighting. 32 | point_highlight_color (Union[Tuple[str, str], str]): The color of points used for highlighting. 33 | fill (str): Whether fill for the line is enabled or disabled. 34 | fill_color (Union[Tuple[str, str], str]): The color of the fill for the line. 35 | Raises: 36 | TypeError: If any of the parameters are of an incorrect type. 37 | ValueError: If any of the parameters are invalid. 38 | """ 39 | if master is None: 40 | if len(args) != 0: 41 | master = args[0] 42 | else: 43 | Validate._master_att_not_provide_for_line("master") 44 | 45 | Validate._is_valid_ctk_line_chart(master, "master") 46 | Validate._is_valid_color(color, "color") 47 | Validate._is_int(size, "size") 48 | Validate._is_valid_line_style(style, "style") 49 | Validate._is_valid_style_type(style_type, "style_type") 50 | Validate._is_valid_line_highlight(point_highlight, "point_highlight") 51 | Validate._is_int(point_highlight_size, "point_highlight_size") 52 | Validate._is_valid_color(point_highlight_color, "point_highlight_color") 53 | Validate._is_valid_line_fill(fill, "fill") 54 | Validate._is_valid_color(fill_color, "fill_color") 55 | 56 | # id (int): The id of the line. need unique 57 | self.__id = CTkLine.current_usable_id 58 | CTkLine.current_usable_id += 1 59 | 60 | self.__master = master 61 | self.__color = color 62 | self.__size = size 63 | self.__y_end = 0 64 | self.__x_end = self.__master._CTkLineChart__x_axis_point_spacing * -1 65 | self.__data = [] 66 | self.__temp_data = [] 67 | self.__ret_data = [] 68 | self.__visibility = self.__master._CTkLineChart__visibility 69 | self.__style = style 70 | self.__style_type = style_type 71 | self.__point_highlight = point_highlight 72 | self.__point_highlight_size = point_highlight_size 73 | self.__point_highlight_color = point_highlight_color 74 | self.__fill = fill 75 | self.__fill_color = fill_color 76 | 77 | self.__master._CTkLineChart__lines.append(self) 78 | 79 | def configure( 80 | self, 81 | color: Union[Tuple[str, str], str] = None, 82 | size: int = None, 83 | style: Literal["normal", "dashed", "dotted"] = None, 84 | style_type: Tuple[int, int] = None, 85 | point_highlight: Literal["enabled", "disabled"] = None, 86 | point_highlight_size: int = None, 87 | point_highlight_color: Union[Tuple[str, str], str] = None, 88 | fill: Literal["enabled", "disabled"] = None, 89 | fill_color: Union[Tuple[str, str], str] = None 90 | ) -> None: 91 | """ 92 | Configure attributes of the CTkLine object. 93 | 94 | Args: 95 | color (Union[Tuple[str, str], str]): The color of the line. 96 | size (int): The size/thickness of the line. 97 | style (str): The style of the line (e.g., 'normal', 'dashed', 'dotted'). 98 | style_type (Tuple[int, int]): The style type for dashed or dotted lines. 99 | point_highlight (str): Whether point highlighting is enabled or disabled. 100 | point_highlight_size (int): The size of points used for highlighting. 101 | point_highlight_color (Union[Tuple[str, str], str]): The color of points used for highlighting. 102 | fill (str): Whether fill for the line is enabled or disabled. 103 | fill_color (Union[Tuple[str, str], str]): The color of the fill for the line. 104 | 105 | Raises: 106 | TypeError: If any of the parameters are of an incorrect type. 107 | ValueError: If any of the parameters are invalid. 108 | """ 109 | changes_req = False 110 | 111 | if color is not None: 112 | Validate._is_valid_color(color, "color") 113 | self.__color = color 114 | changes_req = True 115 | 116 | if size is not None: 117 | Validate._is_int(size, "size") 118 | self.__size = size 119 | changes_req = True 120 | 121 | if style is not None: 122 | Validate._is_valid_line_style(style, "style") 123 | self.__style = style 124 | changes_req = True 125 | 126 | if style_type is not None: 127 | Validate._is_valid_style_type(style_type, "style_type") 128 | self.__style_type = style_type 129 | changes_req = True 130 | 131 | if point_highlight is not None: 132 | Validate._is_valid_line_highlight(point_highlight, "point_highlight") 133 | self.__point_highlight = point_highlight 134 | changes_req = True 135 | 136 | if point_highlight_size is not None: 137 | Validate._is_int(point_highlight_size, "point_highlight_size") 138 | self.__point_highlight_size = point_highlight_size 139 | changes_req = True 140 | 141 | if point_highlight_color is not None: 142 | Validate._is_valid_color(point_highlight_color, "point_highlight_color") 143 | self.__point_highlight_color = point_highlight_color 144 | changes_req = True 145 | 146 | if fill is not None: 147 | Validate._is_valid_line_fill(fill, "fill") 148 | self.__fill = fill 149 | changes_req = True 150 | 151 | if fill_color is not None: 152 | Validate._is_valid_color(fill_color, "fill_color") 153 | self.__fill_color = fill_color 154 | changes_req = True 155 | 156 | if changes_req: 157 | self.__master._CTkLineChart__apply_line_configuration() 158 | 159 | def get_id(self) -> int: 160 | """ 161 | Get the unique identifier of the CTkLine object. 162 | 163 | Returns: 164 | int: The unique identifier of the line. 165 | """ 166 | return self.__id 167 | 168 | def __reset_positions(self) -> None: 169 | """ 170 | Reset the CTkLine object. 171 | """ 172 | self.__y_end = 0 173 | self.__x_end = self.__master._CTkLineChart__x_axis_point_spacing * -1 174 | 175 | def __reset_data(self) -> None: 176 | self.__data = [] 177 | 178 | def clear_data(self) -> None: 179 | """ 180 | Clears the chart data, ensuring that only the relevant visible data is retained. 181 | 182 | This method works by checking the maximum number of data points across all lines in the chart 183 | and the maximum number of visible data points. If the chart contains more data points than 184 | the visible limit, the data is cropped so that only the most recent data points (up to the 185 | visible limit) are kept. If the chart is already within the visible limit, the data is not altered. 186 | 187 | The data is trimmed from the beginning of the dataset, and the most recent points are kept. 188 | 189 | This ensures that the chart does not display more data than the allowed visible limit, 190 | optimizing performance and display consistency. 191 | 192 | Attributes: 193 | self.__data: The internal list that holds all the data for the lines on the chart. 194 | 195 | Returns: 196 | None: This method modifies the internal state of the data but does not return any value. 197 | """ 198 | maximum_data = self.__master._CTkLineChart__get_max_data_length_across_lines() 199 | max_visible_points = self.__master._CTkLineChart__get_max_visible_data_points() 200 | 201 | if maximum_data > max_visible_points: 202 | self.__data = self.__data[maximum_data - max_visible_points::] 203 | 204 | def get_data(self, start: int = None, end: int = None, step: int = None) -> Tuple[int | float]: 205 | """ 206 | Retrieve data points from the specified range and step. 207 | 208 | Args: 209 | start (int, optional): The starting index for slicing the data. Defaults to None. 210 | end (int, optional): The ending index for slicing the data. Defaults to None. 211 | step (int, optional): The step size for slicing the data. Defaults to None. 212 | 213 | Returns: 214 | Tuple[int | float]: A tuple of data points from the specified range and step. 215 | """ 216 | return tuple(self.__data[start: end: step]) 217 | 218 | def get_current_visible_data(self) -> Tuple[int | float]: 219 | """ 220 | Retrieve the currently visible data points. 221 | 222 | Determines visible data points based on the maximum data length across all lines 223 | and the maximum number of visible points. 224 | 225 | Returns: 226 | Tuple[int | float]: A tuple of currently visible data points. 227 | If no data is visible, an empty tuple is returned. 228 | """ 229 | maximum_data = self.__master._CTkLineChart__get_max_data_length_across_lines() 230 | max_visible_points = self.__master._CTkLineChart__get_max_visible_data_points() 231 | 232 | data = () 233 | if maximum_data > max_visible_points: 234 | data = tuple(self.__data[maximum_data - max_visible_points::]) 235 | else: 236 | data = () 237 | return data 238 | 239 | def get_x_axis_visible_point_count(self) -> int: 240 | """ 241 | Get the maximum number of data points that can be visible along the X-axis. 242 | 243 | Returns: 244 | int: The maximum number of visible data points on the X-axis. 245 | """ 246 | return self.__master.get_x_axis_visible_point_count() 247 | 248 | def reset(self) -> None: 249 | """ 250 | Reset the line. 251 | """ 252 | self.__reset_positions() 253 | self.__reset_data() 254 | self.__master._CTkLineChart__apply_line_configuration() 255 | 256 | def set_visible(self, state: bool) -> None: 257 | """ 258 | Set the visibility of the line. 259 | 260 | Args: 261 | state (bool): True if the line should be visible, False otherwise. 262 | 263 | Raises: 264 | TypeError: If the state is not a boolean. 265 | """ 266 | Validate._is_bool(state, "state") 267 | if self.__visibility != state: 268 | self.__visibility = state 269 | self.__master._CTkLineChart__apply_line_configuration() 270 | 271 | def cget( 272 | self, 273 | attribute_name: Literal[ 274 | "master", "color", "size", "style", "style_type", "point_highlight", 275 | "point_highlight_size", "point_highlight_color", "fill", "fill_color", 276 | "__all__" 277 | ] = "__all__" 278 | ) -> any: 279 | """ 280 | Get the value of a CTkLine attribute. 281 | 282 | Args: 283 | attribute_name (str): Name of the attribute. 284 | 285 | Returns: 286 | any: Value of the attribute. 287 | 288 | Raises: 289 | ValueError: If the attribute name is invalid. 290 | """ 291 | if attribute_name == "master": 292 | return self.__master 293 | elif attribute_name == "color": 294 | return self.__color 295 | elif attribute_name == "size": 296 | return self.__size 297 | elif attribute_name == "style": 298 | return self.__style 299 | elif attribute_name == "style_type": 300 | return self.__style_type 301 | elif attribute_name == "point_highlight": 302 | return self.__point_highlight 303 | elif attribute_name == "point_highlight_size": 304 | return self.__point_highlight_size 305 | elif attribute_name == "point_highlight_color": 306 | return self.__point_highlight_color 307 | elif attribute_name == "fill": 308 | return self.__fill 309 | elif attribute_name == "fill_color": 310 | return self.__fill_color 311 | elif attribute_name == "__all__": 312 | return { 313 | "master": self.__master, 314 | "color": self.__color, 315 | "size": self.__size, 316 | "style": self.__style, 317 | "style_type": self.__style_type, 318 | "point_highlight": self.__point_highlight, 319 | "point_highlight_size": self.__point_highlight_size, 320 | "point_highlight_color": self.__point_highlight_color, 321 | "fill": self.__fill, 322 | "fill_color": self.__fill_color 323 | } 324 | else: 325 | Validate._invalid_cget(attribute_name) 326 | 327 | def get_visibility(self) -> bool: 328 | """ 329 | Get the visibility of the line. 330 | 331 | Returns: 332 | bool: True if the line is visible, False otherwise. 333 | """ 334 | return self.__visibility 335 | 336 | def __del__(self) -> None: 337 | """Destructor method to delete instance attributes.""" 338 | del self.__id 339 | del self.__master 340 | del self.__color 341 | del self.__size 342 | del self.__y_end 343 | del self.__x_end 344 | del self.__data 345 | del self.__temp_data 346 | del self.__ret_data 347 | del self.__visibility 348 | del self.__style 349 | del self.__style_type 350 | del self.__point_highlight 351 | del self.__point_highlight_size 352 | del self.__point_highlight_color 353 | del self.__fill 354 | del self.__fill_color 355 | 356 | def destroy(self) -> None: 357 | """ 358 | Removes the instance from its master's line chart and 359 | applies the updated line configuration. Calls the destructor 360 | to clean up resources. 361 | """ 362 | try: 363 | self.__master._CTkLineChart__lines.remove(self) 364 | self.__master._CTkLineChart__apply_line_configuration() 365 | except ValueError: 366 | pass # In case the line is not in the list 367 | finally: 368 | self.__del__() 369 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Chinese](https://img.shields.io/badge/Language-中文-red)](README_zh.md) 2 | 3 |
    4 | 5 | [![ctkchart](https://snyk.io/advisor/python/ctkchart/badge.svg)](https://snyk.io/advisor/python/ctkchart) 6 | 7 | # ctkchart 8 | 9 | [![PyPI version](https://badge.fury.io/py/ctkchart.svg)](https://pypi.org/project/ctkchart/) 10 | 11 | [![Downloads](https://static.pepy.tech/badge/ctkchart)](https://pepy.tech/project/ctkchart) ![Downloads last 6 month](https://static.pepy.tech/personalized-badge/ctkchart?period=total&units=international_system&left_color=grey&right_color=BLUE&left_text=downloads%20last%206%20month) [![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) 12 | 13 | 14 | ![PyPI - License](https://img.shields.io/badge/license-MIT-blue) 15 | ![LOC](https://tokei.rs/b1/github/Thisal-D/ctkchart?category=lines) 16 | 17 |
    18 | 19 | 20 | **
  • ctkchart is a Python library for creating live updating line charts in customtkinter.
  • ** 21 | 22 | --- 23 | 24 | ### Features 25 | 26 | - **Live Update**: Display live data with line charts. 27 | - **Multiple Lines**: Support for plotting multiple lines on the same chart for easy comparison. 28 | - **Color Customization**: Customize colors to match your application's design or data representation. 29 | - **Dynamic Color Change**: Dynamic Color Change for Dark & Light. 30 | - **Font Customization**: Adjust fonts for text elements to enhance readability. 31 | - **Dimension Customization**: Customize chart dimensions to fit various display sizes and layouts. 32 | 33 | [**Check out what's new | Changes**](CHANGES_en.md) 34 | 35 | --- 36 | 37 | ### Importing & Installation 38 | * **Installation** 39 | ``` 40 | pip install ctkchart 41 | ``` 42 | 43 | * **Importing** 44 | ``` python 45 | import ctkchart 46 | ``` 47 | --- 48 | 49 | 50 | ### Simple Guide 51 | - **import package** 52 | ``` python 53 | import tkchart 54 | ``` 55 | 56 | - **Create Line Chart and place the chart** 57 | ``` python 58 | chart = ctkchart.CTkLineChart( 59 | master=root, 60 | x_axis_values=("a", "b", "c", "d", "e", "f"), 61 | y_axis_values=(100, 900) 62 | ) 63 | chart.place(x=10, y=10) 64 | ``` 65 | 66 | - **Create Line** 67 | ``` python 68 | line = ctkchart.CTkLine(master=chart) 69 | ``` 70 | 71 | - **Display Data** 72 | display data using a loop 73 | ``` python 74 | def loop(): 75 | while True: 76 | random_data = random.choice(range(100, 900)) 77 | chart.show_data(line=line, data=[random_data]) 78 | time.sleep(1) 79 | 80 | #call the loop as thead 81 | theading.Thread(target=loop).start() 82 | ``` 83 | 84 | --- 85 | 86 | ### Links 87 | 88 | - **Documentation :** [Documents](documentation) 89 | - [English doc.](documentation/DOCUMENTATION_en.md) 90 | - [Chinese doc.](documentation/DOCUMENTATION_zh.md) 91 | - **Python official :** [ctkchart](https://pypi.org/project/ctkchart/) 92 | 93 | --- 94 | 95 | ### What You Can Accomplish 96 | 97 | - **Simple** 98 | 99 | https://github.com/Thisal-D/ctkchart/assets/93121062/6f1e844f-d51c-467a-a3dc-ee03fea78fc9 100 | 101 | ``` python 102 | import customtkinter as ctk # Importing the customtkinter library as ctk 103 | import ctkchart # Importing the ctkchart module for chart creation 104 | import random # Importing the random module for generating random data 105 | import threading # Importing the threading module for running tasks concurrently 106 | import time # Importing the time module for adding delays 107 | 108 | # Create the root window and configure 109 | root = ctk.CTk() 110 | root.configure(fg_color="#0d1117") 111 | root.geometry("720x430+200+200") 112 | 113 | # Create a line chart widget 114 | line_chart = ctkchart.CTkLineChart( 115 | master=root, # Set the master as the root window 116 | 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 117 | y_axis_values=(0, 1000) # Y-axis values (range) 118 | ) 119 | 120 | line_chart.pack(pady=15) # Pack the line chart widget into the root 121 | 122 | # Create a line for the line chart 123 | line = ctkchart.CTkLine(master=line_chart) # Set the master as the line chart 124 | 125 | def display_data(): 126 | """Function to continuously display random data on the line chart.""" 127 | while True: 128 | random_data = [random.choice(range(0, 1000))] # Generate random data between 0 and 1000 129 | line_chart.show_data(line=line, data=random_data) # Display the random data on the line chart 130 | time.sleep(0.5) # Pause for 0.5 seconds before the next iteration 131 | 132 | # Call the display_data function as a separate thread 133 | threading.Thread(target=display_data).start() 134 | 135 | # Start the main event loop 136 | root.mainloop() 137 | ``` 138 | --- 139 | 140 | - **Simple style** 141 | 142 | https://github.com/Thisal-D/ctkchart/assets/93121062/afe56452-68c3-44f0-9c67-2ab6f6910f6e 143 | 144 | ``` python 145 | import customtkinter as ctk # Importing the customtkinter library as ctk 146 | import ctkchart # Importing the ctkchart module for chart creation 147 | import random # Importing the random module for generating random data 148 | import threading # Importing the threading module for running tasks concurrently 149 | import time # Importing the time module for adding delays 150 | 151 | # Create the root window and configure 152 | root = ctk.CTk() 153 | root.configure(fg_color="#0d1117") 154 | root.geometry("720x430+200+200") 155 | 156 | # Create a line chart widget 157 | line_chart = ctkchart.CTkLineChart( 158 | master=root, # Set the master as the root window 159 | 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 160 | y_axis_values=(0, 1000), # Y-axis values (range) 161 | y_axis_label_count=10, # set y axis labels count to 10 162 | ) 163 | 164 | line_chart.pack(pady=15) # Pack the line chart widget into the root 165 | 166 | # Create a line for the line chart 167 | line = ctkchart.CTkLine( 168 | master=line_chart, # Set the master as the line chart 169 | size=2, # Set the line size to 2 170 | fill="enabled" # enable line fill 171 | ) 172 | 173 | def display_data(): 174 | """Function to continuously display random data on the line chart.""" 175 | while True: 176 | random_data = [random.choice(range(0, 1000))] # Generate random data between 0 and 1000 177 | line_chart.show_data(line=line, data=random_data) # Display the random data on the line chart 178 | time.sleep(0.5) # Pause for 0.5 seconds before the next iteration 179 | 180 | # Call the display_data function as a separate thread 181 | threading.Thread(target=display_data).start() 182 | 183 | # Start the main event loop 184 | root.mainloop() 185 | ``` 186 | --- 187 | 188 | - **2 lines with different line styles** 189 | 190 | https://github.com/Thisal-D/ctkchart/assets/93121062/9bc35a39-a8ca-4942-9fc7-a1c89d1bd1bc 191 | 192 | ``` python 193 | import customtkinter as ctk # Importing the customtkinter library as ctk 194 | import ctkchart # Importing the ctkchart module for chart creation 195 | import random # Importing the random module for generating random data 196 | import threading # Importing the threading module for running tasks concurrently 197 | import time # Importing the time module for adding delays 198 | 199 | # Create the root window and configure 200 | root = ctk.CTk() 201 | root.configure(fg_color=("#ffffff", "#0d1117")) 202 | root.geometry("720x430+200+200") 203 | 204 | # Create a line chart widget 205 | line_chart = ctkchart.CTkLineChart( 206 | master=root, # Set the master as the root window 207 | 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 208 | y_axis_values=(0, 1000), # Y-axis values (range) 209 | y_axis_label_count=10, # set y axis labels count to 10 210 | ) 211 | 212 | line_chart.pack(pady=15) # Pack the line chart widget into the root 213 | 214 | line1 = ctkchart.CTkLine( 215 | master=line_chart, # Set the master as the line chart 216 | color=("#5dffb6","#5dffb6"), # index 0 for light and 1 for dark theme 217 | size=2, # Set the line size to 2 218 | style="dashed", # style change to dashed 219 | style_type=(10, 5), #index 0 for dash width and 1 for space between dashes 220 | ) 221 | 222 | line2 = ctkchart.CTkLine( 223 | master=line_chart, # Set the master as the line chart 224 | color=("#FFBAD2", "#FFBAD2"), # index 0 for light and 1 for dark theme 225 | size=2, # Set the line size to 2 226 | point_highlight="enabled", # enable point highlight 227 | point_highlight_color=("#FFBAD2", "#FFBAD2"), # enable point highlight 228 | ) 229 | 230 | def display_data(): 231 | """Function to continuously display random data on the line chart.""" 232 | while True: 233 | random_data = [random.choice(range(0, 1000))] # Generate random data between 0 and 1000 234 | line_chart.show_data(line=line1, data=random_data) # Display the random data on the line 1 on chart 235 | random_data = [random.choice(range(0, 1000))] # Generate random data between 0 and 1000 236 | line_chart.show_data(line=line2, data=random_data) # Display the random data on the line 2 on chart 237 | time.sleep(0.5) # Pause for 0.5 seconds before the next iteration 238 | 239 | # Call the display_data function as a separate thread 240 | threading.Thread(target=display_data).start() 241 | 242 | # Start the main event loop 243 | root.mainloop() 244 | ``` 245 | --- 246 | 247 | - **3 lines with different line styles** 248 | 249 | https://github.com/Thisal-D/ctkchart/assets/93121062/6d568b70-2ceb-42d0-b93c-0096f2745134 250 | 251 | ``` python 252 | import customtkinter as ctk # Importing the customtkinter library as ctk 253 | import ctkchart # Importing the ctkchart module for chart creation 254 | import random # Importing the random module for generating random data 255 | import threading # Importing the threading module for running tasks concurrently 256 | import time # Importing the time module for adding delays 257 | 258 | # Create the root window and configure 259 | root = ctk.CTk() 260 | root.configure(fg_color=("#ffffff", "#0d1117")) 261 | root.geometry("720x430+200+200") 262 | 263 | # Create a line chart widget 264 | line_chart = ctkchart.CTkLineChart( 265 | master=root, # Set the master as the root window 266 | 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 267 | y_axis_values=(0, 1000), # Y-axis values (range) 268 | y_axis_label_count=10, # set y axis labels count to 10 269 | ) 270 | 271 | line_chart.pack(pady=15) # Pack the line chart widget into the root 272 | 273 | # Create a line 1 for the line chart 274 | line1 = ctkchart.CTkLine( 275 | master=line_chart, # Set the master as the line chart 276 | size=2, # Set the line size to 2 277 | fill="enabled" # enable line fill 278 | ) 279 | 280 | line2 = ctkchart.CTkLine( 281 | master=line_chart, # Set the master as the line chart 282 | color=("#5dffb6","#5dffb6"), # index 0 for light and 1 for dark theme 283 | size=2, # Set the line size to 2 284 | style="dashed", # style change to dashed 285 | style_type=(10, 5), #index 0 for dash width and 1 for space between dashes 286 | ) 287 | 288 | line3 = ctkchart.CTkLine( 289 | master=line_chart, # Set the master as the line chart 290 | color=("#FFBAD2", "#FFBAD2"), # index 0 for light and 1 for dark theme 291 | size=2, # Set the line size to 2 292 | point_highlight="enabled", # enable point highlight 293 | point_highlight_color=("#FFBAD2", "#FFBAD2"), # enable point highlight 294 | ) 295 | 296 | def display_data(): 297 | """Function to continuously display random data on the line chart.""" 298 | while True: 299 | random_data = [random.choice(range(0, 1000))] # Generate random data between 0 and 1000 300 | line_chart.show_data(line=line1, data=random_data) # Display the random data on the line 1 on chart 301 | random_data = [random.choice(range(0, 1000))] # Generate random data between 0 and 1000 302 | line_chart.show_data(line=line2, data=random_data) # Display the random data on the line 2 on chart 303 | random_data = [random.choice(range(0, 1000))] # Generate random data between 0 and 1000 304 | line_chart.show_data(line=line3, data=random_data) # Display the random data on the line 3 on chart 305 | time.sleep(0.5) # Pause for 0.5 seconds before the next iteration 306 | 307 | # Call the display_data function as a separate thread 308 | threading.Thread(target=display_data).start() 309 | 310 | # Start the main event loop 311 | root.mainloop() 312 | ``` 313 | --- 314 | 315 | - **Advance** (Actually not, Just Two More Attributes Added) 316 | 317 | https://github.com/Thisal-D/ctkchart/assets/93121062/c2838fd6-3a0f-45be-bb39-9953d007067d 318 | 319 | ``` python 320 | import customtkinter as ctk # Importing the customtkinter library as ctk 321 | import ctkchart # Importing the ctkchart module for chart creation 322 | import random # Importing the random module for generating random data 323 | import threading # Importing the threading module for running tasks concurrently 324 | import time # Importing the time module for adding delays 325 | 326 | # Create the root window and configure 327 | root = ctk.CTk() 328 | root.configure(fg_color=("#ffffff", "#0d1117")) 329 | root.geometry("720x430+200+200") 330 | 331 | # Create a line chart widget 332 | line_chart = ctkchart.CTkLineChart( 333 | master=root, # Set the master as the root window 334 | 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 335 | y_axis_values=(0, 1000), # Y-axis values (range) 336 | y_axis_label_count=10, # set y axis labels count to 1 337 | y_axis_section_count=10, 338 | x_axis_section_count=10, 339 | ) 340 | 341 | line_chart.pack(pady=15) # Pack the line chart widget into the root 342 | 343 | line1 = ctkchart.CTkLine( 344 | master=line_chart, # Set the master as the line chart 345 | color=("#5dffb6","#5dffb6"), # index 0 for light and 1 for dark theme 346 | size=2, # Set the line size to 2 347 | style="dashed", # style change to dashed 348 | style_type=(10, 5), #index 0 for dash width and 1 for space between dashes 349 | ) 350 | 351 | line2 = ctkchart.CTkLine( 352 | master=line_chart, # Set the master as the line chart 353 | color=("#FFBAD2", "#FFBAD2"), # index 0 for light and 1 for dark theme 354 | size=2, # Set the line size to 2 355 | point_highlight="enabled", # enable point highlight 356 | point_highlight_color=("#FFBAD2", "#FFBAD2"), # enable point highlight 357 | ) 358 | 359 | def display_data(): 360 | """Function to continuously display random data on the line chart.""" 361 | while True: 362 | random_data = [random.choice(range(0, 1000))] # Generate random data between 0 and 1000 363 | line_chart.show_data(line=line1, data=random_data) # Display the random data on the line 1 on chart 364 | random_data = [random.choice(range(0, 1000))] # Generate random data between 0 and 1000 365 | line_chart.show_data(line=line2, data=random_data) # Display the random data on the line 2 on chart 366 | time.sleep(0.5) # Pause for 0.5 seconds before the next iteration 367 | 368 | # Call the display_data function as a separate thread 369 | threading.Thread(target=display_data).start() 370 | 371 | # Start the main event loop 372 | root.mainloop() 373 | ``` 374 | --- 375 | 376 | - #### Light and Dark theme 377 | 378 | **For every parameter that involves color in ctkchart, you can provide either**: 379 | - A single string representing the color. 380 | - 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. 381 | 382 | https://github.com/user-attachments/assets/9fed4b83-5b03-4ea0-82a0-36029dfc93dd 383 | 384 | --- 385 | 386 | **Explore customizable features such as colors, fonts, and more in the documentation.** 387 | 388 | #### Please refer to the full documentation 389 | - [**English doc.**](documentation/DOCUMENTATION_en.md) 390 | - [**Chinese doc.**](documentation/DOCUMENTATION_zh.md) 391 | 392 | --- 393 | 394 | #### Contributors 395 | - [](https://github.com/childeyouyu) [youyu](https://github.com/childeyouyu) 396 | -------------------------------------------------------------------------------- /documentation/DOCUMENTATION_zh.md: -------------------------------------------------------------------------------- 1 |
    2 | 3 | [![Language](https://img.shields.io/badge/Language-English-blue)](DOCUMENTATION_en.md) 4 | 5 | --- 6 | 7 | **如何使用** | **例子** | **参数说明** | **查看新功能** 8 | 9 |
    10 | 11 | ### 安装和使用 12 | * 安装 13 | ``` 14 | pip install ctkchart 15 | ``` 16 | 17 | * 使用 18 | ``` python 19 | import ctkchart 20 | ``` 21 | --- 22 | 23 |
    24 | 25 | ### 参数概述 26 | 27 |
    28 | 29 | 30 | 31 | 32 | 33 | 34 | --- 35 | 36 |
    37 | 38 |
    39 | 40 | ### 要使用 ctkchart 显示数据,您需要执行以下三步: 41 | 1. **创建折线图** 42 | 2. **创建一条线** 43 | 3. **数据显示** 44 | 45 | --- 46 | 47 |
    48 | 49 | ## 1 . 创建折线图 50 | **创建一条线** | **数据显示** 51 | 52 | ``` python 53 | linechart = ctkchart.CTkLineChart() 54 | ``` 55 | 56 | ### 参数 57 | 58 | | 参数 | 必备参数 / 可选参数 | 描述 | 数据类型 | 示例值 | 59 | |-------------------------------------------------|-------------|--------------------|---------------------------------|----------------------------------------| 60 | | master | ***必须*** | 折线图主体 | ``widget`` | widget | 61 | | [y_axis_values](#x_y_axis_values) | ***必须*** | y 轴的最小值和最大值 | ``tuple[int \| float], ...`` | (-1000, 1000), ... | 62 | | [x_axis_values](#x_y_axis_values) | ***必须*** | x 轴的值 | ``tuple[any, ...]`` | (1, 2, 3, 4, 5), ... | 63 | | width | ***可选*** | 折线图的宽度 | ``int`` | 300, ... | 64 | | height | ***可选*** | 折线图的高度 | ``int`` | 100, ... | 65 | | [axis_size](#parameter_img) | ***可选*** | 坐标轴宽度 | ``int`` | 1<= | 66 | | [axis_color](#parameter_img) | ***可选*** | 坐标轴轴颜色 | ``tuple[str, str]`` \| ``str`` | ("#FF0000", "#00FF00"), ... | 67 | | [bg_color](#parameter_img) | ***可选*** | 折线图的背景色 | ``tuple[str, str]`` \| ``str`` | ("#FF0000", "#00FF00"), ... | 68 | | [fg_color](#parameter_img) | ***可选*** | 折线图的前景色 | ``tuple[str, str]`` \| ``str`` | ("#FF0000", "#00FF00"), ... | 69 | | [data_font_style](#x_y_data) | ***可选*** | 坐标轴名称的字体样式 | ``tuple[str, int, str]`` | ("arial", 9, "bold"), ... | 70 | | [axis_font_style](#x_y_font_style) | ***可选*** | 坐标轴文字的字体样式 | ``tuple[str, int, str]`` | ("arial", 8, "normal"), ... | 71 | | [x_axis_data](#x_y_data) | ***可选*** | x_data 的值(x 坐标轴名称) | ``str`` | "X", ... | 72 | | [y_axis_data](#x_y_data) | ***可选*** | y_data 的值(y 坐标轴名称) | ``any`` | "Y", ... | 73 | | [x_axis_data_font_color](#x_y_data) | ***可选*** | x_data 的字体颜色 | ``tuple[str, str]`` \| ``str`` | ("#FF0000", "#00FF00"), "#707070", ... | 74 | | [y_axis_data_font_color](#x_y_data) | ***可选*** | y_data 的字体颜色 | ``tuple[str, str]`` \| ``str`` | ("#FF0000", "#00FF00"), "#707070", ... | 75 | | [x_axis_data_position](#data_position) | ***可选*** | x_data 的排布方式 | ``str`` | "top" | 76 | | [y_axis_data_position](#data_position) | ***可选*** | y_data 的排布方式 | ``str`` | "top" | 77 | | [x_axis_section_count](#x_y_section) | ***可选*** | x 轴上的网格线数 | ``int`` | 0<= | 78 | | [y_axis_section_count](#x_y_section) | ***可选*** | y 轴上的网格线数 | ``int`` | 0<= | 79 | | [x_axis_label_count](#x_y_label_count) | ***可选*** | x 轴标签数量 | ``int`` | 0<= | 80 | | [y_axis_label_count](#x_y_label_count) | ***可选*** | y 轴标签数量 | ``int`` | 1<= | 81 | | [x_axis_font_color](#x_y_font_style) | ***可选*** | x 轴标签的字体颜色 | ``tuple[str, str]`` \| ``str`` | ("#FF0000", "#00FF00"), "#606060", ... | 82 | | [y_axis_font_color](#x_y_font_style) | ***可选*** | y 轴标签的字体颜色 | ``tuple[str, str]`` \| ``str`` | ("#FF0000", "#00FF00"), "#606060", ... | 83 | | [x_axis_section_style](#x_y_section_style) | ***可选*** | x 轴上的网格线样式 | ``str`` | "normal" | 84 | | [y_axis_section_style](#x_y_section_style) | ***可选*** | y 轴上的网格线样式 | ``str`` | "normal" | 85 | | [x_axis_section_style_type](#x_y_section_style) | ***可选*** | x 轴上网格线的实线与空白的尺寸 | ``tuple[int, int]`` | (100, 50) , (50,50), ... | 86 | | [y_axis_section_style_type](#x_y_section_style) | ***可选*** | y 轴上网格线的实线与空白的尺寸 | ``tuple[int, int]`` | (100, 50) | 87 | | [x_axis_section_color](#x_y_section) | ***可选*** | x 轴上网格线的颜色 | ``tuple[str, str]`` \| ``str`` | ("#FF0000", "#00FF00"), "#2C2C2C", ... | 88 | | [y_axis_section_color](#x_y_section) | ***可选*** | y 轴上网格线的颜色 | ``tuple[str, str]`` \| ``str`` | ("#FF0000", "#00FF00"), "#2C2C2C" | 89 | | [y_axis_precision](#y_precision) | ***可选*** | y 轴值的精度 | ``int`` | 0<= | 90 | | [x_axis_display_values_indices](#indices_view) | ***可选*** | 显示在 x 轴上的坐标值的索引 | ``tuple[int, ...]`` | (0, 1, 2, 3, 4, 5), ... | 91 | | [x_axis_point_spacing](#x_axis_point_spacing) | ***可选*** | 线条宽度 | ``int`` \| ``str`` "auto" | "auto"
    1<= | 92 | | [x_space](#parameter_img) | ***可选*** | x 轴和图表区域之间的空间 | ``int`` | 0<= | 93 | | [y_space](#parameter_img) | ***可选*** | y 轴和图表区域之间的空间 | ``int`` | 0<= | 94 | | pointer_state | ***可选*** | 鼠标状态 | ``str`` ("enabled", "disabled") | "disabled" | 95 | | pointing_callback_function | ***可选*** | 鼠标的回调函数 | ``callable`` | function(*args)
    function(x, y) | 96 | | pointer_color | ***可选*** | 鼠标颜色 | ``tuple[str, str]`` \| ``str`` | ("#FF0000", "#00FF00"), "#606060", ... | 97 | | pointing_values_precision | ***可选*** | 指向值的精度 | ``int`` | 0<= | 98 | | pointer_lock | ***可选*** | 鼠标锁状态 | ``str`` ("enabled", "disabled") | "enabled" | 99 | | pointer_size | ***可选*** | 鼠标显示线的宽度 | ``int`` | 1<= | 100 | 101 | --- 102 | 103 | ### 方法 104 | 105 | | 方法 | 描述 | 支持的参数 / 必须的参数 | 返回类型 | 106 | |----------------------------|---------------------|----------------------------------------------------------------------------------------------------------------------------------|----------| 107 | | configure | 更改 LineChart(折线图)属性 | 所有属性,除了 master | ``None`` | 108 | | [show_data](#display-data) | 显示数据 | data: ``list``
    line: ``ctkchart.CTkLine`` | ``None`` | 109 | | place | 放置 (place) 折线图 | x: ``int``
    y: ``int``
    rely: ``float or int``
    relx: ``float or int``
    anchor: ``str`` | ``None`` | 110 | | pack | 放置 (pack) 折线图 | pady: ``int``
    padx: ``int``
    before: ``widget``
    after: ``widget``
    side: ``str``
    anchor: ``str`` | ``None`` | 111 | | grid | 放置 (grid) 折线图 | column: ``int``
    columnspan: ``int``
    padx: ``int``
    pady: ``int``
    row: ``int``
    rowspan: ``int``
    sticky: ``str`` | ``None`` | 112 | | place_forget | Place 忘编号 | - | ``None`` | 113 | | pack_forget | Pack 忘编号 | - | ``None`` | 114 | | grid_forget | Grid 忘编号 | - | ``None`` | 115 | | set_lines_visibility | 更改所有线条的可见性 | state: ``bool`` | ``None`` | 116 | | set_line_visibility | 更改特定行的可见性 | line: ``ctkchart.CTkLine``
    state: ``bool`` | ``None`` | 117 | | get_line_visibility | 获取特定生产线的可见性 | line: ``ctkchart.CTkLine`` | ``bool`` | 118 | | reset | 重置折线图 | - | ``None`` | 119 | | cget | 获取指定参数的值。 | attribute_name: ``str`` \| "\_\_all\_\_" | ``any`` | 120 | | place_info | 获取地点信息 | attribute_name: ``str`` \| "\_\_all\_\_" | ``any`` | 121 | | pack_info | 获取有关包装的信息 | attribute_name: ``str`` \| "\_\_all\_\_" | ``any`` | 122 | | grid_info | 获取网格信息 | attribute_name: ``str`` \| "\_\_all\_\_" | ``any`` | 123 | | get_line_area | 获取特定线的面积 | line: `ctkchart.CTkLine` | `float` | 124 | | get_lines_area | 获取所有线的面积 | - | `float` | 125 | | clear_data | 清除图表中所有线的数据,确保只保留最新的可见数据点。如果数据点总数超过最大可见点,则会从每条线的数据中移除旧数据。此方法确保图表仅显示基于最大可见范围的相关数据部分。 | - | ``None`` | 126 | | destroy | 销毁图表 | - | ``None`` | 127 | | get_lines_data | 获取指定范围内所有线条的数据点,可以选择步长值。 | start: `int`
    end: `int`
    step: `int` | `Dict[ctkchart.CTkLine, Tuple[int]]` | 128 | | get_line_data | 获取指定范围和步长值下某一条线的数据点。 | line: `ctkchart.CTkLine`
    start: `int`
    end: `int`
    step: `int` | `Tuple[int \| float]` | 129 | | get_x_axis_visible_point_count | 获取X轴上可见数据点的最大数量。 | - | `int` | 130 | | get_lines_visible_data | 获取所有线条当前可见的数据点,基于最大数据长度和可见点数。 | - | `Dict[ctkchart.CTkLine, Tuple[int \| float]]` | 131 | | get_line_visible_data | 获取某一条线当前可见的数据点。 | line: `ctkchart.CTkLine` | `Tuple[int \| float]` | 132 | 133 |
    134 | 135 |
    136 | 137 | --- 138 | 139 | ## 2 . 创建一条线 140 | 141 | **创建折线图** | **数据显示** 142 | 143 | ``` python 144 | line = ctkchart.CTkLine() 145 | ``` 146 | 147 | ### 参数 148 | 149 | | 参数名称 | 必备参数 / 可选参数 | 描述 | 数据类型 | 示例值 | 150 | |-------------------------------------------|-------------|------------------|----------------------------------------|---------------| 151 | | master | 必须 | Master | ``ctkchart.CTkLine`` | LineChart obj | 152 | | [color](#line_color_size) | 可选 | 折线的颜色 | ``str`` | "#768df1" | 153 | | [size](#line_color_size) | 可选 | Size of the line | ``int`` | 1<= | 154 | | [style](#line_style) | 可选 | 折线风格(直线、虚线、点线) | ``str`` ("normal", "dashed", "dotted") | "normal" | 155 | | [style_type](#line_style_type) | 可选 | 实线与虚线的尺寸 | ``tuple[int, int]`` | (10, 5),... | 156 | | [point_highlight](#point_highlight) | 可选 | 端点高亮状态 | ``str`` ("enabled", "disabled") | "disabled" | 157 | | [point_highlight_size](#point_highlight) | 可选 | 高亮点的大小 | ``int`` | 1<= | 158 | | [point_highlight_color](#point_highlight) | 可选 | 高亮点的颜色 | ``str`` | "#768df1" | 159 | | [fill](#fill) | 可选 | 是否启用填充 | ``str`` ("enabled", "disabled") | "disabled" | 160 | | [fill_color](#fill) | 可选 | 填充部分的颜​​色 | ``str`` | "#5d6db6" | 161 | 162 | --- 163 | 164 | ### 方法 165 | 166 | | 方法 | 描述 | 支持的参数 | 返回类型 | 167 | |----------------|----------|------------------------------------------|----------| 168 | | configure | 更改折线图属性 | 所有属性,除了 master | ``None`` | 169 | | cget | 获取指定参数的值 | attribute_name: ``str`` \| "\_\_all\_\_" | ``any`` | 170 | | reset | 重置线对象 | - | ``None`` | 171 | | set_visible | 改变线条的可见度 | state: ``bool`` | ``None`` | 172 | | get_visibility | 获得线路的可见度 | - | ``bool`` | 173 | | clear_data | 清除特定线的数据,确保只保留最新的可见数据点。如果线的数据超过最大可见点,则会修剪旧数据。此方法允许每条线独立清除其数据,确保它始终保持在可见范围内。 | - | ``None`` | 174 | | destroy | 破坏线 | - | ``None`` | 175 | | get_data | 获取指定范围的数据点,可以选择步长值。如果没有提供参数,将返回所有可用数据。 | start: `int`
    end: `int`
    step: `int` | `Tuple[int \| float]` | 176 | | get_current_visible_data | 根据所有线条的最大数据长度和最大可见点数,返回当前可见的数据点。 | - | `Tuple[int \| float]` | 177 | | get_x_axis_visible_point_count | 获取X轴上可见数据点的最大数量。 | - | `int` | 178 | 179 |
    180 | 181 |
    182 | 183 | --- 184 | 185 |
    186 | 187 | ## 3 . 数据显示 188 | 189 | **创建折线图** | **创建一条折线** 190 | 191 | 192 | ``` python 193 | import tkinter as tk 194 | import ctkchart 195 | import random 196 | 197 | ## root 198 | root = tk.Tk() 199 | root.configure(bg="#151515") 200 | 201 | ## 创建折线图 202 | chart = ctkchart.CTkLineChart( 203 | master=root, 204 | x_axis_values = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10), 205 | y_axis_values = (-100,100) 206 | ) 207 | chart.pack() 208 | 209 | ## 创建一条折线 210 | line = ctkchart.CTkLine(master=chart) 211 | 212 | data = [x for x in range(-100,101)] #values -100 to 100 213 | ## 显示数据(随机) 214 | def loop(): 215 | chart.show_data(line=line, data=random.choices(data, k=1)) 216 | root.after(500, loop) 217 | loop() 218 | 219 | root.mainloop() 220 | ``` 221 | 222 |
    223 | 224 | https://github.com/Thisal-D/tkchart/assets/93121062/64440c23-63e6-4093-b027-21b00a6f5518 225 | 226 | --- 227 | 228 |
    229 | 230 |
    231 | 232 | 233 |
    234 | 235 | **返回顶部** | **使用指南** | **例子** | **查看新功能** 236 | 237 | ## 参数说明 238 | 239 |
    240 | 241 | ### CTkLineChart 242 | 243 | - #### y_axis_values 244 | y_axis_values 是一个包含两个数值的元组。第一个值(索引 0)表示 y 轴的起始值,第二个值(索引 1)表示 y 轴的结束值。该元组定义了折线图上沿 y 轴显示的值的范围。 245 | 246 | - #### x_axis_values 247 | x_axis_values 是可以包含任何数据类型的值的集合。这些值被分配给 x 轴,从索引 0 开始一直到 x_axis_values 元组的最后一个索引。元组中的每个值对应于折线图中 x 轴上的一个点。 248 | 249 | 250 | 251 | 252 | 253 | 254 | ``` python 255 | chart = ctkchart.CTkLineChart( 256 | master=any_widget, 257 | x_axis_values=(2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025), 258 | y_axis_values=(-100, 100) 259 | ) 260 | ``` 261 | 262 | --- 263 | 264 |
    265 | 266 |
    267 | 268 | - #### x_axis_data 269 | 指折线图 x 轴上显示的值类型。 270 | **注意:"X"为默认值。** 271 | 272 | - #### y_axis_data 273 | 指折线图 y 轴上显示的值类型。 274 | **注意:"Y" 是默认值。** 275 | 276 | - #### x_axis_data_font_color 277 | 指应用于表示折线图 x_axis_data 的标签的字体颜色。 278 | 279 | - #### y_axis_data_font_color 280 | 指应用于表示折线图 y_axis_data 的标签的字体颜色。 281 | 282 | - #### data_font_style 283 | 指应用于代表折线图 x_axis_data 和 y_axis_data 的标签的字体样式。 284 | 285 | 286 | 287 | 288 | 289 | 290 | ``` python 291 | chart = ctkchart.CTkLineChart( 292 | master=any_widget, 293 | x_axis_values=(2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025), 294 | y_axis_values=(-100, 100), 295 | y_axis_data="Y data" , 296 | x_axis_data="X data", 297 | x_axis_data_font_color="#ff0000", 298 | y_axis_data_font_color="#00ff00", 299 | data_font_style=("arial", 15, "underline") 300 | ) 301 | ``` 302 | 303 | --- 304 | 305 |
    306 | 307 |
    308 | 309 | - #### x_axis_label_count 310 | 当您有一组 x_value(例如从 2018 年到 2025 年)时,通常会显示所有这些标签。但有时为了更清晰起见,您可能只想显示其中的几个。
    311 | 例如,如果您将 x_axis_label_count 设置为 4,则意味着您只想显示 4 个标签,而不是全部 8 个。因此,折线图将自动跳过一些标签以适合您指定的数量。
    312 | **注意:len(x_axis_values) 是默认值。**
    313 | 换句话说,调整 x_axis_label_count 可以让您控制 x 轴上显示的标签数量,使您的可视化更清晰、更易于理解。 314 |
    315 | -**如果有 9 个标签,您可以将其限制为:3、1。** 316 | -**如果有 20 个标签,您可以将其限制为:10, 5, 4, 2, 1。** 317 | -**如果有 15 个标签,您可以将其限制为:5、3、1。** 318 | 319 | #### 在某些情况下,使用 x_axis_label_count 参数可能不足以满足您的需求。在这种情况下,您可以利用 x_axis_display_values_indices 参数来精确控制 x 轴上显示的值。 320 | 321 | - #### y_axis_label_count 322 | 默认情况下,如果将 y 轴值设置为 -100 到 100 范围,则 y 轴上将仅显示极值(-100 和 100 两个数字)。但是,您可以选择使用 y_axis_label_count 参数调整显示的标签数量。
    323 | 例如,如果将 y_axis_label_count 设置为 3,系统会将 y 轴范围(-100 到 100)划分为相等的间隔,并按这些间隔显示标签。因此,对于本例,标签计数为 3,您可能会看到 -100、0 和 100 处的标签。
    324 | 总之,调整 y_axis_label_count 参数允许您控制 y 轴上显示的标签数量,从而可以根据您的偏好和要求灵活地自定义可视化效果。 325 | 326 | 327 | 328 | 329 | 330 | 331 | ``` python 332 | chart = ctkchart.CTkLineChart( 333 | master=any_widget, 334 | x_axis_values=(2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025), 335 | y_axis_values=(-100, 100), 336 | x_axis_label_count=4, 337 | y_axis_label_count=10 338 | ) 339 | ``` 340 | 341 | --- 342 | 343 |
    344 | 345 |
    346 | 347 | - #### x_axis_display_values_indices 348 | 假设您有一组代表从 2018 年到 2025 年的 x 轴值:(2018、2019、2020、2021、2022、2023、2024、2025)。通常,所有这些值都会显示在 x 轴上。
    349 | 但是,在某些情况下,您可能只想显示特定年份而不是全部。在这种情况下,您可以使用 x_axis_display_values_indices 参数来控制在 x 轴上显示哪些值。
    350 | 例如,如果您只想显示 2019 年、2022 年和 2025 年,则可以在 x_axis_display_values_indices 参数中指定它们的索引。因此,如果 2019 年的索引为 1、2022 年为 4、2025 年为 7(假设基于 0 的索引),则您可以将 x_axis_display_values_indices 设置为 (1, 4, 7)。
    351 | 这样,通过设置要显示的值的索引,您可以精确控制可视化中 X 轴上显示的值,从而允许您根据您的特定要求对其进行定制。 352 | 353 | 354 | 355 | 356 | 357 | 358 | ``` python 359 | chart = ctkchart.CTkLineChart( 360 | master=any_widget, 361 | x_axis_values=(2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025), 362 | y_axis_values=(-100, 100), 363 | x_axis_display_values_indices=(1, 4, 7) 364 | ) 365 | ``` 366 | 367 | --- 368 | 369 |
    370 | 371 |
    372 | 373 | - #### x_axis_data_position 374 | x_axis_data_position 参数确定 x_axis_data 的文字布局。 375 | 376 | 它有两个支持的值: 377 | - "top" 378 | - "side" 379 | 380 | **注意:“top”是默认位置** 381 | 382 | - #### y_axis_data_position 383 | y_axis_data_position 参数确定 y_axis_data 的文字布局。 384 | 385 | 它有两个支持的值: 386 | - "top" 387 | - "side" 388 | 389 | **注意:“top”是默认位置** 390 | 391 |
    392 | 393 | 在"top"、"side"之间进行选择分别确定 x/y_axis_data 是水平放置在数据点上方还是垂直放置在数据点旁边。此参数允许您根据您的喜好和可用空间自定义折线图的布局。 394 | 395 | 396 | 397 | 398 | 399 | 400 | ``` python 401 | chart = ctkchart.CTkLineChart( 402 | master=any_widget, 403 | x_axis_values=(2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025), 404 | y_axis_values=(-100, 100), 405 | x_axis_data_position="side", 406 | y_axis_data_position="top" 407 | ) 408 | ``` 409 | 410 | --- 411 | 412 |
    413 | 414 |
    415 | 416 | - #### y_axis_precision 417 | y_axis_ precision 参数控制 y 轴上的值显示的小数位数。
    418 | **注意:1 是默认精度**
    419 | 例如: 420 | - 如果将 y_axis_precision 设置为 0,则 y 轴上的值将显示为整数。
    421 | - 如果将 y_axis_precision 设置为 1,则 y 轴上的值将显示一位小数。
    422 | - 如果将 y_axis_precision 设置为 2,则 y 轴上的值将显示两位小数。 423 |
    424 | 425 | 此外 : 426 | - **调整 y_axis_ precision 参数允许您控制折线图中 y 轴值的精度级别。当处理需要特定精度的数据或当您想要通过减少显示的小数位数来提高折线图的可读性时,此参数特别有用。** 427 | 428 | 429 | 430 | 431 | 432 | 433 | ``` python 434 | chart = ctkchart.CTkLineChart( 435 | master=any_widget, 436 | x_axis_values=(2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025), 437 | y_axis_values=(-100, 100), 438 | y_axis_label_count=12, 439 | y_axis_precision=4, 440 | ) 441 | ``` 442 | 443 | --- 444 | 445 |
    446 | 447 |
    448 | 449 | - #### axis_font_style 450 | 指 x 和 y 轴值的字体样式 451 | 452 | - #### x_axis_font_color 453 | 指 x 轴值的颜色 454 | 455 | - #### y_axis_font_color 456 | 指 y 轴值的颜色 457 | 458 | 459 | 460 | 461 | 462 | 463 | ``` python 464 | chart = ctkchart.CTkLineChart( 465 | master=any_widget, 466 | x_axis_values=(2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025), 467 | y_axis_values=(-100, 100), 468 | x_axis_font_color="#00FF00", 469 | y_axis_font_color="#FF0000", 470 | axis_font_style=("arial", 13, "bold") 471 | ) 472 | ``` 473 | 474 | --- 475 | 476 |
    477 | 478 |
    479 | 480 |
    481 | 482 | - #### x_axis_section_count 483 | x_axis_section_count 参数定义折线图中 x 轴范围将划分为的部分或间隔的数量。
    484 | **这里有更清晰的细分:** 485 | - 假设 x 轴上有一系列值,例如从 2018 年到 2025 年。默认情况下,此范围可能表示为连续线,没有标记任何特定部分或间隔。 486 | - 但是,如果将 x_axis_section_count 设置为一个值,例如 8,则意味着您想要将此 x 轴范围划分为等间距的部分或间隔。每个部分将代表总 x 轴范围的一个子集。 487 | - 调整 x_axis_section_count 参数允许您控制折线图中 x 轴的粒度,使查看者更容易解释数据并识别特定间隔内的趋势。 488 | 489 |
    490 | 491 | - #### y_axis_section_count 492 | y_axis_section_count 参数定义折线图中 y 轴范围将划分为的部分或间隔的数量。
    493 | **请参阅:x_axis_section_count** 了解更多... 494 | 495 | - #### x_axis_section_color 496 | 指 y 轴网格线的颜色 497 | 498 | - #### y_axis_section_color 499 | 指 x 轴网格线的颜色 500 | 501 | 502 | 503 | 504 | 505 | 506 | ``` python 507 | chart = ctkchart.CTkLineChart( 508 | master=any_widget, 509 | x_axis_section_count=8, 510 | y_axis_section_count=5, 511 | x_axis_section_color="#2C2C2C", 512 | y_axis_section_color="#2C2C2C" 513 | ) 514 | ``` 515 | 516 | --- 517 | 518 |
    519 | 520 |
    521 | 522 |
    523 | 524 | - #### x_axis_section_style 525 | x_axis_section_style 参数允许您定义折线图中沿 x 轴的部分的视觉样式。 526 | 527 | - 支持的样式: 528 | - "dashed": 当您将 x_axis_section_style 设置为“dashed”时,沿 x 轴的剖面将使用虚线显示。 529 | - "normal": 相反,当 x_axis_section_style 设置为“正常”时,沿 x 轴的截面将使用实线显示。 530 |
    531 | 532 | **注意:"normal"是默认样式。** 533 | 534 |
    535 | 536 | - #### y_axis_section_style 537 | 与 x_axis_section_style 工作方式相同, 538 | 有关更多信息,请参阅 x_axis_section_style 539 | 540 |
    541 | 542 | - #### x_axis_section_style_type 543 | x_axis_section_style_type 参数是一个包含两个整数值的元组,指定当 x_axis_section_style 设置为“dashed”时使用的破折号样式。
    544 | 例如:
    545 | - 如果将 x_axis_section_style_type 设置为 (20, 10),则意味着: 546 | - 每个破折号的宽度为 20 像素。 547 | - 破折号之间的间距为 10 548 |
    549 | 550 | 551 | 这些值确定用于表示沿 x 轴的部分的虚线或标记的视觉外观。通过调整这些值,您可以根据您的偏好或可视化要求自定义虚线部分的外观。 552 | 553 |
    554 | 555 | - #### y_axis_section_style_type 556 | 与 x_axis_section_style_type 工作相同, 557 | 请参阅 x_axis_section_style_type 了解更多信息 558 | 559 | 560 | 561 | 562 | 563 | 564 | ``` python 565 | chart = ctkchart.CTkLineChart( 566 | master=any_widget, 567 | x_axis_section_count=8, 568 | y_axis_section_count=5, 569 | x_axis_section_style="dashed", 570 | x_axis_section_style_type=(20,10), 571 | y_axis_section_style="dashed", 572 | y_axis_section_style_type=(20,10), 573 | ) 574 | ``` 575 | 576 | --- 577 | 578 |
    579 | 580 | 581 |
    582 | 583 | - #### x_axis_point_spacing 584 | x_axis_point_spacing 参数允许您手动设置 x 轴上点之间的间距,通常以像素为单位测量。但是,如果您不手动设置该参数,则会根据 x_axis_values 的长度自动计算。 585 |
    586 | **注意:"auto"是默认值。** 587 |
    588 | 589 | - 将特定值配置为 x_axis_point_spacing 后,您可以通过将其配置为"auto"来重置值以设置默认值。 590 |
    591 | ``` python 592 | chart.configure( 593 | x_axis_point_spacing="auto" 594 | ) 595 | ``` 596 | 597 | 598 | 599 | 600 | 601 | 602 | ``` python 603 | chart = ctkchart.CTkLineChart( 604 | master=any_widget, 605 | x_axis_point_spacing="auto" 606 | ) 607 | ``` 608 | 609 | x_axis_point_spacing 参数是根据 x_axis_values 元组的长度自动计算的。这意味着 x 轴上点之间的间距是通过将折线图的宽度除以 x_axis_values 列表的长度来确定的。 610 | 611 | 612 | 613 | 614 | 615 | 616 | 当您将 x_axis_point_spacing 参数设置为特定值(例如 40)时,这意味着您已手动将 x 轴上的点之间的间距指定为 40 个单位(例如像素)。在这种情况下,无论 x_axis_values 元组的长度如何,折线图都将在 x 轴上的每个点之间使用用户定义的 40 个单位的间距。 617 | 618 | ``` python 619 | chart = ctkchart.CTkLineChart( 620 | master=any_widget, 621 | x_axis_point_spacing=40 622 | ) 623 | ``` 624 | 625 | --- 626 | 627 |
    628 | 629 | ### CTkLine 630 | 631 |
    632 | 633 | - #### color 634 | 指的是线条的颜色。 635 | 636 | - #### size 637 | 指线条的尺寸(粗细)。
    638 | **注:1 为默认尺寸** 639 |
    640 | 641 | 642 | 643 | 644 | 645 | 646 | ``` python 647 | line = ctkchart.CTkLine( 648 | master=chart, 649 | color="#30ACC7", 650 | size=5 651 | ) 652 | ``` 653 | 654 | --- 655 | 656 |
    657 | 658 |
    659 | 660 | - #### style 661 | style 参数允许您定义线条的视觉样式。 662 |
    663 | - 支持的样式: 664 | - "dashed": 当样式设置为"dashed"时,折线条显示为虚线。 665 | - "dotted": 当样式设置为"dotted"时,折线显示为点虚线。 666 | - "normal": 当样式设置为"normal"时,线条显示为实线。 667 |
    668 | **注意:"normal"是默认样式。** 669 | 670 | 671 | 672 | 673 | 674 | 675 | ``` python 676 | line = ctkchart.CTkLine( 677 | master=chart, 678 | line_style="dashed" 679 | ) 680 | ``` 681 | 682 | --- 683 | 684 |
    685 | 686 |
    687 | 688 | - #### style_type 689 | style_type 参数是一个包含两个整数值的元组,指定样式设置为"dashed"或"dotted"时使用的破折号和点的样式。 690 | 691 | 例如: 692 | - 如果将 style_type 设置为 (20, 10),则意味着: 693 | - 每个破折号的宽度或每个点的大小为 20 像素。 694 | - 破折号或点之间的间距为 10 个像素。 695 | 696 | **注意 在"dotted"风格下 , size 参数无关紧要,因为点的大小是由 style_type 元组确定的固定大小。**
    697 | **注意 在"normal"风格下,style_type 参数无效。** 698 | 699 | 700 | 701 | 702 | 703 | 704 | ``` python 705 | line = ctkchart.CTkLine( 706 | master=chart, 707 | line_style="dashed", 708 | line_style_type=(10,2) 709 | ) 710 | ``` 711 | 712 | --- 713 | 714 |
    715 | 716 |
    717 | 718 | - #### point_highlight 719 | point_highlight 参数用于控制点高亮。 720 |
    721 | - 支持的值: 722 | - "enabled": 启用点高亮显示。 723 | - "disabled": 禁用点高亮显示。 724 | 725 | - #### point_highlight_size 726 | point_highlight_size 用于设置高亮点的大小。 727 | 728 | - #### point_highlight_color 729 | 高亮点的颜色。 730 | 731 | 732 | 733 | 734 | 735 | 736 | ``` python 737 | line = ctkchart.CTkLine( 738 | master=chart, 739 | point_highlight="enabled", 740 | point_highlight_color="#80CCFF", 741 | point_highlight_size=8 742 | ) 743 | ``` 744 | 745 | --- 746 | 747 |
    748 | 749 |
    750 | 751 | - #### fill 752 | fill 参数用于控制是否启用或禁用行填充。 753 |
    754 | - 支持的值: 755 | - "enabled": 启用线条填充。 756 | - "disabled": 禁用线条填充。 757 | 758 | - #### fill_color 759 | fill_color 参数用于指定填充的颜色。 760 | 761 | 762 | 763 | 764 | 765 | 766 | ``` python 767 | line = ctkchart.CTkLine( 768 | master=chart, 769 | fill="enabled", 770 | fill_color="#5D6DB6" 771 | ) 772 | ``` 773 | 774 |
    775 | 776 |
    777 | 778 | --- 779 | 780 |
    781 | 782 | ## 动态颜色变化 783 | 784 | ***对于 ctkchart 中涉及颜色的每个参数,有两种写法***: 785 | 786 | - 代表颜色的单个字符串。 787 | - 两个字符串的元组,其中第一个字符串表示浅色主题的颜色,第二个字符串表示深色主题的颜色。 788 | 789 |
    790 | 791 |
    792 | 793 | --- 794 | 795 | **回到顶部** | **使用指南** | **参数说明** | **查看新功能** 796 | 797 | ## [例子](https://github.com/Thisal-D/ctkchart/tree/main/template(s)) 798 | 799 |
    800 | 801 | 802 | 803 | 804 | 805 | 806 | 807 | 808 | 809 | 810 | 811 | 812 | 813 | 814 | 815 |
    816 | 817 |
    818 | 819 | --- 820 | 821 | ## 链接 822 | 823 | **PyPi.org** : ctkchart 824 | 825 | **GitHub.com** : ctkchart 826 | 827 | --- 828 | 829 | ## 翻译贡献 830 | 831 | **翻译支持** : [有语](https://github.com/childeyouyu) 832 | 833 | **Translation by** : [youyu](https://github.com/childeyouyu) -------------------------------------------------------------------------------- /Tests/Main - Test.py: -------------------------------------------------------------------------------- 1 | import ctkchart 2 | import customtkinter as ctk 3 | import random 4 | 5 | root = ctk.CTk() 6 | root.geometry("1900x900") 7 | 8 | data = ([x for x in range(0,1001)]) 9 | x_axis_values = tuple([x for x in range(1,21)]) 10 | line_chart = ctkchart.CTkLineChart(master=root, 11 | x_axis_values=x_axis_values, y_axis_values=(0, 1000)) 12 | line_chart.pack() 13 | 14 | 15 | line = ctkchart.CTkLine(master=line_chart, style="dashed", style_type=(10,5), size=1, color=("#404040", "lightblue"), fill="enabled", 16 | point_highlight="enabled", point_highlight_size=5, point_highlight_color=("#404040", "lightblue")) 17 | 18 | def loop(): 19 | line_chart.show_data(line=line ,data=[random.choice(data)]) 20 | root.after(100, loop) 21 | loop() 22 | 23 | 24 | frame = ctk.CTkScrollableFrame(master=root, width=1000, height=900, fg_color=("#FFFFFF","#151515")) 25 | frame.pack(pady=100) 26 | 27 | def line_chart_configure(**kwrgs): 28 | line_chart.configure(**kwrgs) 29 | 30 | def line_configure(**kwrgs): 31 | line.configure(**kwrgs) 32 | 33 | row = 1 34 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Line Chart Attributes : ", font=("Arial",25,"bold")).grid(row=row, column=1) 35 | row += 1 36 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Width : ").grid(row=row, column=1) 37 | column = 2 38 | for width in range(900,1600,100): 39 | 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) 40 | column += 1 41 | 42 | row += 1 43 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 44 | row += 1 45 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Height : ").grid(row=row, column=1) 46 | column = 2 47 | for height in range(350,900,50): 48 | 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) 49 | column += 1 50 | 51 | row += 1 52 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 53 | row += 1 54 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Axis Size : ").grid(row=row, column=1) 55 | column = 2 56 | for axis_size in range(1,9,1): 57 | 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) 58 | column += 1 59 | 60 | row += 1 61 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 62 | row += 1 63 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Y Axis Labels : ").grid(row=row, column=1) 64 | column = 2 65 | for y_axis_label_count in range(0,14,2): 66 | 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) 67 | column += 1 68 | 69 | row += 1 70 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 71 | row += 1 72 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="X Axis Labels : ").grid(row=row, column=1) 73 | column = 2 74 | for x_axis_label_count in [0, 1, 2, 4, 5, 10, 20]: 75 | 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) 76 | column += 1 77 | 78 | row += 1 79 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 80 | row += 1 81 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Y Axis Precision : ").grid(row=row, column=1) 82 | column = 2 83 | for y_axis_precision in range(0,9,1): 84 | 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) 85 | column += 1 86 | 87 | row += 1 88 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 89 | row += 1 90 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Y Axis values : ").grid(row=row, column=1) 91 | column = 2 92 | values = [(-1000, 1000), (0, 1000), (-2000, 1000), (0, 2000), (-5000,2000)] 93 | for i in range(5): 94 | 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) 95 | column += 1 96 | 97 | row += 1 98 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 99 | row += 1 100 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="X Axis Values : ").grid(row=row, column=1) 101 | column = 2 102 | for x_axis_values in range(1, 90, 10): 103 | ctk.CTkButton(master=frame, text="range({},{})".format(x_axis_values,x_axis_values+20), width=90, height=30, 104 | 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_)) 105 | ).grid(row=row, column=column, padx=10, pady=2) 106 | column += 1 107 | 108 | row += 1 109 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 110 | row += 1 111 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Y Axis Sections : ").grid(row=row, column=1) 112 | column = 2 113 | for y_axis_section_count in range(0, 14, 2): 114 | 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) 115 | column += 1 116 | 117 | row += 1 118 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 119 | row += 1 120 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="X Axis Sections : ").grid(row=row, column=1) 121 | column = 2 122 | for x_axis_section_count in range(0, 14, 2): 123 | 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) 124 | column += 1 125 | 126 | row += 1 127 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 128 | row += 1 129 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="x axis point spacing : ").grid(row=row, column=1) 130 | 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) 131 | column = 3 132 | for x_axis_point_spacing in range(10, 40, 5): 133 | 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) 134 | column += 1 135 | 136 | row += 1 137 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 138 | row += 1 139 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Y Space : ").grid(row=row, column=1) 140 | column = 2 141 | for y_space in range(0, 90, 10): 142 | 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) 143 | column += 1 144 | 145 | row += 1 146 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 147 | row += 1 148 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="X Space : ").grid(row=row, column=1) 149 | column = 2 150 | for x_space in range(0, 90, 10): 151 | 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) 152 | column += 1 153 | 154 | row += 1 155 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 156 | row += 1 157 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Y Axis Data : ").grid(row=row, column=1) 158 | column = 2 159 | 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) 160 | column += 1 161 | 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) 162 | 163 | row += 1 164 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 165 | row += 1 166 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="X Axis Data : ").grid(row=row, column=1) 167 | column = 2 168 | 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) 169 | column += 1 170 | 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) 171 | 172 | row += 1 173 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 174 | row += 1 175 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="X Axis Data Position : ").grid(row=row, column=1) 176 | column = 2 177 | 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) 178 | column += 1 179 | 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) 180 | 181 | row += 1 182 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 183 | row += 1 184 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Y Axis Data Position : ").grid(row=row, column=1) 185 | column = 2 186 | 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) 187 | column += 1 188 | 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) 189 | 190 | row += 1 191 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 192 | row += 1 193 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Data Font Style : ").grid(row=row, column=1) 194 | column = 2 195 | 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) 196 | column += 1 197 | 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) 198 | column += 1 199 | 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) 200 | column += 1 201 | 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) 202 | 203 | row += 1 204 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 205 | row += 1 206 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Axis Font Style : ").grid(row=row, column=1) 207 | column = 2 208 | 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) 209 | column += 1 210 | 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) 211 | column += 1 212 | 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) 213 | column += 1 214 | 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) 215 | 216 | row += 1 217 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 218 | row += 1 219 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="X Section Color : ").grid(row=row, column=1) 220 | column = 2 221 | 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) 222 | column += 1 223 | 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) 224 | column += 1 225 | 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) 226 | column += 1 227 | 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) 228 | column += 1 229 | 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) 230 | column += 1 231 | 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) 232 | column += 1 233 | 234 | 235 | row += 1 236 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 237 | row += 1 238 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Y Section Color : ").grid(row=row, column=1) 239 | column = 2 240 | 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) 241 | column += 1 242 | 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) 243 | column += 1 244 | 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) 245 | column += 1 246 | 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) 247 | column += 1 248 | 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) 249 | column += 1 250 | 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) 251 | column += 1 252 | 253 | 254 | row += 1 255 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 256 | row += 1 257 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="X Axis Section Style : ").grid(row=row, column=1) 258 | column = 2 259 | 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) 260 | column += 1 261 | 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) 262 | column += 1 263 | 264 | row += 1 265 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 266 | row += 1 267 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="X Axis Style Type : ").grid(row=row, column=1) 268 | column = 2 269 | 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) 270 | column += 1 271 | 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) 272 | column += 1 273 | 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) 274 | column += 1 275 | 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) 276 | column += 1 277 | 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) 278 | column += 1 279 | 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) 280 | column += 1 281 | 282 | row += 1 283 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 284 | row += 1 285 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Y Axis Section Style : ").grid(row=row, column=1) 286 | column = 2 287 | 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) 288 | column += 1 289 | 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) 290 | column += 1 291 | 292 | row += 1 293 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 294 | row += 1 295 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Y Axis Style Type : ").grid(row=row, column=1) 296 | column = 2 297 | 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) 298 | column += 1 299 | 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) 300 | column += 1 301 | 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) 302 | column += 1 303 | 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) 304 | column += 1 305 | 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) 306 | column += 1 307 | 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) 308 | column += 1 309 | 310 | 311 | row += 1 312 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 313 | row += 1 314 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Axis Color : ").grid(row=row, column=1) 315 | column = 2 316 | 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) 317 | column += 1 318 | 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) 319 | column += 1 320 | 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) 321 | column += 1 322 | 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) 323 | column += 1 324 | 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) 325 | column += 1 326 | 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) 327 | column += 1 328 | 329 | row += 1 330 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 331 | row += 1 332 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="BG Color : ").grid(row=row, column=1) 333 | column = 2 334 | 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) 335 | column += 1 336 | 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) 337 | column += 1 338 | 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) 339 | column += 1 340 | 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) 341 | column += 1 342 | 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) 343 | column += 1 344 | 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) 345 | column += 1 346 | 347 | row += 1 348 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 349 | row += 1 350 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="FG Color : ").grid(row=row, column=1) 351 | column = 2 352 | 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) 353 | column += 1 354 | 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) 355 | column += 1 356 | 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) 357 | column += 1 358 | 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) 359 | column += 1 360 | 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) 361 | column += 1 362 | 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) 363 | column += 1 364 | 365 | row += 1 366 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 367 | row += 1 368 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Y Axis Font Color : ").grid(row=row, column=1) 369 | column = 2 370 | 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) 371 | column += 1 372 | 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) 373 | column += 1 374 | 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) 375 | column += 1 376 | 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) 377 | column += 1 378 | 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) 379 | column += 1 380 | 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) 381 | column += 1 382 | 383 | row += 1 384 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 385 | row += 1 386 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="X Axis Font Color : ").grid(row=row, column=1) 387 | column = 2 388 | 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) 389 | column += 1 390 | 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) 391 | column += 1 392 | 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) 393 | column += 1 394 | 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) 395 | column += 1 396 | 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) 397 | column += 1 398 | 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) 399 | column += 1 400 | 401 | row += 1 402 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 403 | row += 1 404 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Y Axis Data Font Color : ").grid(row=row, column=1) 405 | column = 2 406 | 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) 407 | column += 1 408 | 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) 409 | column += 1 410 | 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) 411 | column += 1 412 | 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) 413 | column += 1 414 | 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) 415 | column += 1 416 | 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) 417 | column += 1 418 | 419 | row += 1 420 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 421 | row += 1 422 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="X Axis Data Font Color : ").grid(row=row, column=1) 423 | column = 2 424 | 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) 425 | column += 1 426 | 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) 427 | column += 1 428 | 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) 429 | column += 1 430 | 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) 431 | column += 1 432 | 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) 433 | column += 1 434 | 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) 435 | column += 1 436 | 437 | row += 1 438 | ctk.CTkFrame(master=frame ,height=10, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 439 | 440 | row += 1 441 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Line Attributes : ", font=("Arial",25,"bold")).grid(row=row, column=1) 442 | 443 | row += 1 444 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 445 | row += 1 446 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Size : ").grid(row=row, column=1) 447 | column = 2 448 | 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) 449 | column += 1 450 | 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) 451 | column += 1 452 | 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) 453 | 454 | row += 1 455 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 456 | row += 1 457 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Style : ").grid(row=row, column=1) 458 | column = 2 459 | 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) 460 | column += 1 461 | 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) 462 | column += 1 463 | 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) 464 | 465 | 466 | row += 1 467 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 468 | row += 1 469 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Style Type : ").grid(row=row, column=1) 470 | column = 2 471 | 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) 472 | column += 1 473 | 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) 474 | column += 1 475 | 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) 476 | column += 1 477 | 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) 478 | column += 1 479 | 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) 480 | 481 | 482 | 483 | row += 1 484 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 485 | row += 1 486 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Color : ").grid(row=row, column=1) 487 | column = 2 488 | 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) 489 | column += 1 490 | 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) 491 | column += 1 492 | 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) 493 | column += 1 494 | 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) 495 | column += 1 496 | 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) 497 | 498 | 499 | 500 | row += 1 501 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 502 | row += 1 503 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Point Hightlight : ").grid(row=row, column=1) 504 | column = 2 505 | 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) 506 | column += 1 507 | 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) 508 | column += 1 509 | 510 | 511 | 512 | row += 1 513 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 514 | row += 1 515 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Point Hightlight Size : ").grid(row=row, column=1) 516 | column = 2 517 | 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) 518 | column += 1 519 | 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) 520 | column += 1 521 | 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) 522 | column += 1 523 | 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) 524 | column += 1 525 | 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) 526 | 527 | 528 | 529 | row += 1 530 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 531 | row += 1 532 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Point Hightlight Color : ").grid(row=row, column=1) 533 | column = 2 534 | 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) 535 | column += 1 536 | 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) 537 | column += 1 538 | 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) 539 | column += 1 540 | 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) 541 | column += 1 542 | 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) 543 | 544 | 545 | row += 1 546 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 547 | row += 1 548 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Fill : ").grid(row=row, column=1) 549 | column = 2 550 | 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) 551 | column += 1 552 | 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) 553 | column += 1 554 | 555 | row += 1 556 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 557 | row += 1 558 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Point Hightlight Color : ").grid(row=row, column=1) 559 | column = 2 560 | 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) 561 | column += 1 562 | 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) 563 | column += 1 564 | 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) 565 | column += 1 566 | 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) 567 | column += 1 568 | 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) 569 | 570 | 571 | root.mainloop() -------------------------------------------------------------------------------- /documentation/DOCUMENTATION_en.md: -------------------------------------------------------------------------------- 1 |
    2 | 3 | [![Chinese](https://img.shields.io/badge/Language-中文-red)](DOCUMENTATION_zh.md) 4 | 5 |
    6 | 7 | --- 8 | 9 |
    10 | 11 | **Usage Guide** | **Examples** | **Parameter Explanation** | **Whats New ?** 12 | 13 | ### Importing & Installation 14 | * Installation 15 | ``` 16 | pip install ctkchart 17 | ``` 18 | 19 | * Importing 20 | ``` python 21 | import ctkchart 22 | ``` 23 | --- 24 |
    25 | 26 | ### Parameter Overview 27 | 28 |
    29 | 30 | 31 | 32 | 33 | 34 | 35 |
    36 |
    37 | 38 | --- 39 | 40 | ### To display data using ctkchart you need to do 3 main tasks 41 | 1. **Creating a Line Chart** 42 | 2. **Creating a Line** 43 | 3. **Display of data** 44 | 45 | --- 46 | 47 |
    48 | 49 | ## 1 . Creating a LineChart 50 | **Creating a Line** | **Display of data** 51 | 52 | ``` python 53 | linechart = ctkchart.CTkLineChart() 54 | ``` 55 | 56 | ### Parameters 57 | 58 | | Parameter | Required / Optional | Description | Types | Example Value(s) | 59 | |-------------------------------------------------|---------------------|--------------------------------------------|---------------------------------|-------------------------------------| 60 | | master | ***Required*** | Master Widget for LineChart | ``widget`` | widget | 61 | | [y_axis_values](#x_y_axis_values) | ***Required*** | Minimum and maximum values for y-axis | ``tuple[int \| float]`` | (-1000, 1000), ... | 62 | | [x_axis_values](#x_y_axis_values) | ***Required*** | Values for x-axis | ``tuple[any]`` | (1, 2, 3, 4, 5), ... | 63 | | width | ***Optional*** | Width of the chart | ``int`` | 300, ... | 64 | | height | ***Optional*** | Height of the chart | ``int`` | 100, ... | 65 | | [axis_size](#parameter_img) | ***Optional*** | Size of the axis | ``int`` | 1<= | 66 | | [axis_color](#parameter_img) | ***Optional*** | Color of the axis | ``tuple[str, str]`` \| ``str`` | ("#FF0000", "#00FF00"), ... | 67 | | [bg_color](#parameter_img) | ***Optional*** | Background color of the chart | ``tuple[str, str]`` \| ``str`` | ("#FF0000", "#00FF00"), ... | 68 | | [fg_color](#parameter_img) | ***Optional*** | Foreground color of the chart | ``tuple[str, str]`` \| ``str`` | ("#FF0000", "#00FF00"), ... | 69 | | [data_font_style](#x_y_data) | ***Optional*** | Font style for data labels | ``tuple[str, int, str]`` | ("arial", 9, "bold"), ... | 70 | | [axis_font_style](#x_y_font_style) | ***Optional*** | Font style for axis labels | ``tuple[str, int, str]`` | ("arial", 8, "normal"), ... | 71 | | [x_axis_data](#x_y_data) | ***Optional*** | Data label for x-axis | ``str`` | "X", ... | 72 | | [y_axis_data](#x_y_data) | ***Optional*** | Value for y-axi data label | ``any`` | "Y", ... | 73 | | [x_axis_data_font_color](#x_y_data) | ***Optional*** | Font color for x-axis data label | ``tuple[str, str]`` \| ``str`` | ("#FF0000", "#00FF00"), ... | 74 | | [y_axis_data_font_color](#x_y_data) | ***Optional*** | Font color for y-axis data label | ``tuple[str, str]`` \| ``str`` | ("#FF0000", "#00FF00"), ... | 75 | | [x_axis_data_position](#data_position) | ***Optional*** | Position of x-axis data label | ``str`` ("top", "side") | "top" | 76 | | [y_axis_data_position](#data_position) | ***Optional*** | Position of y-axis data label | ``str`` ("top", "side") | "top" | 77 | | [x_axis_section_count](#x_y_section) | ***Optional*** | Number of sections on the x-axis | ``int`` | 0<= | 78 | | [y_axis_section_count](#x_y_section) | ***Optional*** | Number of sections on the y-axis | ``int`` | 0<= | 79 | | [x_axis_label_count](#x_y_label_count) | ***Optional*** | Number of x-axis labels | ``int`` | 0<= | 80 | | [y_axis_label_count](#x_y_label_count) | ***Optional*** | Number of y-axis labels | ``int`` | 1<= | 81 | | [x_axis_font_color](#x_y_font_style) | ***Optional*** | Font color for x-axis labels | ``tuple[str, str]`` \| ``str`` | ("#FF0000", "#00FF00"), ... | 82 | | [y_axis_font_color](#x_y_font_style) | ***Optional*** | Font color for y-axis labels | ``tuple[str, str]`` \| ``str`` | ("#FF0000", "#00FF00"), ... | 83 | | [x_axis_section_style](#x_y_section_style) | ***Optional*** | Style of sections on the x-axis | ``str`` ("normal", "dashed") | "normal" | 84 | | [y_axis_section_style](#x_y_section_style) | ***Optional*** | Style of sections on the y-axis | ``str`` ("normal", "dashed") | "normal" | 85 | | [x_axis_section_style_type](#x_y_section_style) | ***Optional*** | Style type for sections on the x-axis | ``tuple[int, int]`` | (100, 50), ... | 86 | | [y_axis_section_style_type](#x_y_section_style) | ***Optional*** | Style type for sections on the y-axis | ``tuple[int, int]`` | (100, 50) | 87 | | [x_axis_section_color](#x_y_section) | ***Optional*** | Color of sections on the x-axis | ``tuple[str, str]`` \| ``str`` | ("#FF0000", "#00FF00"), ... | 88 | | [y_axis_section_color](#x_y_section) | ***Optional*** | Color of sections on the y-axis | ``tuple[str, str]`` \| ``str`` | ("#FF0000", "#00FF00"), ... | 89 | | [y_axis_precision](#y_precision) | ***Optional*** | Precision for y-axis values | ``int`` | 0<= | 90 | | [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), ... | 91 | | [x_axis_point_spacing](#x_axis_point_spacing) | ***Optional*** | Width of lines | ``int`` \| ``str`` "auto" | "auto"
    1<= | 92 | | [x_space](#parameter_img) | ***Optional*** | Space between x-axis and chart area | ``int`` | 0<= | 93 | | [y_space](#parameter_img) | ***Optional*** | Space between y-axis and chart area | ``int`` | 0<= | 94 | | pointer_state | ***Optional*** | State of the pointer | ``str`` ("enabled", "disabled") | "disabled" | 95 | | pointing_callback_function | ***Optional*** | Callback function for pointer | ``callable`` | function(*args)
    function(x, y) | 96 | | pointer_color | ***Optional*** | Color of the pointer | ``tuple[str, str]`` \| ``str`` | ("#FF0000", "#00FF00"), ... | 97 | | pointing_values_precision | ***Optional*** | Precision for pointing values | ``int`` | 0<= | 98 | | pointer_lock | ***Optional*** | State of pointer lock | ``str`` ("enabled", "disabled") | "enabled" | 99 | | pointer_size | ***Optional*** | Size of the pointer | ``int`` | 1<= | 100 | 101 | 102 | --- 103 | 104 | ### Methods 105 | 106 | | Method | Description | Supported / Required Parameters | Return Type | 107 | |----------------------------|------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------|-------------| 108 | | configure | Change LineChart attributes | All attributes except for master | ``None`` | 109 | | [show_data](#display-data) | Display data | data: ``list``
    line: ``ctkchart.CTkLine`` | ``None`` | 110 | | place | Place LineChart | x: ``int``
    y: ``int``
    rely: ``float or int``
    relx: ``float or int``
    anchor: ``str`` | ``None`` | 111 | | pack | Pack LineChart | pady: ``int``
    padx: ``int``
    before: ``widget``
    after: ``widget``
    side: ``str``
    anchor: ``str`` | ``None`` | 112 | | grid | Grid LineChart | column: ``int``
    columnspan: ``int``
    padx: ``int``
    pady: ``int``
    row: ``int``
    rowspan: ``int``
    sticky: ``str`` | ``None`` | 113 | | place_forget | Place forget the chart | - | ``None`` | 114 | | pack_forget | Pack forget the chart | - | ``None`` | 115 | | grid_forget | Grid forget the chart | - | ``None`` | 116 | | set_lines_visibility | Change the visibility of all the lines | state: ``bool`` | ``None`` | 117 | | set_line_visibility | Change the visibility of a specific line | line: ``ctkchart.CTkLine``
    state: ``bool`` | ``None`` | 118 | | get_line_visibility | Get the visibility of a specific line | line: ``ctkchart.CTkLine`` | ``bool`` | 119 | | reset | Reset line chart | - | ``None`` | 120 | | cget | Get the value of the specified parameter | attribute_name: ``str`` \| "\_\_all\_\_" | ``any`` | 121 | | place_info | Get info about place | attribute_name: ``str`` \| "\_\_all\_\_" | ``any`` | 122 | | pack_info | Get info about pack | attribute_name: ``str`` \| "\_\_all\_\_" | ``any`` | 123 | | grid_info | Get info about grid | attribute_name: ``str`` \| "\_\_all\_\_" | ``any`` | 124 | | get_line_area | Get the are of specific line | line: `ctkchart.CTkLine` | ``float`` | 125 | | get_lines_area | Get the are of all lines | - | ``float`` | 126 | | destroy | Destroy the chart | - | ``None`` | 127 | | 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`` | 128 | | get_lines_data | Retrieves data points for all lines within a specified range with an optional step value. | start: `int`
    end: `int`
    step: `int` | `Dict[ctkchart.CTkLine, Tuple[int]]` | 129 | get_line_data | Retrieves data points for a specific line within a specified range and step. | line: `ctkchart.CTkLine`
    start: `int`
    end: `int`
    step: `int` | `Tuple[int \| float]` | 130 | | get_x_axis_visible_point_count | Retrieves the maximum number of data points that can be visible along the X-axis. | - | `int` | 131 | | get_lines_visible_data | Retrieves currently visible data points for all lines based on the maximum data length and visible points. | - | `Dict[ctkchart.CTkLine, Tuple[int \| float]]` | 132 | | get_line_visible_data | Retrieves currently visible data points for a specific line. | line: `ctkchart.CTkLine` | `Tuple[int \| float]` | 133 | 134 |
    135 | 136 | --- 137 | 138 |
    139 | 140 | ## 2 . Creating a Line 141 | 142 | **Creating a LineChart** | **Display of data** 143 | 144 | ``` python 145 | line = ctkchart.CTkLine() 146 | ``` 147 | 148 | ### Parameters 149 | 150 | | Parameter Name | Required / Optional | Description | Types | Example Value(s) | 151 | |-------------------------------------------|---------------------|--------------------------------|----------------------------------------|------------------| 152 | | master | Required | Master of the line | ``ctkchart.CTkLine`` | LineChart obj | 153 | | [color](#line_color_size) | Optional | Color of the line | ``tuple[str, str]`` \| ``str`` | "#768df1" | 154 | | [size](#line_color_size) | Optional | Size of the line | ``int`` | 1<= | 155 | | [style](#line_style) | Optional | Style of the line | ``str`` ("normal", "dashed", "dotted") | "normal" | 156 | | [style_type](#line_style_type) | Optional | Style type for the line | ``tuple[int, int]`` | (10, 5),... | 157 | | [point_highlight](#point_highlight) | Optional | State of point highlighting | ``str`` ("enabled", "disabled") | "disabled" | 158 | | [point_highlight_size](#point_highlight) | Optional | Size of the highlighted point | ``int`` | 1<= | 159 | | [point_highlight_color](#point_highlight) | Optional | Color of the highlighted point | ``tuple[str, str]`` \| ``str`` | "#768df1" | 160 | | [fill](#fill) | Optional | State of filling | ``str`` ("enabled", "disabled") | "disabled" | 161 | | [fill_color](#fill) | Optional | Color of the fill | ``tuple[str, str]`` \| ``str`` | "#5d6db6" | 162 | 163 | 164 | --- 165 | 166 | ### Methods 167 | 168 | | Method | Description | Supported Parameters | Return Type | 169 | |----------------|------------------------------------------|--------------------------------------------|-------------| 170 | | configure | Change LineChart attributes | All attributes except for master | ``None`` | 171 | | cget | Get the value of the specified parameter | attribute_name: ``str`` \| "\_\_all\_\_" | ``any`` | 172 | | reset | reset line object | - | ``None`` | 173 | | set_visible | change the visibility of the line | state: ``bool`` | ``None`` | 174 | | get_visibility | get the visibility of the line | - | ``bool`` | 175 | | 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`` | 176 | | destroy | Destroy the line | - | ``None`` | 177 | | get_data | Retrieves data points from a specified range with an optional step value. If no parameters are given, it returns all available data. | start: `int`
    end: `int`
    step: `int` | `Tuple[int \| float]` | 178 | | get_current_visible_data | Returns the currently visible data points based on the maximum data length across all lines and the maximum number of visible points. | - | `Tuple[int \| float]` | 179 | | get_x_axis_visible_point_count | Retrieves the maximum number of data points that can be visible along the X-axis. | - | `int` | 180 | 181 |
    182 | 183 | --- 184 | 185 |
    186 | 187 | ## 3 . Display of Data 188 | 189 | **Creating a LineChart** | **Creating a Line** 190 | 191 | ``` python 192 | import tkinter as tk 193 | import ctkchart 194 | import random 195 | 196 | #root 197 | root = tk.Tk() 198 | root.configure(bg="#151515") 199 | 200 | #creating a chart 201 | chart = ctkchart.CTkLineChart( 202 | master=root, 203 | x_axis_values = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10), 204 | y_axis_values = (-100,100) 205 | ) 206 | chart.pack() 207 | 208 | #creating a line 209 | line = ctkchart.CTkLine(master=chart) 210 | 211 | data = [x for x in range(-100,101)] #values -100 to 100 212 | #dipslay data (random) 213 | def loop(): 214 | chart.show_data(line=line, data=random.choices(data, k=1)) 215 | root.after(500, loop) 216 | loop() 217 | 218 | root.mainloop() 219 | ``` 220 | 221 |
    222 | 223 | https://github.com/Thisal-D/tkchart/assets/93121062/64440c23-63e6-4093-b027-21b00a6f5518 224 | 225 |
    226 | 227 | --- 228 | 229 |
    230 | 231 | 232 |
    233 | 234 | **Back to the Top** | **Usage Guide** | **Examples** | **Whats New ?** 235 | 236 | ## Parameter Explanation 237 | 238 |
    239 | 240 | ### CTkLineChart 241 | 242 | - #### y_axis_values 243 | 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. 244 | 245 | - #### x_axis_values 246 | 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. 247 | 248 | 249 | 250 | 251 | 252 | 253 | ``` python 254 | chart = ctkchart.CTkLineChart( 255 | master=any_widget 256 | x_axis_values=(2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025), 257 | y_axis_values=(-100, 100) 258 | ) 259 | ``` 260 | --- 261 |
    262 | 263 |
    264 | 265 | - #### x_axis_data 266 | refers to the value type displayed in the x-axis of a chart. 267 | **Note: "X" is the default value.** 268 | 269 | - #### y_axis_data 270 | refers to the value type displayed in the y-axis of a chart. 271 | **Note: "Y" is the default value.** 272 | 273 | - #### x_axis_data_font_color 274 | refers to the font color applied to the label representing the data type on x-axis of a chart. 275 | 276 | - #### y_axis_data_font_color 277 | refers to the font color applied to the label representing the data type on y-axis of a chart. 278 | 279 | - #### data_font_style 280 | refers to the font style applied to the labels representing the data types on both the x-axis and y-axis of a chart. 281 | 282 | 283 | 284 | 285 | 286 | 287 | ``` python 288 | chart = ctkchart.CTkLineChart( 289 | master=any_widget, 290 | x_axis_values=(2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025), 291 | y_axis_values=(-100, 100), 292 | y_axis_data="Y data" , 293 | x_axis_data="X data", 294 | x_axis_data_font_color="#ff0000", 295 | y_axis_data_font_color="#00ff00", 296 | data_font_style=("arial", 15, "underline") 297 | ) 298 | ``` 299 | 300 | --- 301 | 302 |
    303 | 304 |
    305 | 306 | - #### x_axis_label_count 307 | 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.
    308 | 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.
    309 | **Note: len(x_axis_values) is the default value.**
    310 | 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. 311 |
    312 | - **if there are 9 labels you can limit it to : 3, 1, 0.** 313 | - **if there are 20 labels you can limit it to : 10, 5, 4, 2, 1, 0.** 314 | - **if there are 15 labels you can limit it to : 5, 3, 1, 0.** 315 | 316 | ##### 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. 317 | 318 | - #### y_axis_label_count 319 | 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.
    320 | 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.
    321 | 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. 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | ``` python 330 | chart = ctkchart.CTkLineChart( 331 | master=any_widget, 332 | x_axis_values=(2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025), 333 | y_axis_values=(-100, 100), 334 | x_axis_label_count=4, 335 | y_axis_label_count=10, 336 | ) 337 | ``` 338 | 339 | --- 340 | 341 |
    342 | 343 |
    344 | 345 | - #### x_axis_display_values_indices 346 | 347 | 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.
    348 | 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.
    349 | 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).
    350 | 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. 351 | 352 | 353 | 354 | 355 | 356 | 357 | ``` python 358 | chart = ctkchart.CTkLineChart( 359 | master=any_widget, 360 | x_axis_values=(2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025), 361 | y_axis_values=(-100, 100), 362 | x_axis_display_values_indices=(1, 4, 7) 363 | ) 364 | ``` 365 | 366 | --- 367 | 368 |
    369 | 370 |
    371 | 372 | - #### x_axis_data_position 373 | The x_axis_data_position parameter determines the position of the x data label. It has two 374 | 375 | supported values: 376 | - "top" 377 | - "side" 378 | 379 | **Note: "top" is the default position** 380 | 381 | - #### y_axis_data_position 382 | The y_axis_data_position parameter determines the position of the x data label. It has two 383 | 384 | supported values: 385 | - "top" 386 | - "side" 387 | 388 | **Note: "top" is the default position** 389 | 390 | 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. 391 | 392 | 393 | 394 | 395 | 396 | 397 | ``` python 398 | chart = ctkchart.CTkLineChart( 399 | master=any_widget, 400 | x_axis_values=(2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025), 401 | y_axis_values=(-100, 100), 402 | x_axis_data_position="side", 403 | y_axis_data_position="top" 404 | ) 405 | ``` 406 | 407 | --- 408 | 409 |
    410 | 411 |
    412 | 413 | - #### y_axis_precision 414 | 415 | The y_axis_precision parameter controls the number of decimal places displayed for the values on the y-axis.
    416 | **Note: 1 is the deafault precion**
    417 | For example: 418 | - If you set y_axis_precision to 0, the values on the y-axis will be displayed as whole numbers.
    419 | - If you set y_axis_precision to 1, the values on the y-axis will be displayed with one decimal place.
    420 | - If you set y_axis_precision to 2, the values on the y-axis will be displayed with two decimal places. 421 |
    422 | 423 | And so on : 424 | - **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.** 425 | 426 | 427 | 428 | 429 | 430 | 431 | ``` python 432 | chart = ctkchart.CTkLineChart( 433 | master=any_widget, 434 | x_axis_values=(2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025), 435 | y_axis_values=(-100, 100), 436 | y_axis_label_count=12, 437 | y_axis_precision=4, 438 | ) 439 | ``` 440 | 441 | --- 442 | 443 |
    444 | 445 |
    446 | 447 | - #### axis_font_style 448 | refers to font style of the x and y axis values 449 | 450 | - #### x_axis_font_color 451 | refers to color of x axis values 452 | 453 | - #### y_axis_font_color 454 | refers to color of y axis values 455 | 456 | 457 | 458 | 459 | 460 | 461 | ``` python 462 | chart = ctkchart.CTkLineChart( 463 | master=any_widget, 464 | x_axis_values=(2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025), 465 | y_axis_values=(-100, 100), 466 | x_axis_font_color="#00FF00", 467 | y_axis_font_color="#FF0000", 468 | axis_font_style=("arial", 13, "bold") 469 | ) 470 | ``` 471 | 472 | --- 473 | 474 |
    475 | 476 |
    477 | 478 |
    479 | 480 | - #### x_axis_section_count 481 | 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.
    482 | **Here's a clearer breakdown :** 483 | - 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. 484 | - 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. 485 | - 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. 486 | 487 |
    488 | 489 | - #### y_axis_section_count 490 | 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.
    491 | **refer : x_axis_section_count** for more... 492 | 493 | - #### x_axis_section_color 494 | refers to color of y axis sections 495 | 496 | - #### y_axis_section_color 497 | refers to color of x axis sections 498 | 499 | 500 | 501 | 502 | 503 | 504 | ``` python 505 | chart = ctkchart.CTkLineChart( 506 | master=any_widget, 507 | x_axis_section_count=8, 508 | y_axis_section_count=5, 509 | x_axis_section_color="#2C2C2C", 510 | y_axis_section_color="#2C2C2C" 511 | ) 512 | ``` 513 | 514 | --- 515 | 516 |
    517 | 518 |
    519 | 520 |
    521 | 522 | - #### x_axis_section_style 523 | x_axis_section_style parameter allows you to define the visual style of the sections along the x-axis in a chart. 524 | 525 | - Supported styles: 526 | - "dashed": When you set x_axis_section_style to "dashed", the sections along the x-axis are displayed using dashed lines. 527 | - "normal": Conversely, when x_axis_section_style is set to "normal", the sections along the x-axis are displayed using solid lines.

    528 | 529 | **Note: "normal" is default style.** 530 | 531 |
    532 | 533 | - #### y_axis_section_style 534 | working same as x_axis_section_style, 535 | refer x_axis_section_style for more 536 | 537 |
    538 | 539 | - #### x_axis_section_style_type 540 | 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".
    541 | For example:
    542 | - If you set x_axis_section_style_type to (20, 10), it means : 543 | - The width of each dash is 20 pixels. 544 | - The spacing between dashes is 10 pixels. 545 |
    546 | 547 | 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. 548 | 549 |
    550 | 551 | - #### y_axis_section_style_type 552 | working same as x_axis_section_style_type, 553 | refer x_axis_section_style_type for more 554 | 555 | 556 | 557 | 558 | 559 | 560 | ``` python 561 | chart = ctkchart.CTkLineChart( 562 | master=any_widget, 563 | x_axis_section_count=8, 564 | y_axis_section_count=5, 565 | x_axis_section_style="dashed", 566 | x_axis_section_style_type=(20,10), 567 | y_axis_section_style="dashed", 568 | y_axis_section_style_type=(20,10), 569 | ) 570 | ``` 571 | 572 | --- 573 | 574 |
    575 | 576 |
    577 | 578 | - #### x_axis_point_spacing 579 | 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.
    580 | **Note: "auto" is the default value.** 581 |
    582 | 583 | - after configure specific value to x_axis_point_spacing, you can reset value by configure it as "auto" for set default value. 584 |
    585 | ``` python 586 | chart.configure(x_axis_point_spacing = "auto") 587 | ``` 588 | 589 | 590 | 591 | 592 | 593 | 594 | ``` python 595 | chart = ctkchart.CTkLineChart( 596 | master=any_widget, 597 | x_axis_point_spacing="auto" 598 | ) 599 | ``` 600 | 601 | 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. 602 | 603 | 604 | 605 | 606 | 607 | 608 | 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. 609 | 610 | ``` python 611 | chart = ctkchart.CTkLineChart( 612 | master=any_widget, 613 | x_axis_point_spacing=40 614 | ) 615 | ``` 616 | 617 | --- 618 | 619 |
    620 | 621 | ### CTkLine 622 | 623 |
    624 | 625 | - #### color 626 | refers to color of line. 627 | 628 | - #### size 629 | refers to size(thickness) of line.
    630 | **Note: 1 is the deafault size** 631 |
    632 | 633 | 634 | 635 | 636 | 637 | 638 | ``` python 639 | line = ctkchart.CTkLine( 640 | master=chart, 641 | color="#30ACC7", 642 | size=5 643 | ) 644 | ``` 645 | 646 |
    647 | 648 |
    649 | 650 | - #### style 651 | style parameter allows you to define the visual style of the line. 652 |
    653 | - supported styles: 654 | - "dashed": When you set style to "dashed", the line is displayed as dashed line. 655 | - "dotted": When you set style to "dotted", the line is displayed as dotted line. 656 | - "normal": When you set style to "normal", the line is displayed as solid line. 657 |
    658 | **Note: "normal" is the default style.** 659 | 660 | 661 | 662 | 663 | 664 | 665 | ``` python 666 | line = ctkchart.CTkLine( 667 | master=chart, 668 | line_style="dashed" 669 | ) 670 | ``` 671 | 672 | --- 673 | 674 |
    675 | 676 |
    677 | 678 | - #### style_type 679 | 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". 680 | 681 | For example: 682 | - If you set style_type to (20, 10), it means: 683 | - The width of each dash or size of each dot is 20 pixels. 684 | - The spacing between dashes or dots is 10 pixels. 685 | 686 | **Note: In the "dotted" style, the size parameter is irrelevant as the dots are of fixed size determined by the style_type tuple.**
    687 | **Note: In the "normal" style, the style_type parameter is do nothing.** 688 | 689 | 690 | 691 | 692 | 693 | 694 | ``` python 695 | line = ctkchart.CTkLine( 696 | master=chart, 697 | line_style="dashed", 698 | line_style_type=(10,2) 699 | ) 700 | ``` 701 | 702 | --- 703 | 704 |
    705 | 706 |
    707 | 708 | - #### point_highlight 709 | The point_highlight parameter is used to control point highlight, enabling or disabling it. 710 |
    711 | - Supported values: 712 | - "enabled": Enable point highlight. 713 | - "disabled": Disable point highlight. 714 | 715 | - #### point_highlight_size 716 | The point_highlight_size is used to set size of the highlight. 717 | 718 | - #### point_highlight_color 719 | The point_highlight_color used to control color of highlight. 720 | 721 | 722 | 723 | 724 | 725 | 726 | ``` python 727 | line = ctkchart.CTkLine( 728 | master=chart, 729 | point_highlight="enabled", 730 | point_highlight_color="#80CCFF", 731 | point_highlight_size=8 732 | ) 733 | ``` 734 | 735 | --- 736 | 737 |
    738 | 739 |
    740 | 741 | - #### fill 742 | The fill parameter is utilized to control whether line fill is enabled or disabled. 743 |
    744 | - Supported Values: 745 | - "enabled": Enable line fill. 746 | - "disabled": Disable line fill. 747 | 748 | - #### fill_color 749 | The fill_color parameter is used to specify the color for the fill. 750 | 751 | 752 | 753 | 754 | 755 | 756 | ``` python 757 | line = ctkchart.CTkLine( 758 | master=chart, 759 | fill="enabled", 760 | fill_color="#5D6DB6" 761 | ) 762 | ``` 763 | 764 | --- 765 | 766 |
    767 | 768 |
    769 | 770 |
    771 | 772 | ## Dynamic Color Change 773 | 774 | ***For every parameter that involves color in ctkchart, you can provide either***: 775 | 776 | - A single string representing the color. 777 | - 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. 778 | 779 |
    780 | 781 | --- 782 | 783 |
    784 | 785 | **Back to the Top** | **Usage Guide** | **Parameter Explanation** | **Whats New ?** 786 | 787 | ## [Examples](https://github.com/Thisal-D/ctkchart/tree/main/template(s)) 788 | 789 |
    790 | 791 | 792 | 793 | 794 | 795 | 796 | 797 | 798 | 799 | 800 | 801 | 802 | 803 | 804 | 805 |
    806 | 807 |
    808 | 809 | --- 810 | 811 | ## Links 812 | 813 | **PyPi.org** : ctkchart 814 | 815 | **GitHub.com** : ctkchart --------------------------------------------------------------------------------