├── .gitignore ├── SECURITY.md ├── PULL_REQUEST_TEMPLATE.md ├── .github └── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── template(s) ├── template (1).py ├── template (2).py ├── template (3).py ├── template (7).py ├── template (4).py ├── template (5).py ├── template (8).py └── template (6).py ├── src └── tkchart │ ├── __init__.py │ ├── FontStyle.py │ ├── Utils.py │ ├── Validate.py │ └── Line.py ├── examples ├── 1. Simple.py ├── 2. width height.py ├── 3. data showing.py ├── 4. change colors.py ├── 5. change fonts.py ├── 6. change sections labels.py ├── 7. y axis precision.py ├── 8. y x space.py ├── 9. data position.py ├── 10. change line style.py ├── 12. change section style.py ├── 1000. Complex.py └── 11. pointing values.py ├── setup.py ├── LICENSE ├── CONTRIBUTING.md ├── tests ├── test.py └── main test.py ├── CODE_OF_CONDUCT.md ├── CHANGES_zh.md ├── CHANGES_en.md ├── README_zh.md ├── README.md └── documentation └── DOCUMENTATION_zh.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *.pyd -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /template(s)/template (1).py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | import tkchart 3 | import random 4 | 5 | #root 6 | root = tk.Tk() 7 | root.configure(bg="#151515") 8 | 9 | #creating a chart 10 | chart = tkchart.LineChart(master=root, 11 | x_axis_values = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10), 12 | y_axis_values = (-100,100)) 13 | chart.pack() 14 | 15 | #creating a line 16 | line = tkchart.Line(master=chart) 17 | 18 | data = [x for x in range(-100,100)] 19 | #dipslay data (random) 20 | def loop(): 21 | chart.show_data(line=line, data=random.choices(data, k=1)) 22 | root.after(500, loop) 23 | loop() 24 | 25 | root.mainloop() -------------------------------------------------------------------------------- /.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/tkchart/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | tkchart: A library to create live-update charts for Tkinter GUIs. 3 | """ 4 | 5 | from .LineChart import LineChart 6 | from .Line import Line 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__ = "tkchart" 22 | __version__ = "2.1.8" 23 | __authors__ = ("Thisal Dilmith", "childeyouyu (有语)") 24 | 25 | __all__ = [ 26 | "LineChart", 27 | "Line", 28 | "ENABLED", 29 | "DISABLED", 30 | "NORMAL", 31 | "DASHED", 32 | "DOTTED", 33 | "TOP", 34 | "SIDE", 35 | "AUTO", 36 | ] 37 | -------------------------------------------------------------------------------- /template(s)/template (2).py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | import tkchart 3 | import random 4 | 5 | #root 6 | root = tk.Tk() 7 | root.geometry("700x400+500+300") 8 | 9 | root.configure(bg="#151515") 10 | 11 | #creating a chart 12 | chart = tkchart.LineChart(master=root,y_axis_label_count=4, 13 | x_axis_values = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10), 14 | y_axis_values = (-100,100)) 15 | chart.pack() 16 | 17 | #creating a line 18 | line = tkchart.Line(master=chart, fill="enabled") 19 | 20 | data = [x for x in range(-100,100)] 21 | #dipslay data (random) 22 | def loop(): 23 | chart.show_data(line=line, data=random.choices(data, k=1)) 24 | root.after(500, loop) 25 | loop() 26 | 27 | root.mainloop() -------------------------------------------------------------------------------- /examples/1. Simple.py: -------------------------------------------------------------------------------- 1 | import tkchart 2 | import customtkinter 3 | 4 | root = customtkinter.CTk() 5 | root.geometry("1280x720") 6 | 7 | # values for chart x axis 8 | x_axis_values = ('2020 Year', '2021 Year', '2022 Year', '2023 Year', '2024 Year') 9 | #create line chart 10 | linechart = tkchart.LineChart(master=root, 11 | y_axis_values=(0,1000), 12 | x_axis_values=x_axis_values 13 | ) 14 | #place line chart 15 | linechart.place(x=50, y=50) 16 | 17 | #create line 18 | line = tkchart.Line(master=linechart) 19 | 20 | #display data 21 | display_data = [200, 100, 800, 400, 600, 700] 22 | 23 | #displaying data 24 | linechart.show_data(line=line, data=display_data) 25 | 26 | root.mainloop() -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | 3 | setup( 4 | name='tkchart', # Replace with your package name 5 | version='2.1.8', # Replace with your package version 6 | author='Thisal-D', # Replace with your name 7 | author_email='', # Replace with your email 8 | description='Python library for creating live updating line charts in Tkinter.', 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/tkchart', 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 | include_package_data=True, 21 | ) 22 | -------------------------------------------------------------------------------- /examples/2. width height.py: -------------------------------------------------------------------------------- 1 | import tkchart 2 | import customtkinter 3 | 4 | root = customtkinter.CTk() 5 | root.geometry("1280x720") 6 | 7 | # values for chart x axis 8 | x_axis_values = ('2020 Year', '2021 Year', '2022 Year', '2023 Year', '2024 Year') 9 | #create line chart 10 | linechart = tkchart.LineChart(master=root, 11 | y_axis_values=(0,1000), 12 | x_axis_values=x_axis_values, 13 | 14 | width=1000, height=500, 15 | axis_size=5, 16 | ) 17 | #place line chart 18 | linechart.place(x=50, y=50) 19 | 20 | #create line 21 | line = tkchart.Line(master=linechart, size=2) 22 | 23 | #display data 24 | display_data = [200, 100, 800, 400, 600, 700] 25 | 26 | #displaying data 27 | linechart.show_data(line=line, data=display_data) 28 | 29 | root.mainloop() -------------------------------------------------------------------------------- /template(s)/template (3).py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | import tkchart 3 | import random 4 | 5 | #root 6 | root = tk.Tk() 7 | root.geometry("700x400+500+300") 8 | 9 | root.configure(bg="#151515") 10 | 11 | #creating a chart 12 | chart = tkchart.LineChart(master=root, 13 | x_axis_values = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10), 14 | y_axis_values = (0,100)) 15 | chart.pack() 16 | 17 | #creating a line 18 | line = tkchart.Line(master=chart, 19 | size=3, 20 | style_type=(10,4), 21 | color="#ef8ccb", 22 | style="dashed", 23 | fill="enabled", 24 | fill_color="#b46d9a") 25 | 26 | data = [x for x in range(0,100)] 27 | #dipslay data (random) 28 | def loop(): 29 | chart.show_data(line=line, data=random.choices(data, k=1)) 30 | root.after(500, loop) 31 | loop() 32 | 33 | root.mainloop() -------------------------------------------------------------------------------- /template(s)/template (7).py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | import tkchart 3 | import random 4 | 5 | #root 6 | root = tk.Tk() 7 | root.geometry("700x400+500+300") 8 | root.configure(bg="#151515") 9 | 10 | #creating a chart 11 | chart = tkchart.LineChart(master=root, 12 | x_axis_values = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10), 13 | y_axis_values = (0,100), 14 | ) 15 | chart.pack() 16 | 17 | #creating a line 18 | line1 = tkchart.Line(master=chart, 19 | size=3, 20 | point_highlight="enabled", 21 | point_highlight_size=10, 22 | fill="enabled", 23 | style="normal") 24 | 25 | 26 | 27 | 28 | data = [x for x in range(0,100)] 29 | #dipslay data (random) 30 | def loop(): 31 | chart.show_data(line=line1, data=random.choices(data, k=1)) 32 | 33 | root.after(500, loop) 34 | loop() 35 | 36 | root.mainloop() -------------------------------------------------------------------------------- /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. -------------------------------------------------------------------------------- /examples/3. data showing.py: -------------------------------------------------------------------------------- 1 | import tkchart 2 | import customtkinter 3 | import random 4 | import threading 5 | import time 6 | 7 | root = customtkinter.CTk() 8 | root.geometry("1280x720") 9 | 10 | # values for chart x axis 11 | x_axis_values = ('2020 Year', '2021 Year', '2022 Year', '2023 Year', '2024 Year') 12 | #create line chart 13 | linechart = tkchart.LineChart(master=root, 14 | y_axis_values=(0,1000), 15 | x_axis_values=x_axis_values, 16 | 17 | width=1000, height=500, 18 | axis_size=5, 19 | ) 20 | #place line chart 21 | linechart.place(x=50, y=50) 22 | 23 | #create line 24 | line = tkchart.Line(master=linechart, size=2) 25 | 26 | #display data 27 | data = [100, 200, 300, 400, 500, 600, 700, 800, 900, 1000] 28 | 29 | 30 | 31 | def display_data(): 32 | while True: 33 | #displaying data 34 | linechart.show_data(line=line, data=random.choices(data,k=1)) 35 | time.sleep(0.5) 36 | 37 | threading.Thread(target=display_data).start() 38 | 39 | root.mainloop() -------------------------------------------------------------------------------- /template(s)/template (4).py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | import tkchart 3 | import random 4 | 5 | #root 6 | root = tk.Tk() 7 | root.geometry("700x400+500+300") 8 | 9 | root.configure(bg="#151515") 10 | 11 | #creating a chart 12 | chart = tkchart.LineChart(master=root, 13 | x_axis_values = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10), 14 | y_axis_values = (0,100)) 15 | chart.pack() 16 | 17 | #creating a line 18 | line1 = tkchart.Line(master=chart, 19 | size=3, 20 | color="#ef8ccb", 21 | style="normal", 22 | fill="enabled", 23 | fill_color="#b46d9a") 24 | 25 | line2 = tkchart.Line(master=chart, 26 | style="dashed", 27 | size=3, 28 | style_type=(10,5), 29 | ) 30 | 31 | data = [x for x in range(0,100)] 32 | #dipslay data (random) 33 | def loop(): 34 | chart.show_data(line=line1, data=random.choices(data, k=1)) 35 | chart.show_data(line=line2, data=random.choices(data, k=1)) 36 | root.after(500, loop) 37 | loop() 38 | 39 | root.mainloop() -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to tkchart 2 | 3 | Thank you for considering contributing to tkchart! 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/tkchart.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/tkchart/issues) or start a discussion in the [GitHub Discussions](https://github.com/Thisal-D/tkchart/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 (5).py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | import tkchart 3 | import random 4 | 5 | #root 6 | root = tk.Tk() 7 | root.configure(bg="#151515") 8 | root.geometry("700x400+500+300") 9 | 10 | 11 | #creating a chart 12 | chart = tkchart.LineChart(master=root, 13 | x_axis_values = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10), 14 | y_axis_values = (0,100)) 15 | chart.pack() 16 | 17 | #creating a line 18 | line1 = tkchart.Line(master=chart, 19 | size=3, 20 | color="#ef8ccb", 21 | style="normal", 22 | fill="enabled", 23 | fill_color="#b46d9a") 24 | 25 | line2 = tkchart.Line(master=chart, 26 | style="dashed", 27 | size=3, 28 | style_type=(10,5), 29 | ) 30 | 31 | line3 = tkchart.Line(master=chart, 32 | style="dotted", 33 | style_type=(6,10), 34 | color="#22eb48" 35 | ) 36 | 37 | data = [x for x in range(0,100)] 38 | #dipslay data (random) 39 | def loop(): 40 | chart.show_data(line=line1, data=random.choices(data, k=1)) 41 | chart.show_data(line=line2, data=random.choices(data, k=1)) 42 | chart.show_data(line=line3, data=random.choices(data, k=1)) 43 | 44 | root.after(500, loop) 45 | loop() 46 | 47 | root.mainloop() -------------------------------------------------------------------------------- /examples/4. change colors.py: -------------------------------------------------------------------------------- 1 | import tkchart 2 | import customtkinter 3 | import random 4 | import threading 5 | import time 6 | 7 | root = customtkinter.CTk() 8 | root.geometry("1280x720") 9 | 10 | # values for chart x axis 11 | x_axis_values = ('2020 Year', '2021 Year', '2022 Year', '2023 Year', '2024 Year') 12 | #create line chart 13 | linechart = tkchart.LineChart(master=root, 14 | y_axis_values=(0,1000), 15 | x_axis_values=x_axis_values, 16 | 17 | width=1000, height=500, 18 | axis_size=5, 19 | 20 | 21 | bg_color="#202020", 22 | fg_color="#202020", 23 | 24 | axis_color="#707070", 25 | 26 | x_axis_data_font_color="lightblue", 27 | y_axis_data_font_color="lightblue", 28 | 29 | x_axis_font_color="#707070", 30 | y_axis_font_color="#707070", 31 | 32 | x_axis_section_color="#404040", 33 | y_axis_section_color="#404040" 34 | ) 35 | #place line chart 36 | linechart.place(x=50, y=50) 37 | 38 | #create line 39 | line = tkchart.Line(master=linechart, size=2, color="lightblue") 40 | 41 | #display data 42 | data = [100, 200, 300, 400, 500, 600, 700, 800, 900, 1000] 43 | 44 | 45 | 46 | def display_data(): 47 | while True: 48 | #displaying data 49 | linechart.show_data(line=line, data=random.choices(data,k=1)) 50 | time.sleep(0.5) 51 | 52 | threading.Thread(target=display_data).start() 53 | 54 | root.mainloop() -------------------------------------------------------------------------------- /template(s)/template (8).py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | import tkchart 3 | import random 4 | 5 | #root 6 | root = tk.Tk() 7 | root.geometry("700x400+500+300") 8 | root.configure(bg="#151515") 9 | 10 | #creating a chart 11 | chart = tkchart.LineChart(master=root, 12 | width=1700, 13 | height=800, 14 | axis_size=5, 15 | x_axis_values = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10), 16 | y_axis_values = (-1000,1000), 17 | y_axis_label_count=10, 18 | x_axis_section_count=10, 19 | y_axis_section_count=10, 20 | x_axis_section_color="#555555", 21 | y_axis_section_color="#555555", 22 | data_font_style=("arial", 15, "bold"), 23 | axis_font_style=("arial", 11, "bold"), 24 | x_axis_font_color="#efefef", 25 | y_axis_font_color="#efefef", 26 | axis_color="#909090", 27 | x_axis_data_font_color="#efefef", 28 | y_axis_data_font_color="#efefef", 29 | y_space=20, 30 | x_space=20, 31 | ) 32 | chart.pack(pady=20) 33 | 34 | #creating a line 35 | line1 = tkchart.Line(master=chart, 36 | size=3, 37 | style="normal", 38 | fill_color="#5d6db6", 39 | fill="enabled", 40 | point_highlight="enabled", 41 | point_highlight_size=15, 42 | ) 43 | 44 | 45 | 46 | 47 | data = [x for x in range(-1000,1000)] 48 | #dipslay data (random) 49 | def loop(): 50 | chart.show_data(line=line1, data=random.choices(data, k=1)) 51 | 52 | root.after(500, loop) 53 | loop() 54 | 55 | root.mainloop() -------------------------------------------------------------------------------- /template(s)/template (6).py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | import tkchart 3 | import random 4 | 5 | #root 6 | root = tk.Tk() 7 | root.geometry("700x400+500+300") 8 | root.configure(bg="#151515") 9 | 10 | #creating a chart 11 | chart = tkchart.LineChart(master=root, 12 | x_axis_values = ("100\nS", "200\nS", "300\nS", "400\nS", "500\nS", "600\nS", "700\nS", "800\nS", "900\nS"), 13 | y_axis_values = (0,100), 14 | y_axis_label_count=10, 15 | x_axis_section_count=10, 16 | y_axis_section_count=10, 17 | x_axis_section_color="#5d6db6", 18 | y_axis_section_color="#5d6db6", 19 | data_font_style=("arial", 10, "bold"), 20 | axis_font_style=("arial", 9, "italic"), 21 | x_axis_font_color="#efefef", 22 | y_axis_font_color="#efefef", 23 | axis_color="#5d6db6", 24 | x_axis_data_font_color="#efefef", 25 | y_axis_data_font_color="#efefef", 26 | y_space=20, 27 | x_space=20, 28 | x_axis_data="Seconds\n(s)", 29 | x_axis_data_position="side", 30 | y_axis_data_position="top", 31 | 32 | 33 | ) 34 | chart.pack() 35 | 36 | #creating a line 37 | line1 = tkchart.Line(master=chart, 38 | size=3, 39 | style="normal", 40 | fill_color="#5d6db6", 41 | fill="enabled") 42 | 43 | 44 | 45 | 46 | data = [x for x in range(0,100)] 47 | #dipslay data (random) 48 | def loop(): 49 | chart.show_data(line=line1, data=random.choices(data, k=1)) 50 | 51 | root.after(500, loop) 52 | loop() 53 | 54 | root.mainloop() -------------------------------------------------------------------------------- /examples/5. change fonts.py: -------------------------------------------------------------------------------- 1 | import tkchart 2 | import customtkinter 3 | import random 4 | import threading 5 | import time 6 | 7 | root = customtkinter.CTk() 8 | root.geometry("1280x720") 9 | 10 | # values for chart x axis 11 | x_axis_values = ('2020 Year', '2021 Year', '2022 Year', '2023 Year', '2024 Year') 12 | #create line chat 13 | linechart = tkchart.LineChart(master=root, 14 | y_axis_values=(0 ,1000), 15 | x_axis_values=x_axis_values, 16 | 17 | width=1000, height=500, 18 | axis_size=5, 19 | 20 | 21 | bg_color="#202020", 22 | fg_color="#202020", 23 | 24 | axis_color="#707070", 25 | 26 | x_axis_data_font_color="lightblue", 27 | y_axis_data_font_color="lightblue", 28 | 29 | x_axis_font_color="#707070", 30 | y_axis_font_color="#707070", 31 | 32 | x_axis_section_color="#404040", 33 | y_axis_section_color="#404040", 34 | 35 | data_font_style=("arial","20","bold"), 36 | axis_font_style=("arial","11","bold"), 37 | 38 | 39 | ) 40 | #place line chart 41 | linechart.place(x=50, y=50) 42 | 43 | #create line 44 | line = tkchart.Line(master=linechart, size=2, color="lightblue") 45 | 46 | #display data 47 | data = [100, 200, 300, 400, 500, 600, 700, 800, 900, 1000] 48 | 49 | 50 | 51 | def display_data(): 52 | while True: 53 | #displaying data 54 | linechart.show_data(line=line, data=random.choices(data,k=1)) 55 | time.sleep(0.5) 56 | 57 | threading.Thread(target=display_data).start() 58 | 59 | root.mainloop() -------------------------------------------------------------------------------- /examples/6. change sections labels.py: -------------------------------------------------------------------------------- 1 | import tkchart 2 | import customtkinter 3 | import random 4 | import threading 5 | import time 6 | 7 | root = customtkinter.CTk() 8 | root.geometry("1280x720") 9 | 10 | # values for chart x axis 11 | x_axis_values = ('2020 Year', '2021 Year', '2022 Year', '2023 Year', '2024 Year') 12 | #create line chart 13 | linechart = tkchart.LineChart(master=root, 14 | y_axis_values=(0 ,1000), 15 | x_axis_values=x_axis_values, 16 | 17 | width=1000, height=500, 18 | axis_size=5, 19 | 20 | 21 | bg_color="#202020", 22 | fg_color="#202020", 23 | 24 | axis_color="#707070", 25 | 26 | x_axis_data_font_color="lightblue", 27 | y_axis_data_font_color="lightblue", 28 | 29 | x_axis_font_color="#707070", 30 | y_axis_font_color="#707070", 31 | 32 | x_axis_section_color="#404040", 33 | y_axis_section_color="#404040", 34 | 35 | data_font_style=("arial","20","bold"), 36 | axis_font_style=("arial","11","bold"), 37 | 38 | x_axis_section_count=10, 39 | y_axis_section_count=10, 40 | 41 | y_axis_label_count=15, 42 | ) 43 | #place line chart 44 | linechart.place(x=50, y=50) 45 | 46 | #create line 47 | line = tkchart.Line(master=linechart, size=2, color="lightblue") 48 | 49 | #display data 50 | data = [100, 200, 300, 400, 500, 600, 700, 800, 900, 1000] 51 | 52 | 53 | 54 | def display_data(): 55 | while True: 56 | #displaying data 57 | linechart.show_data(line=line, data=random.choices(data,k=1)) 58 | time.sleep(0.5) 59 | 60 | threading.Thread(target=display_data).start() 61 | 62 | root.mainloop() -------------------------------------------------------------------------------- /examples/7. y axis precision.py: -------------------------------------------------------------------------------- 1 | import tkchart 2 | import customtkinter 3 | import random 4 | import threading 5 | import time 6 | 7 | root = customtkinter.CTk() 8 | root.geometry("1280x720") 9 | 10 | # values for chart x axis 11 | x_axis_values = ('2020 Year', '2021 Year', '2022 Year', '2023 Year', '2024 Year') 12 | #create line chart 13 | linechart = tkchart.LineChart(master=root, 14 | y_axis_values=(0, 1000), 15 | x_axis_values=x_axis_values, 16 | 17 | width=1000, height=500, 18 | axis_size=5, 19 | 20 | 21 | bg_color="#202020", 22 | fg_color="#202020", 23 | 24 | axis_color="#707070", 25 | 26 | x_axis_data_font_color="lightblue", 27 | y_axis_data_font_color="lightblue", 28 | 29 | x_axis_font_color="#707070", 30 | y_axis_font_color="#707070", 31 | 32 | x_axis_section_color="#404040", 33 | y_axis_section_color="#404040", 34 | 35 | data_font_style=("arial","20","bold"), 36 | axis_font_style=("arial","11","bold"), 37 | 38 | x_axis_section_count=10, 39 | y_axis_section_count=10, 40 | 41 | y_axis_label_count=15, 42 | 43 | y_axis_precision=3, 44 | 45 | ) 46 | #place line chart 47 | linechart.place(x=50, y=50) 48 | 49 | #create line 50 | line = tkchart.Line(master=linechart, size=2, color="lightblue") 51 | 52 | #display data 53 | data = [100, 200, 300, 400, 500, 600, 700, 800, 900, 1000] 54 | 55 | 56 | def display_data(): 57 | while True: 58 | #displaying data 59 | linechart.show_data(line=line, data=random.choices(data,k=1)) 60 | time.sleep(0.5) 61 | 62 | threading.Thread(target=display_data).start() 63 | 64 | root.mainloop() -------------------------------------------------------------------------------- /src/tkchart/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 | -------------------------------------------------------------------------------- /examples/8. y x space.py: -------------------------------------------------------------------------------- 1 | import tkchart 2 | import customtkinter 3 | import random 4 | import threading 5 | import time 6 | 7 | root = customtkinter.CTk() 8 | root.geometry("1280x720") 9 | 10 | # values for chart x axis 11 | x_axis_values = ('2020 Year', '2021 Year', '2022 Year', '2023 Year', '2024 Year') 12 | #create line chart 13 | linechart = tkchart.LineChart(master=root, 14 | y_axis_values=(0, 1000), 15 | x_axis_values=x_axis_values, 16 | 17 | width=1000, height=500, 18 | axis_size=5, 19 | 20 | 21 | bg_color="#202020", 22 | fg_color="#202020", 23 | 24 | axis_color="#707070", 25 | 26 | x_axis_data_font_color="lightblue", 27 | y_axis_data_font_color="lightblue", 28 | 29 | x_axis_font_color="#707070", 30 | y_axis_font_color="#707070", 31 | 32 | x_axis_section_color="#404040", 33 | y_axis_section_color="#404040", 34 | 35 | data_font_style=("arial","20","bold"), 36 | axis_font_style=("arial","11","bold"), 37 | 38 | x_axis_section_count=10, 39 | y_axis_section_count=10, 40 | 41 | y_axis_label_count=15, 42 | 43 | y_axis_precision=3, 44 | 45 | y_space=20, 46 | x_space=20 47 | 48 | ) 49 | #place line chart 50 | linechart.place(x=50, y=50) 51 | 52 | #create line 53 | line = tkchart.Line(master=linechart, size=2, color="lightblue") 54 | 55 | #display data 56 | data = [100, 200, 300, 400, 500, 600, 700, 800, 900, 1000] 57 | 58 | 59 | def display_data(): 60 | while True: 61 | #displaying data 62 | linechart.show_data(line=line, data=random.choices(data,k=1)) 63 | time.sleep(0.5) 64 | 65 | threading.Thread(target=display_data).start() 66 | 67 | root.mainloop() -------------------------------------------------------------------------------- /examples/9. data position.py: -------------------------------------------------------------------------------- 1 | import tkchart 2 | import customtkinter 3 | import random 4 | import threading 5 | import time 6 | 7 | root = customtkinter.CTk() 8 | root.geometry("1280x720") 9 | 10 | # values for chat x axis 11 | x_axis_values = ('2020 Year', '2021 Year', '2022 Year', '2023 Year', '2024 Year') 12 | #create line chart 13 | linechart = tkchart.LineChart(master=root, 14 | y_axis_values=(0, 1000), 15 | x_axis_values=x_axis_values, 16 | 17 | width=1000, height=500, 18 | axis_size=5, 19 | 20 | 21 | bg_color="#202020", 22 | fg_color="#202020", 23 | 24 | axis_color="#707070", 25 | 26 | x_axis_data_font_color="lightblue", 27 | y_axis_data_font_color="lightblue", 28 | 29 | x_axis_font_color="#707070", 30 | y_axis_font_color="#707070", 31 | 32 | x_axis_section_color="#404040", 33 | y_axis_section_color="#404040", 34 | 35 | data_font_style=("arial","20","bold"), 36 | axis_font_style=("arial","11","bold"), 37 | 38 | x_axis_section_count=10, 39 | y_axis_section_count=10, 40 | 41 | y_axis_label_count=15, 42 | 43 | y_axis_precision=3, 44 | 45 | y_space=20, 46 | x_space=20, 47 | 48 | x_axis_data_position="side", 49 | y_axis_data_position="side" 50 | 51 | ) 52 | #place line chart 53 | linechart.place(x=50, y=50) 54 | 55 | #create line 56 | line = tkchart.Line(master=linechart, size=2, color="lightblue") 57 | 58 | #display data 59 | data = [100, 200, 300, 400, 500, 600, 700, 800, 900, 1000] 60 | 61 | 62 | def display_data(): 63 | while True: 64 | #displaying data 65 | linechart.show_data(line=line, data=random.choices(data,k=1)) 66 | time.sleep(0.5) 67 | 68 | threading.Thread(target=display_data).start() 69 | 70 | root.mainloop() -------------------------------------------------------------------------------- /examples/10. change line style.py: -------------------------------------------------------------------------------- 1 | import tkchart 2 | import customtkinter 3 | import random 4 | import threading 5 | import time 6 | 7 | root = customtkinter.CTk() 8 | root.geometry("1280x720") 9 | 10 | # values for chart x axis 11 | x_axis_values = ('2020 Year', '2021 Year', '2022 Year', '2023 Year', '2024 Year') 12 | #create line chart 13 | linechart = tkchart.LineChart(master=root, 14 | y_axis_values=(0, 1000), 15 | x_axis_values=x_axis_values, 16 | 17 | width=1000, height=500, 18 | axis_size=5, 19 | 20 | 21 | bg_color="#202020", 22 | fg_color="#202020", 23 | 24 | axis_color="#707070", 25 | 26 | x_axis_data_font_color="lightblue", 27 | y_axis_data_font_color="lightblue", 28 | 29 | x_axis_font_color="#707070", 30 | y_axis_font_color="#707070", 31 | 32 | x_axis_section_color="#404040", 33 | y_axis_section_color="#404040", 34 | 35 | data_font_style=("arial","20","bold"), 36 | axis_font_style=("arial","11","bold"), 37 | 38 | x_axis_section_count=10, 39 | y_axis_section_count=10, 40 | 41 | y_axis_label_count=15, 42 | 43 | y_axis_precision=3, 44 | 45 | y_space=20, 46 | x_space=20, 47 | 48 | x_axis_data_position="side", 49 | y_axis_data_position="side" 50 | ) 51 | #place line chart 52 | linechart.place(x=50, y=50) 53 | 54 | #create line 55 | line = tkchart.Line(master=linechart, size=2, color="lightblue" ,style="dashed", style_type=(10,10)) 56 | 57 | #display data 58 | data = [100, 200, 300, 400, 500, 600, 700, 800, 900, 1000] 59 | 60 | 61 | def display_data(): 62 | while True: 63 | #displaying data 64 | linechart.show_data(line=line, data=random.choices(data,k=1)) 65 | time.sleep(0.5) 66 | 67 | threading.Thread(target=display_data).start() 68 | 69 | root.mainloop() -------------------------------------------------------------------------------- /tests/test.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | import customtkinter as ctk 4 | 5 | import tkchart 6 | 7 | root = ctk.CTk() 8 | 9 | charts: list[tkchart.LineChart] = [] 10 | lines: list[tkchart.Line] = [] 11 | 12 | line_chart = tkchart.LineChart( 13 | master=root, 14 | x_axis_values=(1, 2, 3, 4, 5, 6, 7, 8, 9, 10), 15 | y_axis_values=(0, 100), 16 | y_axis_label_count=10, 17 | width=500, height=200, 18 | axis_color="red", axis_size=10) 19 | line_chart.pack() 20 | 21 | line = tkchart.Line(master=line_chart, color="red") 22 | line2 = tkchart.Line(master=line_chart, color="blue") 23 | line_destroyed = False 24 | line2_destroyed = False 25 | 26 | 27 | def loop(): 28 | global line2_destroyed, line_destroyed 29 | if not line_destroyed: 30 | line_chart.show_data(line=line, data=[random.choice(range(0, 101))]) 31 | if not line2_destroyed: 32 | line_chart.show_data(line=line2, data=[random.choice(range(0, 101))]) 33 | 34 | root.after(1000, loop) 35 | 36 | 37 | loop() 38 | 39 | line_chart2 = tkchart.LineChart( 40 | master=root, 41 | x_axis_values=(1, 2, 3, 4, 5, 6, 7, 8, 9, 10), 42 | y_axis_values=(0, 100), 43 | y_axis_label_count=10, 44 | width=500, height=200, 45 | axis_color="red", axis_size=10) 46 | line_chart2.pack() 47 | 48 | def hide(line: tkchart.Line): 49 | line.set_visible(False) 50 | 51 | 52 | def show(line: tkchart.Line): 53 | line.set_visible(True) 54 | 55 | 56 | def destroy1(): 57 | global line_destroyed 58 | line_destroyed = True 59 | line.destroy() 60 | 61 | 62 | def destroy2(): 63 | global line2_destroyed 64 | line2_destroyed = True 65 | line2.destroy() 66 | 67 | def hide_all(): 68 | line_chart.set_lines_visibility(False) 69 | 70 | 71 | def show_all(): 72 | line_chart.set_lines_visibility(True) 73 | 74 | def destroy_chart(): 75 | line_chart.destroy() 76 | 77 | def destroy_chart2(): 78 | line_chart2.destroy() 79 | 80 | def reset_chart(): 81 | line_chart.reset() 82 | 83 | ctk.CTkButton(master=root, text="hide line1", command=lambda: hide(line)).pack() 84 | ctk.CTkButton(master=root, text="hide line2", command=lambda: hide(line2)).pack() 85 | ctk.CTkButton(master=root, text="show line1", command=lambda: show(line)).pack() 86 | ctk.CTkButton(master=root, text="show line2", command=lambda: show(line2)).pack() 87 | ctk.CTkButton(master=root, text="show lines", command=show_all).pack() 88 | ctk.CTkButton(master=root, text="hide lines", command=hide_all).pack() 89 | 90 | ctk.CTkButton(master=root, text="destroy line1", command=destroy1).pack() 91 | ctk.CTkButton(master=root, text="destroy line2", command=destroy2).pack() 92 | ctk.CTkButton(master=root, text="destroy chart", command=destroy_chart).pack() 93 | ctk.CTkButton(master=root, text="destroy chart2", command=destroy_chart2).pack() 94 | ctk.CTkButton(master=root, text="reset chart", command=reset_chart).pack() 95 | 96 | 97 | root.mainloop() 98 | -------------------------------------------------------------------------------- /examples/12. change section style.py: -------------------------------------------------------------------------------- 1 | import tkchart 2 | import customtkinter 3 | import random 4 | import threading 5 | import time 6 | 7 | root = customtkinter.CTk() 8 | root.geometry("1280x720") 9 | 10 | # values for chart x axis 11 | x_axis_values = ('2020 Year', '2021 Year', '2022 Year', '2023 Year', '2024 Year') 12 | #create line chart 13 | linechart = tkchart.LineChart(master=root, 14 | y_axis_values=(0, 1000), 15 | x_axis_values=x_axis_values, 16 | 17 | width=1000, height=500, 18 | axis_size=5, 19 | 20 | bg_color="#202020", 21 | fg_color="#202020", 22 | 23 | axis_color="#707070", 24 | 25 | x_axis_data_font_color="lightblue", 26 | y_axis_data_font_color="lightblue", 27 | 28 | x_axis_font_color="#707070", 29 | y_axis_font_color="#707070", 30 | 31 | x_axis_section_color="#404040", 32 | y_axis_section_color="#404040", 33 | 34 | data_font_style=("arial","20","bold"), 35 | axis_font_style=("arial","11","bold"), 36 | 37 | x_axis_section_count=10, 38 | y_axis_section_count=10, 39 | 40 | y_axis_label_count=15, 41 | 42 | y_axis_precision=3, 43 | 44 | y_space=20, 45 | x_space=20, 46 | 47 | x_axis_data_position="side", 48 | y_axis_data_position="side", 49 | 50 | x_axis_section_style="dashed", 51 | y_axis_section_style="dashed", 52 | 53 | x_axis_section_style_type=(20,10), 54 | y_axis_section_style_type=(20,10), 55 | 56 | ) 57 | #place line chart 58 | linechart.place(x=50, y=50) 59 | 60 | #create line 61 | line = tkchart.Line(master=linechart, size=2, color="lightblue" ,style="dashed", style_type=(10,10)) 62 | 63 | #display data 64 | data = [100, 200, 300, 400, 500, 600, 700, 800, 900, 1000] 65 | 66 | 67 | def display_data(): 68 | while True: 69 | #displaying data 70 | linechart.show_data(line=line, data=random.choices(data,k=1)) 71 | time.sleep(0.5) 72 | 73 | threading.Thread(target=display_data).start() 74 | 75 | root.mainloop() -------------------------------------------------------------------------------- /examples/1000. Complex.py: -------------------------------------------------------------------------------- 1 | import tkchart 2 | import customtkinter 3 | import random 4 | import threading 5 | import time 6 | 7 | root = customtkinter.CTk() 8 | root.geometry("1280x720") 9 | 10 | 11 | # values for chart x axis 12 | x_axis_values = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10) 13 | #create line chart 14 | linechart = tkchart.LineChart(master=root, 15 | y_axis_values=(0,1000), 16 | x_axis_values=x_axis_values, 17 | 18 | width=1000, height=500, 19 | axis_size=5, 20 | 21 | 22 | bg_color="#202020", 23 | fg_color="#202020", 24 | 25 | axis_color="#707070", 26 | 27 | x_axis_data_font_color="lightblue", 28 | y_axis_data_font_color="lightblue", 29 | 30 | x_axis_font_color="#707070", 31 | y_axis_font_color="#707070", 32 | 33 | x_axis_section_color="#404040", 34 | y_axis_section_color="#404040", 35 | 36 | data_font_style=("arial","20","bold"), 37 | axis_font_style=("arial","11","bold"), 38 | 39 | x_axis_section_count=10, 40 | y_axis_section_count=10, 41 | x_axis_label_count=5, 42 | y_axis_label_count=15, 43 | 44 | y_axis_precision=3, 45 | 46 | y_space=20, 47 | x_space=20, 48 | 49 | x_axis_data_position="side", 50 | y_axis_data_position="side" 51 | ) 52 | #place line chart 53 | linechart.place(x=50, y=50) 54 | 55 | #create line 56 | line1 = tkchart.Line(master=linechart, size=2, color="lightblue") 57 | line2 = tkchart.Line(master=linechart, size=2, color="lightgreen" ,style="dashed", style_type=(5,7)) 58 | line3 = tkchart.Line(master=linechart, size=2, color="pink" ,style="dotted", style_type=(4,7)) 59 | #display data 60 | data = [100, 200, 300, 400, 500, 600, 700, 800, 900, 1000] 61 | 62 | 63 | 64 | count = 0 65 | 66 | def display_data(): 67 | while True: 68 | global x_axis_values , count 69 | 70 | #displaying data 71 | linechart.show_data(line=line1, data=random.choices(data,k=1)) 72 | linechart.show_data(line=line2, data=random.choices(data,k=1)) 73 | linechart.show_data(line=line3, data=random.choices(data,k=1)) 74 | if count > len(x_axis_values): 75 | x_axis_values = tuple([(x+1) for x in x_axis_values]) 76 | linechart.configure(x_axis_values=x_axis_values) 77 | count += 1 78 | 79 | time.sleep(0.5) 80 | 81 | threading.Thread(target=display_data).start() 82 | 83 | root.mainloop() -------------------------------------------------------------------------------- /src/tkchart/Utils.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | from typing import Union, Tuple, Any, List 3 | 4 | 5 | class Utils: 6 | 7 | @staticmethod 8 | def _required_width(text: Any, font: Tuple[str, int, str]) -> int: 9 | """ 10 | Get the required width of a label to display the given text with the specified font. 11 | 12 | Args: 13 | text (Any): Text to measure. 14 | font (Tuple[str, int, str]): Font specification (family, size, style). 15 | 16 | Returns: 17 | int: Required label width in pixels. 18 | """ 19 | label = tk.Label(font=font) 20 | label.config(text=str(text)) 21 | return label.winfo_reqwidth() 22 | 23 | @staticmethod 24 | def _required_height(text: Any, font: Tuple[str, int, str]) -> int: 25 | """ 26 | Get the required height of a label to display the given text with the specified font. 27 | 28 | Args: 29 | text (Any): Text to measure. 30 | font (Tuple[str, int, str]): Font specification (family, size, style). 31 | 32 | Returns: 33 | int: Required label height in pixels. 34 | """ 35 | label = tk.Label(font=font) 36 | label.config(text=str(text)) 37 | return label.winfo_reqheight() 38 | 39 | @staticmethod 40 | def _format_float_with_precision(float_val: Union[int, float], decimals: int) -> str: 41 | """ 42 | Format a float or int value as a string with a specified number of decimal places. 43 | 44 | Args: 45 | float_val (int | float): Number to format. 46 | decimals (int): Number of decimal places. 47 | 48 | Returns: 49 | str: Number formatted as a string with exact decimals. 50 | """ 51 | if decimals > 0: 52 | rounded = round(float(float_val), decimals) 53 | integer_part, dot, fraction_part = str(rounded).partition(".") 54 | fraction_part = fraction_part.ljust(decimals, "0") 55 | return f"{integer_part}.{fraction_part}" 56 | return str(int(float_val)) 57 | 58 | @staticmethod 59 | def _get_max_required_label_width(data: List[Any], font: Tuple[str, int, str]) -> int: 60 | """ 61 | Calculate the maximum label width needed to display all data items with given font. 62 | 63 | Args: 64 | data (List[Any]): List of data items to measure. 65 | font (Tuple[str, int, str]): Font specification. 66 | 67 | Returns: 68 | int: Maximum required label width in pixels. 69 | """ 70 | return max(Utils._required_width(text=d, font=font) for d in data) 71 | 72 | @staticmethod 73 | def _get_max_required_label_height(data: List[Any], font: Tuple[str, int, str]) -> int: 74 | """ 75 | Calculate the maximum label height needed to display all data items with given font. 76 | 77 | Args: 78 | data (List[Any]): List of data items to measure. 79 | font (Tuple[str, int, str]): Font specification. 80 | 81 | Returns: 82 | int: Maximum required label height in pixels. 83 | """ 84 | return max(Utils._required_height(text=d, font=font) for d in data) 85 | 86 | @staticmethod 87 | def _sort_tuple(values: Tuple[int, ...]) -> Tuple[int, ...]: 88 | """ 89 | Sort a tuple of integers and remove duplicates. 90 | 91 | Args: 92 | values (Tuple[int, ...]): Tuple of integers. 93 | 94 | Returns: 95 | Tuple[int, ...]: Sorted tuple with unique integers. 96 | """ 97 | return tuple(sorted(set(values))) 98 | 99 | @staticmethod 100 | def _to_int(value: Union[int, str]) -> int: 101 | """ 102 | Convert a string or integer to an integer. 103 | 104 | Args: 105 | value (Union[int, str]): Value to convert. 106 | 107 | Returns: 108 | int: Converted integer. 109 | """ 110 | return int(value) 111 | -------------------------------------------------------------------------------- /examples/11. pointing values.py: -------------------------------------------------------------------------------- 1 | import tkchart 2 | import customtkinter 3 | import random 4 | 5 | root = customtkinter.CTk() 6 | 7 | root.geometry("1048x599+442+239") 8 | 9 | 10 | def func(x, y): 11 | label.configure(text=y[0]) 12 | label2.configure(text=y[1]) 13 | label3.configure(text=y[2]) 14 | label4.configure(text=y[3]) 15 | 16 | 17 | linechart = tkchart.LineChart(master=root, 18 | width=1500, 19 | height=700, 20 | axis_size=5, 21 | 22 | y_axis_section_count=10, 23 | x_axis_section_count=0, 24 | y_axis_label_count=10, 25 | 26 | y_axis_data="GB", 27 | x_axis_data="S", 28 | x_axis_values=tuple([x for x in range(1,11,1)]), 29 | x_axis_label_count=10, 30 | y_axis_values=(0,1000), 31 | y_axis_precision=4, 32 | 33 | x_axis_section_color="#404040", 34 | y_axis_section_color="#404040", 35 | y_axis_font_color="#707070", 36 | x_axis_font_color="#707070", 37 | x_axis_data_font_color="lightblue", 38 | y_axis_data_font_color="lightblue", 39 | bg_color="#202020", 40 | fg_color="#202020", 41 | axis_color="#707070", 42 | 43 | data_font_style= ("Arial", 15,"bold"), 44 | axis_font_style= ("Arial", 10,"bold"), 45 | 46 | pointing_callback_function = func, 47 | pointer_color="#00ffff", 48 | pointer_state="enabled", 49 | pointing_values_precision=4 50 | ) 51 | 52 | linechart.place(x=100, y=10) 53 | 54 | 55 | line = tkchart.Line(master=linechart, 56 | color="#ff0000", 57 | size=1, 58 | style="normal", 59 | style_type=(4,10), 60 | ) 61 | 62 | line2 = tkchart.Line(master=linechart, 63 | color="#00ff00", 64 | size=1, 65 | style="normal", 66 | style_type=(4,10)) 67 | 68 | line3 = tkchart.Line(master=linechart, 69 | color="#0000ff", 70 | size=1, 71 | style="normal", 72 | style_type=(4,10)) 73 | 74 | line4 = tkchart.Line(master=linechart, 75 | color="#ffff00", 76 | size=1, 77 | style="normal", 78 | style_type=(4,10)) 79 | 80 | frame = customtkinter.CTkFrame(master=root, width=30, height=30, fg_color="#ff0000") 81 | frame.place(x=1650, y=300) 82 | label = customtkinter.CTkLabel(master=root, font=("arial",13, "bold"), text="") 83 | label.place(x=1700, y=300) 84 | 85 | frame2 = customtkinter.CTkFrame(master=root, width=30, height=30, fg_color="#00ff00") 86 | frame2.place(x=1650, y=350) 87 | label2 = customtkinter.CTkLabel(master=root, font=("arial",13, "bold"), text="") 88 | label2.place(x=1700, y=350) 89 | 90 | frame3 = customtkinter.CTkFrame(master=root, width=30, height=30, fg_color="#0000ff") 91 | frame3.place(x=1650, y=400) 92 | label3 = customtkinter.CTkLabel(master=root, font=("arial",13, "bold"), text="") 93 | label3.place(x=1700, y=400) 94 | 95 | frame4 = customtkinter.CTkFrame(master=root, width=30, height=30, fg_color="#ffff00") 96 | frame4.place(x=1650, y=450) 97 | label4 = customtkinter.CTkLabel(master=root, font=("arial",13, "bold"), text="") 98 | label4.place(x=1700, y=450) 99 | 100 | 101 | data = [0,100,200,300,400,500,600,700,800,900,1000] 102 | def loop2(): 103 | if start: 104 | linechart.show_data(data=[random.choice(data)], line=line) 105 | linechart.show_data(data=[random.choice(data)], line=line2) 106 | linechart.show_data(data=[random.choice(data)], line=line3) 107 | linechart.show_data(data=[random.choice(data)], line=line4) 108 | root.after(1000,loop2) 109 | 110 | start = True 111 | def stop_start(): 112 | global start 113 | if start: 114 | start= False 115 | else: 116 | start= True 117 | #calling to loop 118 | btn = customtkinter.CTkButton(master=root, text="Stop/Start", command=stop_start) 119 | btn.place(x=1700,y=600) 120 | 121 | loop2() 122 | root.mainloop() -------------------------------------------------------------------------------- /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.6 4 | 5 | - ### 新方法添加到 `LineChart` 对象 6 | | 方法名 | 描述 | 参数 | 返回类型 | 7 | |------------------------------|------------------------------------------------------------|------------------------------------------|-----------------| 8 | | `get_lines_data` | 获取指定范围内所有线条的数据点,可以选择步长值。 | start: `int`
end: `int`
step: `int` | `Dict[tkchart.Line, Tuple[int]]` | 9 | | `get_line_data` | 获取指定范围和步长值下某一条线的数据点。 | line: `tkchart.Line`
start: `int`
end: `int`
step: `int` | `Tuple[int \| float]` | 10 | | `get_x_axis_visible_point_count` | 获取X轴上可见数据点的最大数量。 | - | `int` | 11 | | `get_lines_visible_data` | 获取所有线条当前可见的数据点,基于最大数据长度和可见点数。 | - | `Dict[tkchart.Line, Tuple[int \| float]]` | 12 | | `get_line_visible_data` | 获取某一条线当前可见的数据点。 | line: `tkchart.Line` | `Tuple[int \| float]` | 13 | 14 | - ### 新方法添加到 `Line` 对象 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 | - ### 新增方法到 `LineChart` 对象 25 | | 方法名称 | 描述 | 参数 | 返回类型 | 26 | |------------------|------------------------------------------------------------|----------------|-------------| 27 | | `clear_data` | 清除图表中所有线的数据,确保只保留最新的可见数据点。如果数据点总数超过最大可见点,则会从每条线的数据中移除旧数据。此方法确保图表仅显示基于最大可见范围的相关数据部分。 | - | `None` | 28 | 29 | - ### 新增方法到 `Line` 对象 30 | | 方法名称 | 描述 | 参数 | 返回类型 | 31 | |------------------|------------------------------------------------------------|----------------|-------------| 32 | | `clear_data` | 清除特定线的数据,确保只保留最新的可见数据点。如果线的数据超过最大可见点,则会修剪旧数据。此方法允许每条线独立清除其数据,确保它始终保持在可见范围内。 | - | `None` | 33 | 34 | --- 35 | 36 | ## v2.1.4 37 | 38 | - ### 新增方法到 `LineChart` 对象 39 | | 方法名称 | 描述 | 参数 | 返回类型 | 40 | |------------------|------------------------------------------------------------|----------------|-------------| 41 | | `get_line_area` | 获取特定线的区域大小 | line: `tkchart.Line` | `float` | 42 | | `get_lines_area` | 获取所有线的区域大小 | - | `float` | 43 | 44 | --- 45 | 46 | ## v2.1.3 47 | 48 | - ### 新增方法到 `LineChart` 对象 49 | | 方法名称 | 描述 | 参数 | 返回类型 | 50 | |------------------|------------------------------------------------------------|----------------|-------------| 51 | | `destroy` | 销毁线图及其所有线 | - | `None` | 52 | 53 | - ### 新增方法到 `Line` 对象 54 | | 方法名称 | 描述 | 参数 | 返回类型 | 55 | |------------------|------------------------------------------------------------|----------------|-------------| 56 | | `destroy` | 销毁线对象 | - | `None` | 57 | 58 | --- 59 | 60 | ## v2.1.2 61 | 62 | - ### 新增方法到 `Line` 对象 63 | 64 | | 方法名称 | 描述 | 参数 | 返回类型 | 65 | |------------------|------------------------------------------------|------------------------------------------|-------------| 66 | | `cget` | 获取指定参数的值 | attribute_name: `str \| "__all__"` | `any` | 67 | | `set_visible` | 更改线的可见性 | state: `bool` | `None` | 68 | | `get_visibility` | 获取线的可见性 | - | `bool` | 69 | 70 | - ### 新增方法到 `LineChart` 对象 71 | 72 | | 方法名称 | 描述 | 参数 | 返回类型 | 73 | |------------------------|------------------------------------------------|--------------------------------------------------|-------------| 74 | | `set_lines_visibility` | 更改所有线的可见性 | state: `bool` | `None` | 75 | | `set_line_visibility` | 更改特定线的可见性 | line: `tkchart.Line`
state: `bool` | `None` | 76 | | `get_line_visibility` | 获取特定线的可见性 | line: `tkchart.Line` | `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 | - ### 移除 `LineChart` 对象的方法 83 | 84 | | 方法名称 | 描述 | 参数 | 返回类型 | 85 | |-------------|----------------------|----------------------------------------------|-------------| 86 | | hide_all | 隐藏所有的线 | state: `bool` | None | 87 | | hide | 隐藏特定的线 | line: `tkchart.Line`
state: `bool` | None | 88 | -------------------------------------------------------------------------------- /CHANGES_en.md: -------------------------------------------------------------------------------- 1 | [![Chinese](https://img.shields.io/badge/Language-中文-red)](CHANGES_zh.md) 2 | 3 | 4 | ## v2.1.6 5 | 6 | - ### New Methods Added to `LineChart` 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[tkchart.Line, Tuple[int]]` | 10 | `get_line_data` | Retrieves data points for a specific line within a specified range and step. | line: `tkchart.Line`
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[tkchart.Line, Tuple[int \| float]]` | 13 | | `get_line_visible_data` | Retrieves currently visible data points for a specific line. | line: `tkchart.Line` | `Tuple[int \| float]` | 14 | 15 | 16 | 17 | - ### New Methods Added to `Line` 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 `LineChart` 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 `Line` 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 Methods Added to `LineChart` Object 42 | | Method Name | Description | Parameters | Return Type | 43 | |------------------|------------------------------------------------------------|----------------|-------------| 44 | | `get_line_area` | Get the are of specific line | line: `tkchart.Line` | ``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 `LineChart` 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 `Line` 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 `Line` 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 `LineChart` 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: `tkchart.Line`
state: `bool` | `None` | 79 | | `get_line_visibility` | Get the visibility of a specific line | line: `tkchart.Line` | `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 `LineChart` 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: ``tkchart.Line``
state: ``bool`` | None | -------------------------------------------------------------------------------- /src/tkchart/Validate.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | from typing import Any, Tuple 3 | from .FontStyle import FontStyle 4 | 5 | 6 | class Validate: 7 | 8 | @staticmethod 9 | def _error_font(value: str) -> str: 10 | """Return a styled error message.""" 11 | return FontStyle._apply(value, "red", "black", "underline") 12 | 13 | @staticmethod 14 | def _var_font(value: str) -> str: 15 | """Return a styled variable name.""" 16 | return FontStyle._apply(value, "green", "black", "italic") 17 | 18 | # --- Basic Type Checkers --- 19 | 20 | @staticmethod 21 | def _is_tuple(value: Any, var: str) -> None: 22 | """Check if value is a tuple.""" 23 | if not isinstance(value, tuple): 24 | raise TypeError(f"{Validate._var_font(var)} {Validate._error_font('must be a tuple.')}") 25 | 26 | @staticmethod 27 | def _is_list(value: Any, var: str) -> None: 28 | """Check if value is a list.""" 29 | if not isinstance(value, list): 30 | raise TypeError(f"{Validate._var_font(var)} {Validate._error_font('must be a list.')}") 31 | 32 | @staticmethod 33 | def _is_int(value: Any, var: str) -> None: 34 | """Check if value is an integer.""" 35 | if not isinstance(value, int): 36 | raise TypeError(f"{Validate._var_font(var)} {Validate._error_font('must be an int.')}") 37 | 38 | @staticmethod 39 | def _is_bool(value: Any, var: str) -> None: 40 | """Check if value is a boolean.""" 41 | if not isinstance(value, bool): 42 | raise TypeError(f"{Validate._var_font(var)} {Validate._error_font('must be a bool.')}") 43 | 44 | @staticmethod 45 | def _is_float(value: Any, var: str) -> None: 46 | """Check if value is a float.""" 47 | if not isinstance(value, float): 48 | raise TypeError(f"{Validate._var_font(var)} {Validate._error_font('must be a float.')}") 49 | 50 | @staticmethod 51 | def _is_str(value: Any, var: str) -> None: 52 | """Check if value is a string.""" 53 | if not isinstance(value, str): 54 | raise TypeError(f"{Validate._var_font(var)} {Validate._error_font('must be a str.')}") 55 | 56 | # --- Complex Validators --- 57 | 58 | @staticmethod 59 | def _is_valid_color(value: Any, var: str) -> None: 60 | """Check if value is a valid color string.""" 61 | Validate._is_str(value, var) 62 | try: 63 | tk.Label(fg=value) 64 | except tk.TclError: 65 | raise ValueError( 66 | f"{Validate._var_font(var)} {Validate._error_font('must be a valid color, e.g. \'red\' or \'#ff0000\'.')}" 67 | ) 68 | 69 | @staticmethod 70 | def _is_valid_font(value: Any, var: str) -> None: 71 | """Check if value is a valid font tuple.""" 72 | Validate._is_tuple(value, var) 73 | try: 74 | tk.Label(font=value) 75 | except tk.TclError: 76 | raise ValueError( 77 | f"{Validate._var_font(var)} {Validate._error_font('must be a valid font, e.g. (\'Arial\', 10, \'bold\').')}" 78 | ) 79 | 80 | @staticmethod 81 | def _is_valid_function(value: Any, var: str) -> None: 82 | """Check if value is callable or None.""" 83 | if value is not None and not callable(value): 84 | raise TypeError( 85 | f"{Validate._var_font(var)} {Validate._error_font('must be a callable function or None.')}" 86 | ) 87 | 88 | @staticmethod 89 | def _is_valid_indices(value: Any, var: str) -> None: 90 | """Check if all values in iterable are integers.""" 91 | if not all(isinstance(v, int) for v in value): 92 | raise TypeError(f"{Validate._var_font(var)} {Validate._error_font('all values must be int.')}") 93 | 94 | @staticmethod 95 | def _is_valid_x_axis_indices(values: Tuple[int, ...], indices: Any, var: str) -> None: 96 | """Validate that indices are within bounds of values.""" 97 | if indices is not None: 98 | Validate._is_tuple(indices, var) 99 | Validate._is_valid_indices(indices, var) 100 | for index in indices: 101 | if index >= len(values): 102 | raise ValueError( 103 | f"{Validate._var_font(var)} {Validate._error_font('index must be less than length of x_axis_values.')}" 104 | ) 105 | 106 | @staticmethod 107 | def _is_valid_x_axis_label_count(value: Any, var: str) -> None: 108 | """Check if x-axis label count is an int if provided.""" 109 | if value is not None: 110 | Validate._is_int(value, var) 111 | 112 | @staticmethod 113 | def _is_valid_style_type(value: Any, var: str) -> None: 114 | """Check if style type is a tuple of two integers.""" 115 | Validate._is_tuple(value, var) 116 | if len(value) != 2 or not all(isinstance(v, int) for v in value): 117 | raise TypeError( 118 | f"{Validate._var_font(var)} {Validate._error_font('must be a tuple of two integers.')}" 119 | ) 120 | 121 | @staticmethod 122 | def _is_valid_data_position(value: Any, var: str) -> None: 123 | """Check if data position is 'top' or 'side'.""" 124 | Validate._is_str(value, var) 125 | if value not in {"top", "side"}: 126 | raise ValueError( 127 | f"{Validate._var_font(var)} {Validate._error_font('must be \'top\' or \'side\'.')}" 128 | ) 129 | 130 | @staticmethod 131 | def _is_valid_line_style(value: Any, var: str) -> None: 132 | """Check if line style is one of the accepted strings.""" 133 | Validate._is_str(value, var) 134 | if value not in {"normal", "dashed", "dotted"}: 135 | raise ValueError( 136 | f"{Validate._var_font(var)} {Validate._error_font('must be \'normal\', \'dashed\', or \'dotted\'.')}" 137 | ) 138 | 139 | @staticmethod 140 | def _is_valid_section_style(value: Any, var: str) -> None: 141 | """Check if section style is either 'normal' or 'dashed'.""" 142 | Validate._is_str(value, var) 143 | if value not in {"normal", "dashed"}: 144 | raise ValueError( 145 | f"{Validate._var_font(var)} {Validate._error_font('must be \'normal\' or \'dashed\'.')}" 146 | ) 147 | 148 | @staticmethod 149 | def _is_valid_x_axis_point_spacing(value: Any, var: str) -> None: 150 | """Check if x-axis point spacing is int or 'auto'.""" 151 | if not (isinstance(value, int) or (isinstance(value, str) and value == "auto")): 152 | raise TypeError( 153 | f"{Validate._var_font(var)} {Validate._error_font('must be int or \'auto\'.')}" 154 | ) 155 | 156 | @staticmethod 157 | def _is_valid_pointer_state_lock(value: Any, var: str) -> None: 158 | """Check if pointer lock state is 'enabled' or 'disabled'.""" 159 | Validate._is_str(value, var) 160 | if value not in {"enabled", "disabled"}: 161 | raise ValueError( 162 | f"{Validate._var_font(var)} {Validate._error_font('must be \'enabled\' or \'disabled\'.')}" 163 | ) 164 | 165 | @staticmethod 166 | def _is_valid_line_highlight(value: Any, var: str) -> None: 167 | """Validate line highlight state.""" 168 | Validate._is_valid_pointer_state_lock(value, var) 169 | 170 | @staticmethod 171 | def _is_valid_line_fill(value: Any, var: str) -> None: 172 | """Validate line fill state.""" 173 | Validate._is_valid_pointer_state_lock(value, var) 174 | 175 | @staticmethod 176 | def _is_valid_y_axis_values(value: Any, var: str) -> None: 177 | """Validate y-axis values as a tuple of two numbers, first less than second.""" 178 | Validate._is_tuple(value, var) 179 | if value == (None, None): 180 | raise ValueError(f"{Validate._var_font(var)} {Validate._error_font('must be provided.')}") 181 | if len(value) != 2 or not all(isinstance(v, (int, float)) for v in value): 182 | raise TypeError( 183 | f"{Validate._var_font(var)} {Validate._error_font('must be a tuple of two numbers.')}" 184 | ) 185 | if value[0] >= value[1]: 186 | raise ValueError( 187 | f"{Validate._var_font(var)} {Validate._error_font('first value must be less than second.')}" 188 | ) 189 | 190 | @staticmethod 191 | def _is_valid_x_axis_values(value: Any, var: str) -> None: 192 | """Validate x-axis values tuple is provided and not placeholders.""" 193 | if value in [(None, None), ("None", "None")]: 194 | raise ValueError(f"{Validate._var_font(var)} {Validate._error_font('must be provided.')}") 195 | Validate._is_tuple(value, var) 196 | 197 | @staticmethod 198 | def _is_valid_line(value: Any, var: str) -> None: 199 | """Check if value is an instance of Line.""" 200 | from .Line import Line 201 | if not isinstance(value, Line): 202 | raise TypeError( 203 | f"{Validate._var_font(var)} {Validate._error_font('must be a tkchart.Line instance.')}" 204 | ) 205 | 206 | @staticmethod 207 | def _is_valid_line_chart(value: Any, var: str) -> None: 208 | """Check if value is an instance of LineChart.""" 209 | from .LineChart import LineChart 210 | if not isinstance(value, LineChart): 211 | raise TypeError( 212 | f"{Validate._var_font(var)} {Validate._error_font('must be a tkchart.LineChart instance.')}" 213 | ) 214 | 215 | @staticmethod 216 | def _is_valid_data(value: Any, var: str) -> None: 217 | """Validate that value is a list of ints or floats.""" 218 | Validate._is_list(value, var) 219 | if not all(isinstance(v, (int, float)) for v in value): 220 | raise TypeError( 221 | f"{Validate._var_font(var)} {Validate._error_font('all values must be int or float.')}" 222 | ) 223 | 224 | # --- Error Helpers --- 225 | 226 | @staticmethod 227 | def _invalid_cget(var: str) -> None: 228 | """Raise error for invalid attribute.""" 229 | raise ValueError( 230 | f"{Validate._var_font(var)} {Validate._error_font('Invalid attribute.')}" 231 | ) 232 | 233 | @staticmethod 234 | def _invalid_line(line: Any) -> None: 235 | """Raise error if line is not part of chart.""" 236 | raise ValueError( 237 | f"{Validate._var_font(str(line))} {Validate._error_font('The line is not part of this chart.')}" 238 | ) 239 | 240 | @staticmethod 241 | def _master_att_not_provided_for_line(value: Any) -> None: 242 | """Raise error if master is not provided for Line.""" 243 | raise ValueError( 244 | f"{Validate._var_font(str(value))} {Validate._error_font('master must be provided for Line.')}" 245 | ) 246 | -------------------------------------------------------------------------------- /README_zh.md: -------------------------------------------------------------------------------- 1 | [![Language](https://img.shields.io/badge/Language-English-blue)](README.md) 2 | 3 |
4 | 5 | [![tkchart](https://snyk.io/advisor/python/tkchart/badge.svg)](https://snyk.io/advisor/python/tkchart) 6 | 7 | # tkchart 8 | 9 | [![PyPI version](https://badge.fury.io/py/tkchart.svg)](https://pypi.org/project/tkchart/) 10 | 11 | [![Downloads](https://static.pepy.tech/badge/tkchart)](https://pepy.tech/project/tkchart) ![Downloads last 6 month](https://static.pepy.tech/personalized-badge/tkchart?period=total&units=international_system&left_color=grey&right_color=BLUE&left_text=downloads%20last%206%20month) [![Downloads](https://static.pepy.tech/badge/tkchart/month)](https://pepy.tech/project/tkchart) [![Downloads](https://static.pepy.tech/badge/tkchart/week)](https://pepy.tech/project/tkchart) 12 | 13 | ![PyPI - License](https://img.shields.io/badge/license-MIT-blue) 14 | ![LOC](https://tokei.rs/b1/github/Thisal-D/tkchart?category=lines) 15 |
16 | 17 | **
  • tkchart 是一个用于在 tkinter 中创建实时更新折线图的 Python 库。
  • ** 18 | 19 | --- 20 | 21 | ### 特性 22 | 23 | - **实时更新**:通过折线图显示实时数据。 24 | - **多条线**:支持在同一图表中绘制多条线,方便对比。 25 | - **颜色自定义**:自定义颜色以匹配您的应用程序设计或数据表示。 26 | - **字体自定义**:调整文本元素的字体以提高可读性。 27 | - **尺寸自定义**:自定义图表的尺寸以适应不同的显示大小和布局。 28 | 29 | [**查看最新变化 | 变更记录**](CHANGES_zh.md) 30 | 31 | --- 32 | 33 | ### 导入与安装 34 | * **安装** 35 | ``` 36 | pip install tkchart 37 | ``` 38 | 39 | * **导入** 40 | ``` python 41 | import tkchart 42 | ``` 43 | 44 | --- 45 | 46 | ### 简单指南 47 | - **导入包** 48 | ``` python 49 | import tkchart 50 | ``` 51 | 52 | - **创建折线图并放置图表** 53 | ``` python 54 | chart = tkchart.LineChart( 55 | master=root, 56 | x_axis_values=("a", "b", "c", "d", "e", "f"), 57 | y_axis_values=(100, 900) 58 | ) 59 | chart.place(x=10, y=10) 60 | ``` 61 | 62 | - **创建折线** 63 | ``` python 64 | line = tkchart.Line(master=chart) 65 | ``` 66 | 67 | - **显示数据** 68 | 使用循环显示数据 69 | ``` python 70 | def loop(): 71 | while True: 72 | random_data = random.choice(range(100, 900)) 73 | chart.show_data(line=line, data=[random_data]) 74 | time.sleep(1) 75 | 76 | # 作为线程调用循环 77 | theading.Thread(target=loop).start() 78 | ``` 79 | 80 | --- 81 | 82 | ### 链接 83 | 84 | - **文档 :** [文档](documentation) 85 | - [英文文档](documentation/DOCUMENTATION_en.md) 86 | - [中文文档](documentation/DOCUMENTATION_zh.md) 87 | - **Python 官方 :** [tkchart](https://pypi.org/project/tkchart/) 88 | 89 | --- 90 | 91 | ### 您可以实现的功能 92 | 93 | - **简单示例** 94 | 95 | https://github.com/Thisal-D/ctkchart/assets/93121062/6f1e844f-d51c-467a-a3dc-ee03fea78fc9 96 | 97 | ``` python 98 | import tkinter as tk # 导入 tkinter 库 99 | import tkchart # 导入 tkchart 模块来创建图表 100 | import random # 导入 random 模块生成随机数据 101 | import threading # 导入 threading 模块实现并发任务 102 | import time # 导入 time 模块添加延时 103 | 104 | # 创建根窗口并配置 105 | root = tk.Tk() 106 | root.configure(bg="#0d1117") 107 | root.geometry("720x430+200+200") 108 | 109 | # 创建折线图控件 110 | line_chart = tkchart.LineChart( 111 | master=root, # 设置根窗口为主控件 112 | x_axis_values=("01-01", "01-02", "01-03", "01-04", "01-05", "01-06", "01-07", "01-08", "01-09", "01-10"), # X轴数据 113 | y_axis_values=(0, 1000) # Y轴数据(范围) 114 | ) 115 | 116 | line_chart.pack(pady=15) # 将折线图控件打包到根窗口中 117 | 118 | # 创建折线 119 | line = tkchart.Line(master=line_chart) # 设置折线图控件为父控件 120 | 121 | def display_data(): 122 | """连续显示随机数据的函数。""" 123 | while True: 124 | random_data = [random.choice(range(0, 1000))] # 生成0到1000之间的随机数据 125 | line_chart.show_data(line=line, data=random_data) # 显示随机数据 126 | time.sleep(0.5) # 每0.5秒更新一次数据 127 | 128 | # 作为线程调用 display_data 函数 129 | threading.Thread(target=display_data).start() 130 | 131 | # 启动主事件循环 132 | root.mainloop() 133 | ``` 134 | 135 | --- 136 | 137 | - **简单样式** 138 | 139 | https://github.com/Thisal-D/ctkchart/assets/93121062/afe56452-68c3-44f0-9c67-2ab6f6910f6e 140 | 141 | ``` python 142 | import tkinter as tk # 导入 tkinter 库 143 | import tkchart # 导入 tkchart 模块来创建图表 144 | import random # 导入 random 模块生成随机数据 145 | import threading # 导入 threading 模块实现并发任务 146 | import time # 导入 time 模块添加延时 147 | 148 | # 创建根窗口并配置 149 | root = tk.Tk() 150 | root.configure(bg="#0d1117") 151 | root.geometry("720x430+200+200") 152 | 153 | # 创建折线图控件 154 | line_chart = tkchart.LineChart( 155 | master=root, # 设置根窗口为主控件 156 | x_axis_values=("01-01", "01-02", "01-03", "01-04", "01-05", "01-06", "01-07", "01-08", "01-09", "01-10"), # X轴数据 157 | y_axis_values=(0, 1000), # Y轴数据(范围) 158 | y_axis_label_count=10, # 设置Y轴标签数量为10 159 | ) 160 | 161 | line_chart.pack(pady=15) # 将折线图控件打包到根窗口中 162 | 163 | # 创建折线 164 | line = tkchart.Line( 165 | master=line_chart, # 设置折线图控件为父控件 166 | size=2, # 设置折线大小为2 167 | fill="enabled" # 启用折线填充 168 | ) 169 | 170 | def display_data(): 171 | """连续显示随机数据的函数。""" 172 | while True: 173 | random_data = [random.choice(range(0, 1000))] # 生成0到1000之间的随机数据 174 | line_chart.show_data(line=line, data=random_data) # 显示随机数据 175 | time.sleep(0.5) # 每0.5秒更新一次数据 176 | 177 | # 作为线程调用 display_data 函数 178 | threading.Thread(target=display_data).start() 179 | 180 | # 启动主事件循环 181 | root.mainloop() 182 | ``` 183 | 184 | --- 185 | 186 | - **两条不同样式的折线** 187 | 188 | https://github.com/Thisal-D/ctkchart/assets/93121062/9bc35a39-a8ca-4942-9fc7-a1c89d1bd1bc 189 | 190 | ``` python 191 | import tkinter as tk # 导入 tkinter 库 192 | import tkchart # 导入 tkchart 模块来创建图表 193 | import random # 导入 random 模块生成随机数据 194 | import threading # 导入 threading 模块实现并发任务 195 | import time # 导入 time 模块添加延时 196 | 197 | # 创建根窗口并配置 198 | root = tk.Tk() 199 | root.configure(bg="#0d1117") 200 | root.geometry("720x430+200+200") 201 | 202 | # 创建折线图控件 203 | line_chart = tkchart.LineChart( 204 | master=root, # 设置根窗口为主控件 205 | x_axis_values=("01-01", "01-02", "01-03", "01-04", "01-05", "01-06", "01-07", "01-08", "01-09", "01-10"), # X轴数据 206 | y_axis_values=(0, 1000), # Y轴数据(范围) 207 | y_axis_label_count=10, # 设置Y轴标签数量为10 208 | ) 209 | 210 | line_chart.pack(pady=15) # 将折线图控件打包到根窗口中 211 | 212 | # 创建折线1 213 | line1 = tkchart.Line( 214 | master=line_chart, # 设置折线图控件为父控件 215 | size=2, # 设置折线大小为2 216 | fill="enabled", # 启用折线填充 217 | color="yellow" # 设置颜色为黄色 218 | ) 219 | 220 | # 创建折线2 221 | line2 = tkchart.Line( 222 | master=line_chart, # 设置折线图控件为父控件 223 | size=2, # 设置折线大小为2 224 | fill="disabled", # 禁用折线填充 225 | color="red" # 设置颜色为红色 226 | ) 227 | 228 | def display_data(): 229 | """连续显示随机数据的函数。""" 230 | while True: 231 | random_data = [random.choice(range(0, 1000))] # 生成0到1000之间的随机数据 232 | line_chart.show_data(line=line1, data=random_data) # 显示随机数据到第一条折线 233 | line_chart.show_data(line=line2, data=random_data) # 显示随机数据到第二条折线 234 | time.sleep(0.5) # 每0.5秒更新一次数据 235 | 236 | # 作为线程调用 display_data 函数 237 | threading.Thread(target=display_data).start() 238 | 239 | # 启动主事件循环 240 | root.mainloop() 241 | ``` 242 | 243 | - **3条具有不同线条样式的线** 244 | 245 | https://github.com/Thisal-D/ctkchart/assets/93121062/6d568b70-2ceb-42d0-b93c-0096f2745134 246 | 247 | ```python 248 | import tkinter as tk # 导入 tkinter 库 249 | import tkchart # 导入 tkchart 模块用于图表创建 250 | import random # 导入 random 模块用于生成随机数据 251 | import threading # 导入 threading 模块用于并发执行任务 252 | import time # 导入 time 模块用于添加延迟 253 | 254 | # 创建根窗口并配置 255 | root = tk.Tk() 256 | root.configure(bg="#0d1117") 257 | root.geometry("720x430+200+200") 258 | 259 | # 创建折线图小部件 260 | line_chart = tkchart.LineChart( 261 | master=root, # 设置根窗口为主控件 262 | x_axis_values=("01-01", "01-02", "01-03", "01-04", "01-05", "01-06", "01-07", "01-08", "01-09", "01-10"), # X轴值 263 | y_axis_values=(0, 1000), # Y轴值(范围) 264 | y_axis_label_count=10, # 设置Y轴标签计数为10 265 | ) 266 | 267 | line_chart.pack(pady=15) # 将折线图小部件放入根窗口 268 | 269 | # 创建第一条线 270 | line1 = tkchart.Line( 271 | master=line_chart, # 设置主控件为折线图 272 | size=2, # 设置线条大小为2 273 | fill="enabled" # 启用线条填充 274 | ) 275 | 276 | line2 = tkchart.Line( 277 | master=line_chart, # 设置主控件为折线图 278 | color="#5dffb6", # 设置颜色为绿色 279 | size=2, # 设置线条大小为2 280 | style="dashed", # 设置样式为虚线 281 | style_type=(10, 5), # 设置虚线的宽度和间隔 282 | ) 283 | 284 | line3 = tkchart.Line( 285 | master=line_chart, # 设置主控件为折线图 286 | color="#FFBAD2", # 设置颜色为粉色 287 | size=2, # 设置线条大小为2 288 | point_highlight="enabled", # 启用高亮点 289 | point_highlight_color="#FFBAD2", # 设置高亮点颜色 290 | ) 291 | 292 | def display_data(): 293 | """连续显示随机数据在折线图上。""" 294 | while True: 295 | random_data = random.choices(range(0, 1000),k=1) # 生成0到1000之间的随机数据 296 | line_chart.show_data(line=line1, data=random_data) # 在第一条线上显示随机数据 297 | random_data = random.choices(range(0, 1000),k=1) # 生成0到1000之间的随机数据 298 | line_chart.show_data(line=line2, data=random_data) # 在第二条线上显示随机数据 299 | random_data = random.choices(range(0, 1000),k=1) # 生成0到1000之间的随机数据 300 | line_chart.show_data(line=line3, data=random_data) # 在第三条线上显示随机数据 301 | time.sleep(0.5) # 暂停0.5秒再进行下一次迭代 302 | 303 | # 在单独的线程中调用 display_data 函数 304 | threading.Thread(target=display_data).start() 305 | 306 | # 启动主事件循环 307 | root.mainloop() 308 | ``` 309 | 310 | --- 311 | 312 | - **高级**(实际上只是增加了两个属性) 313 | 314 | https://github.com/Thisal-D/ctkchart/assets/93121062/c2838fd6-3a0f-45be-bb39-9953d007067d 315 | 316 | ```python 317 | import tkinter as tk # 导入 tkinter 库 318 | import tkchart # 导入 tkchart 模块用于图表创建 319 | import random # 导入 random 模块用于生成随机数据 320 | import threading # 导入 threading 模块用于并发执行任务 321 | import time # 导入 time 模块用于添加延迟 322 | 323 | # 创建根窗口并配置 324 | root = tk.Tk() 325 | root.configure(bg = "#0d1117") 326 | root.geometry("720x430+200+200") 327 | 328 | # 创建折线图小部件 329 | line_chart = tkchart.LineChart( 330 | master=root, # 设置根窗口为主控件 331 | x_axis_values=("01-01", "01-02", "01-03", "01-04", "01-05", "01-06", "01-07", "01-08", "01-09", "01-10"), # X轴值 332 | y_axis_values=(0, 1000), # Y轴值(范围) 333 | y_axis_label_count=10, # 设置Y轴标签计数为1 334 | y_axis_section_count=10, 335 | x_axis_section_count=10, 336 | ) 337 | 338 | line_chart.pack(pady=15) # 将折线图小部件放入根窗口 339 | 340 | line1 = tkchart.Line( 341 | master=line_chart, # 设置主控件为折线图 342 | color="#5dffb6", # 设置颜色为绿色 343 | size=2, # 设置线条大小为2 344 | style="dashed", # 设置样式为虚线 345 | style_type=(10, 5), # 设置虚线的宽度和间隔 346 | ) 347 | 348 | line2 = tkchart.Line( 349 | master=line_chart, # 设置主控件为折线图 350 | color="#FFBAD2", # 设置颜色为粉色 351 | size=2, # 设置线条大小为2 352 | point_highlight="enabled", # 启用高亮点 353 | point_highlight_color="#FFBAD2", # 设置高亮点颜色 354 | ) 355 | 356 | def display_data(): 357 | """连续显示随机数据在折线图上。""" 358 | while True: 359 | random_data = [random.choice(range(0, 1000))] # 生成0到1000之间的随机数据 360 | line_chart.show_data(line=line1, data=random_data) # 在第一条线上显示随机数据 361 | random_data = [random.choice(range(0, 1000))] # 生成0到1000之间的随机数据 362 | line_chart.show_data(line=line2, data=random_data) # 在第二条线上显示随机数据 363 | time.sleep(0.5) # 暂停0.5秒再进行下一次迭代 364 | 365 | # 在单独的线程中调用 display_data 函数 366 | threading.Thread(target=display_data).start() 367 | 368 | # 启动主事件循环 369 | root.mainloop() 370 | ``` 371 | 372 | --- 373 | 374 | **探索可自定义的功能,如颜色、字体等,详细内容请参考文档。** 375 | 376 | #### 请参考完整文档 377 | - [**英文文档**](documentation/DOCUMENTATION_en.md) 378 | - [**中文文档**](documentation/DOCUMENTATION_zh.md) 379 | 380 | --- 381 | 382 | #### 贡献者 383 | - [](https://github.com/childeyouyu) [youyu](https://github.com/childeyouyu) 384 | -------------------------------------------------------------------------------- /src/tkchart/Line.py: -------------------------------------------------------------------------------- 1 | from typing import Tuple, Literal, Any 2 | from .Validate import Validate 3 | 4 | 5 | class Line: 6 | current_usable_id = 1 7 | def __init__( 8 | self, 9 | master: Any = None, 10 | color: str = "#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 = 4, 16 | point_highlight_color: str = "#768df1", 17 | fill: Literal["enabled", "disabled"] = "disabled", 18 | fill_color: str = "#5d6db6", 19 | *args: Any 20 | ) -> None: 21 | """ 22 | Initialize a Line object. 23 | 24 | Args: 25 | master (LineChart): The master object. 26 | color (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 (str): The color of points used for highlighting. 33 | fill (str): Whether fill for the line is enabled or disabled. 34 | fill_color (str): The color of the fill for the line. 35 | 36 | Raises: 37 | TypeError: If any of the parameters are of an incorrect type. 38 | ValueError: If any of the parameters are invalid. 39 | """ 40 | if master is None: 41 | if len(args) != 0: 42 | master = args[0] 43 | else: 44 | Validate._master_att_not_provided_for_line("master") 45 | 46 | Validate._is_valid_line_chart(master, "master") 47 | Validate._is_valid_color(color, "color") 48 | Validate._is_int(size, "size") 49 | Validate._is_valid_line_style(style, "style") 50 | Validate._is_valid_style_type(style_type, "style_type") 51 | Validate._is_valid_line_highlight(point_highlight, "point_highlight") 52 | Validate._is_int(point_highlight_size, "point_highlight_size") 53 | Validate._is_valid_color(point_highlight_color, "point_highlight_color") 54 | Validate._is_valid_line_fill(fill, "fill") 55 | Validate._is_valid_color(fill_color, "fill_color") 56 | 57 | # id (int): The id of the line. need unique 58 | self.__id = Line.current_usable_id 59 | Line.current_usable_id += 1 60 | 61 | self.__master = master 62 | self.__color = color 63 | self.__size = size 64 | self.__y_end = 0 65 | self.__x_end = self.__master._LineChart__x_axis_point_spacing * -1 66 | self.__data = [] 67 | self.__temp_data = [] 68 | self.__ret_data = [] 69 | self.__visibility = self.__master._LineChart__visibility 70 | self.__style = style 71 | self.__style_type = style_type 72 | self.__point_highlight = point_highlight 73 | self.__point_highlight_size = point_highlight_size 74 | self.__point_highlight_color = point_highlight_color 75 | self.__fill = fill 76 | self.__fill_color = fill_color 77 | 78 | self.__master._LineChart__lines.append(self) 79 | 80 | def configure( 81 | self, 82 | color: str = None, 83 | size: int = None, 84 | style: Literal["normal", "dashed", "dotted"] = None, 85 | style_type: Tuple[int, int] = None, 86 | point_highlight: Literal["enabled", "disabled"] = None, 87 | point_highlight_size: int = None, 88 | point_highlight_color: str = None, 89 | fill: Literal["enabled", "disabled"] = None, 90 | fill_color: str = None 91 | ) -> None: 92 | """ 93 | Configure attributes of the Line object. 94 | 95 | Args: 96 | color (str): The color of the line. 97 | size (int): The size/thickness of the line. 98 | style (str): The style of the line (e.g., 'normal', 'dashed', 'dotted'). 99 | style_type (Tuple[int, int]): The style type for dashed or dotted lines. 100 | point_highlight (str): Whether point highlighting is enabled or disabled. 101 | point_highlight_size (int): The size of points used for highlighting. 102 | point_highlight_color (str): The color of points used for highlighting. 103 | fill (str): Whether fill for the line is enabled or disabled. 104 | fill_color (str): The color of the fill for the line. 105 | 106 | Raises: 107 | TypeError: If any of the parameters are of an incorrect type. 108 | ValueError: If any of the parameters are invalid. 109 | """ 110 | changes_req = False 111 | 112 | if color is not None: 113 | Validate._is_valid_color(color, "color") 114 | self.__color = color 115 | changes_req = True 116 | 117 | if size is not None: 118 | Validate._is_int(size, "size") 119 | self.__size = size 120 | changes_req = True 121 | 122 | if style is not None: 123 | Validate._is_valid_line_style(style, "style") 124 | self.__style = style 125 | changes_req = True 126 | 127 | if style_type is not None: 128 | Validate._is_valid_style_type(style_type, "style_type") 129 | self.__style_type = style_type 130 | changes_req = True 131 | 132 | if point_highlight is not None: 133 | Validate._is_valid_line_highlight(point_highlight, "point_highlight") 134 | self.__point_highlight = point_highlight 135 | changes_req = True 136 | 137 | if point_highlight_size is not None: 138 | Validate._is_int(point_highlight_size, "point_highlight_size") 139 | self.__point_highlight_size = point_highlight_size 140 | changes_req = True 141 | 142 | if point_highlight_color is not None: 143 | Validate._is_valid_color(point_highlight_color, "point_highlight_color") 144 | self.__point_highlight_color = point_highlight_color 145 | changes_req = True 146 | 147 | if fill is not None: 148 | Validate._is_valid_line_fill(fill, "fill") 149 | self.__fill = fill 150 | changes_req = True 151 | 152 | if fill_color is not None: 153 | Validate._is_valid_color(fill_color, "fill_color") 154 | self.__fill_color = fill_color 155 | changes_req = True 156 | 157 | if changes_req: 158 | self.__master._LineChart__apply_line_configuration() 159 | 160 | def get_id(self) -> int: 161 | """ 162 | Get the unique identifier of the Line object. 163 | 164 | Returns: 165 | int: The unique identifier of the line. 166 | """ 167 | return self.__id 168 | 169 | def __reset_positions(self) -> None: 170 | """ 171 | Reset the Line object. 172 | """ 173 | self.__y_end = 0 174 | self.__x_end = self.__master._LineChart__x_axis_point_spacing * -1 175 | 176 | def __reset_data(self) -> None: 177 | self.__data = [] 178 | 179 | def clear_data(self) -> None: 180 | """ 181 | Clears the chart data, ensuring that only the relevant visible data is retained. 182 | 183 | This method works by checking the maximum number of data points across all lines in the chart 184 | and the maximum number of visible data points. If the chart contains more data points than 185 | the visible limit, the data is cropped so that only the most recent data points (up to the 186 | visible limit) are kept. If the chart is already within the visible limit, the data is not altered. 187 | 188 | The data is trimmed from the beginning of the dataset, and the most recent points are kept. 189 | 190 | This ensures that the chart does not display more data than the allowed visible limit, 191 | optimizing performance and display consistency. 192 | 193 | Attributes: 194 | self.__data: The internal list that holds all the data for the lines on the chart. 195 | 196 | Returns: 197 | None: This method modifies the internal state of the data but does not return any value. 198 | """ 199 | maximum_data = self.__master._LineChart__get_max_data_length_across_lines() 200 | max_visible_points = self.__master._LineChart__get_max_visible_data_points() 201 | 202 | if maximum_data > max_visible_points: 203 | self.__data = self.__data[maximum_data - max_visible_points::] 204 | 205 | def get_data(self, start: int = None, end: int = None, step: int = None) -> Tuple[int | float]: 206 | """ 207 | Retrieve data points from the specified range and step. 208 | 209 | Args: 210 | start (int, optional): The starting index for slicing the data. Defaults to None. 211 | end (int, optional): The ending index for slicing the data. Defaults to None. 212 | step (int, optional): The step size for slicing the data. Defaults to None. 213 | 214 | Returns: 215 | Tuple[int | float]: A tuple of data points from the specified range and step. 216 | """ 217 | return tuple(self.__data[start: end: step]) 218 | 219 | def get_current_visible_data(self) -> Tuple[int | float]: 220 | """ 221 | Retrieve the currently visible data points. 222 | 223 | Determines visible data points based on the maximum data length across all lines 224 | and the maximum number of visible points. 225 | 226 | Returns: 227 | Tuple[int | float]: A tuple of currently visible data points. 228 | If no data is visible, an empty tuple is returned. 229 | """ 230 | maximum_data = self.__master._LineChart__get_max_data_length_across_lines() 231 | max_visible_points = self.__master._LineChart__get_max_visible_data_points() 232 | 233 | if maximum_data > max_visible_points: 234 | data = tuple(self.__data[maximum_data - max_visible_points::]) 235 | else: 236 | data = tuple(self.__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._LineChart__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._LineChart__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 Line 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._LineChart__lines.remove(self) 364 | self.__master._LineChart__apply_line_configuration() 365 | except ValueError: 366 | pass # In case the line is not in the list 367 | finally: 368 | self.__del__() -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Chinese](https://img.shields.io/badge/Language-中文-red)](README_zh.md) 2 | 3 |
    4 | 5 | [![tkchart](https://snyk.io/advisor/python/tkchart/badge.svg)](https://snyk.io/advisor/python/tkchart) 6 | 7 | # tkchart 8 | 9 | [![PyPI version](https://badge.fury.io/py/tkchart.svg)](https://pypi.org/project/tkchart/) 10 | 11 | [![Downloads](https://static.pepy.tech/badge/tkchart)](https://pepy.tech/project/tkchart) ![Downloads last 6 month](https://static.pepy.tech/personalized-badge/tkchart?period=total&units=international_system&left_color=grey&right_color=BLUE&left_text=downloads%20last%206%20month) [![Downloads](https://static.pepy.tech/badge/tkchart/month)](https://pepy.tech/project/tkchart) [![Downloads](https://static.pepy.tech/badge/tkchart/week)](https://pepy.tech/project/tkchart) 12 | 13 | ![PyPI - License](https://img.shields.io/badge/license-MIT-blue) 14 | ![LOC](https://tokei.rs/b1/github/Thisal-D/tkchart?category=lines) 15 |
    16 | 17 | **
  • tkchart is a Python library for creating live updating line charts in tkinter.
  • ** 18 | 19 | --- 20 | 21 | ### Features 22 | 23 | - **Live Update**: Display live data with line charts. 24 | - **Multiple Lines**: Support for plotting multiple lines on the same chart for easy comparison. 25 | - **Color Customization**: Customize colors to match your application's design or data representation. 26 | - **Font Customization**: Adjust fonts for text elements to enhance readability. 27 | - **Dimension Customization**: Customize chart dimensions to fit various display sizes and layouts. 28 | 29 | [**Check out what's new | Changes**](CHANGES_en.md) 30 | 31 | --- 32 | 33 | ### Importing & Installation 34 | * **Installation** 35 | ``` 36 | pip install tkchart 37 | ``` 38 | 39 | * **Importing** 40 | ``` python 41 | import tkchart 42 | ``` 43 | 44 | --- 45 | 46 | ### Simple Guide 47 | - **import package** 48 | ``` python 49 | import tkchart 50 | ``` 51 | 52 | - **Create Line Chart and place the chart** 53 | ``` python 54 | chart = tkchart.LineChart( 55 | master=root, 56 | x_axis_values=("a", "b", "c", "d", "e", "f"), 57 | y_axis_values=(100, 900) 58 | ) 59 | chart.place(x=10, y=10) 60 | ``` 61 | 62 | - **Create Line** 63 | ``` python 64 | line = tkchart.Line(master=chart) 65 | ``` 66 | 67 | - **Display Data** 68 | display data using a loop 69 | ``` python 70 | def loop(): 71 | while True: 72 | random_data = random.choice(range(100, 900)) 73 | chart.show_data(line=line, data=[random_data]) 74 | time.sleep(1) 75 | 76 | #call the loop as thead 77 | theading.Thread(target=loop).start() 78 | ``` 79 | 80 | --- 81 | 82 | ### Links 83 | 84 | - **Documentation :** [Documents](documentation) 85 | - [English doc.](documentation/DOCUMENTATION_en.md) 86 | - [Chinese doc.](documentation/DOCUMENTATION_zh.md) 87 | - **Python official :** [tkchart](https://pypi.org/project/tkchart/) 88 | 89 | --- 90 | 91 | ### What You Can Accomplish 92 | 93 | - **Simple** 94 | 95 | https://github.com/Thisal-D/ctkchart/assets/93121062/6f1e844f-d51c-467a-a3dc-ee03fea78fc9 96 | 97 | ``` python 98 | import tkinter as tk # Importing the tkinter library as tk 99 | import tkchart # Importing the tkchart module for chart creation 100 | import random # Importing the random module for generating random data 101 | import threading # Importing the threading module for running tasks concurrently 102 | import time # Importing the time module for adding delays 103 | 104 | # Create the root window and configure 105 | root = tk.Tk() 106 | root.configure(bg="#0d1117") 107 | root.geometry("720x430+200+200") 108 | 109 | # Create a line chart widget 110 | line_chart = tkchart.LineChart( 111 | master=root, # Set the master as the root window 112 | 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 113 | y_axis_values=(0, 1000) # Y-axis values (range) 114 | ) 115 | 116 | line_chart.pack(pady=15) # Pack the line chart widget into the root 117 | 118 | # Create a line for the line chart 119 | line = tkchart.Line(master=line_chart) # Set the master as the line chart 120 | 121 | def display_data(): 122 | """Function to continuously display random data on the line chart.""" 123 | while True: 124 | random_data = [random.choice(range(0, 1000))] # Generate random data between 0 and 1000 125 | line_chart.show_data(line=line, data=random_data) # Display the random data on the line chart 126 | time.sleep(0.5) # Pause for 0.5 seconds before the next iteration 127 | 128 | # Call the display_data function as a separate thread 129 | threading.Thread(target=display_data).start() 130 | 131 | # Start the main event loop 132 | root.mainloop() 133 | ``` 134 | --- 135 | 136 | - **Simple style** 137 | 138 | https://github.com/Thisal-D/ctkchart/assets/93121062/afe56452-68c3-44f0-9c67-2ab6f6910f6e 139 | 140 | ``` python 141 | import tkinter as tk # Importing the tkinter library as tk 142 | import tkchart # Importing the tkchart module for chart creation 143 | import random # Importing the random module for generating random data 144 | import threading # Importing the threading module for running tasks concurrently 145 | import time # Importing the time module for adding delays 146 | 147 | # Create the root window and configure 148 | root = tk.Tk() 149 | root.configure(bg="#0d1117") 150 | root.geometry("720x430+200+200") 151 | 152 | # Create a line chart widget 153 | line_chart = tkchart.LineChart( 154 | master=root, # Set the master as the root window 155 | 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 156 | y_axis_values=(0, 1000), # Y-axis values (range) 157 | y_axis_label_count=10, # set y axis labels count to 10 158 | ) 159 | 160 | line_chart.pack(pady=15) # Pack the line chart widget into the root 161 | 162 | # Create a line for the line chart 163 | line = tkchart.Line( 164 | master=line_chart, # Set the master as the line chart 165 | size=2, # Set the line size to 2 166 | fill="enabled" # enable line fill 167 | ) 168 | 169 | def display_data(): 170 | """Function to continuously display random data on the line chart.""" 171 | while True: 172 | random_data = [random.choice(range(0, 1000))] # Generate random data between 0 and 1000 173 | line_chart.show_data(line=line, data=random_data) # Display the random data on the line chart 174 | time.sleep(0.5) # Pause for 0.5 seconds before the next iteration 175 | 176 | # Call the display_data function as a separate thread 177 | threading.Thread(target=display_data).start() 178 | 179 | # Start the main event loop 180 | root.mainloop() 181 | ``` 182 | --- 183 | 184 | - **2 lines with different line styles** 185 | 186 | https://github.com/Thisal-D/ctkchart/assets/93121062/9bc35a39-a8ca-4942-9fc7-a1c89d1bd1bc 187 | 188 | ``` python 189 | import tkinter as tk # Importing the tkinter library as tk 190 | import tkchart # Importing the tkchart module for chart creation 191 | import random # Importing the random module for generating random data 192 | import threading # Importing the threading module for running tasks concurrently 193 | import time # Importing the time module for adding delays 194 | 195 | # Create the root window and configure 196 | root = tk.Tk() 197 | root.configure(bg="#0d1117") 198 | root.geometry("720x430+200+200") 199 | 200 | # Create a line chart widget 201 | line_chart = tkchart.LineChart( 202 | master=root, # Set the master as the root window 203 | 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 204 | y_axis_values=(0, 1000), # Y-axis values (range) 205 | y_axis_label_count=10, # set y axis labels count to 10 206 | ) 207 | 208 | line_chart.pack(pady=15) # Pack the line chart widget into the root 209 | 210 | line1 = tkchart.Line( 211 | master=line_chart, # Set the master as the line chart 212 | color="#5dffb6", # index 0 for light and 1 for dark theme 213 | size=2, # Set the line size to 2 214 | style="dashed", # style change to dashed 215 | style_type=(10, 5), #index 0 for dash width and 1 for space between dashes 216 | ) 217 | 218 | line2 = tkchart.Line( 219 | master=line_chart, # Set the master as the line chart 220 | color="#FFBAD2", # index 0 for light and 1 for dark theme 221 | size=2, # Set the line size to 2 222 | point_highlight="enabled", # enable point highlight 223 | point_highlight_color="#FFBAD2", # enable point highlight 224 | ) 225 | 226 | def display_data(): 227 | """Function to continuously display random data on the line chart.""" 228 | while True: 229 | random_data = [random.choice(range(0, 1000))] # Generate random data between 0 and 1000 230 | line_chart.show_data(line=line1, data=random_data) # Display the random data on the line 1 on chart 231 | random_data = [random.choice(range(0, 1000))] # Generate random data between 0 and 1000 232 | line_chart.show_data(line=line2, data=random_data) # Display the random data on the line 2 on chart 233 | time.sleep(0.5) # Pause for 0.5 seconds before the next iteration 234 | 235 | # Call the display_data function as a separate thread 236 | threading.Thread(target=display_data).start() 237 | 238 | # Start the main event loop 239 | root.mainloop() 240 | ``` 241 | 242 | --- 243 | 244 | - **3 lines with different line styles** 245 | 246 | https://github.com/Thisal-D/ctkchart/assets/93121062/6d568b70-2ceb-42d0-b93c-0096f2745134 247 | 248 | ``` python 249 | import tkinter as tk # Importing the tkinter library as tk 250 | import tkchart # Importing the tkchart module for chart creation 251 | import random # Importing the random module for generating random data 252 | import threading # Importing the threading module for running tasks concurrently 253 | import time # Importing the time module for adding delays 254 | 255 | # Create the root window and configure 256 | root = tk.Tk() 257 | root.configure(bg="#0d1117") 258 | root.geometry("720x430+200+200") 259 | 260 | # Create a line chart widget 261 | line_chart = tkchart.LineChart( 262 | master=root, # Set the master as the root window 263 | 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 264 | y_axis_values=(0, 1000), # Y-axis values (range) 265 | y_axis_label_count=10, # set y axis labels count to 10 266 | ) 267 | 268 | line_chart.pack(pady=15) # Pack the line chart widget into the root 269 | 270 | # Create a line 1 for the line chart 271 | line1 = tkchart.Line( 272 | master=line_chart, # Set the master as the line chart 273 | size=2, # Set the line size to 2 274 | fill="enabled" # enable line fill 275 | ) 276 | 277 | line2 = tkchart.Line( 278 | master=line_chart, # Set the master as the line chart 279 | color="#5dffb6", # index 0 for light and 1 for dark theme 280 | size=2, # Set the line size to 2 281 | style="dashed", # style change to dashed 282 | style_type=(10, 5), #index 0 for dash width and 1 for space between dashes 283 | ) 284 | 285 | line3 = tkchart.Line( 286 | master=line_chart, # Set the master as the line chart 287 | color="#FFBAD2", # index 0 for light and 1 for dark theme 288 | size=2, # Set the line size to 2 289 | point_highlight="enabled", # enable point highlight 290 | point_highlight_color="#FFBAD2", # enable point highlight 291 | ) 292 | 293 | def display_data(): 294 | """Function to continuously display random data on the line chart.""" 295 | while True: 296 | random_data = random.choices(range(0, 1000),k=1) # Generate random data between 0 and 1000 297 | line_chart.show_data(line=line1, data=random_data) # Display the random data on the line 1 on chart 298 | random_data = random.choices(range(0, 1000),k=1) # Generate random data between 0 and 1000 299 | line_chart.show_data(line=line2, data=random_data) # Display the random data on the line 2 on chart 300 | random_data = random.choices(range(0, 1000),k=1) # Generate random data between 0 and 1000 301 | line_chart.show_data(line=line3, data=random_data) # Display the random data on the line 3 on chart 302 | time.sleep(0.5) # Pause for 0.5 seconds before the next iteration 303 | 304 | # Call the display_data function as a separate thread 305 | threading.Thread(target=display_data).start() 306 | 307 | # Start the main event loop 308 | root.mainloop() 309 | ``` 310 | 311 | --- 312 | 313 | - **Advance** (Actually not, Just Two More Attributes Added) 314 | 315 | https://github.com/Thisal-D/ctkchart/assets/93121062/c2838fd6-3a0f-45be-bb39-9953d007067d 316 | 317 | ``` python 318 | import tkinter as tk # Importing the tkinter library as tk 319 | import tkchart # Importing the tkchart module for chart creation 320 | import random # Importing the random module for generating random data 321 | import threading # Importing the threading module for running tasks concurrently 322 | import time # Importing the time module for adding delays 323 | 324 | # Create the root window and configure 325 | root = tk.Tk() 326 | root.configure(bg = "#0d1117") 327 | root.geometry("720x430+200+200") 328 | 329 | # Create a line chart widget 330 | line_chart = tkchart.LineChart( 331 | master=root, # Set the master as the root window 332 | 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 333 | y_axis_values=(0, 1000), # Y-axis values (range) 334 | y_axis_label_count=10, # set y axis labels count to 1 335 | y_axis_section_count=10, 336 | x_axis_section_count=10, 337 | ) 338 | 339 | line_chart.pack(pady=15) # Pack the line chart widget into the root 340 | 341 | line1 = tkchart.Line( 342 | master=line_chart, # Set the master as the line chart 343 | color="#5dffb6", # index 0 for light and 1 for dark theme 344 | size=2, # Set the line size to 2 345 | style="dashed", # style change to dashed 346 | style_type=(10, 5), #index 0 for dash width and 1 for space between dashes 347 | ) 348 | 349 | line2 = tkchart.Line( 350 | master=line_chart, # Set the master as the line chart 351 | color="#FFBAD2", # index 0 for light and 1 for dark theme 352 | size=2, # Set the line size to 2 353 | point_highlight="enabled", # enable point highlight 354 | point_highlight_color="#FFBAD2", # enable point highlight 355 | ) 356 | 357 | def display_data(): 358 | """Function to continuously display random data on the line chart.""" 359 | while True: 360 | random_data = [random.choice(range(0, 1000))] # Generate random data between 0 and 1000 361 | line_chart.show_data(line=line1, data=random_data) # Display the random data on the line 1 on chart 362 | random_data = [random.choice(range(0, 1000))] # Generate random data between 0 and 1000 363 | line_chart.show_data(line=line2, data=random_data) # Display the random data on the line 2 on chart 364 | time.sleep(0.5) # Pause for 0.5 seconds before the next iteration 365 | 366 | # Call the display_data function as a separate thread 367 | threading.Thread(target=display_data).start() 368 | 369 | # Start the main event loop 370 | root.mainloop() 371 | ``` 372 | 373 | --- 374 | 375 | **Explore customizable features such as colors, fonts, and more in the documentation.** 376 | 377 | #### Please refer to the full documentation 378 | - [**English doc.**](documentation/DOCUMENTATION_en.md) 379 | - [**Chinese doc.**](documentation/DOCUMENTATION_zh.md) 380 | 381 | --- 382 | 383 | #### Contributors 384 | - [](https://github.com/childeyouyu) [youyu](https://github.com/childeyouyu) 385 | -------------------------------------------------------------------------------- /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 | * 安装 15 | ``` 16 | pip install tkchart 17 | ``` 18 | 19 | * 使用 20 | ``` python 21 | import tkchart 22 | ``` 23 | 24 |
    25 | 26 | --- 27 | 28 |
    29 | 30 | ### 参数概述 31 | 32 |
    33 | 34 | 35 | 36 | 37 | 38 | 39 |
    40 | 41 |
    42 | 43 | --- 44 | 45 | ### 要使用 tkchart 显示数据,您需要执行以下三步: 46 | 1. **创建折线图** 47 | 2. **创建一条线** 48 | 3. **数据显示** 49 | 50 | 51 | --- 52 | 53 |
    54 | 55 | ## 1 . 创建折线图 56 | **创建一条线** | **数据显示** 57 | 58 | ``` python 59 | linechart = tkchart.LineChart() 60 | ``` 61 | 62 | ### 参数 63 | 64 | | 参数 | 必备参数 / 可选参数 | 描述 | 数据类型 | 示例值 | 65 | |-------------------------------------------------------------|-------------|--------------------|---------------------------------|-------------------------------------| 66 | | master | ***必须*** | 折线图主体 | ``widget`` | widget | 67 | | y_axis_values | ***必须*** | y 轴的最小值和最大值 | ``tuple[[int \| float], ...]`` | (-1000, 1000), ... | 68 | | x_axis_values | ***必须*** | x 轴的值 | ``tuple[any, ...]`` | (1, 2, 3, 4, 5), ... | 69 | | width | ***可选*** | 折线图的宽度 | ``int`` | 300, ... | 70 | | height | ***可选*** | 折线图的高度 | ``int`` | 100, ... | 71 | | axis_size | ***可选*** | 坐标轴宽度 | ``int`` | 1<= | 72 | | axis_color | ***可选*** | 坐标轴轴颜色 | ``str`` | "#2C2C2C" , "blue", ... | 73 | | bg_color | ***可选*** | 折线图的背景色 | ``str`` | "#191919", ... | 74 | | fg_color | ***可选*** | 折线图的前景色 | ``str`` | "#191919", ... | 75 | | data_font_style | ***可选*** | 坐标轴名称的字体样式 | ``tuple[str, int, str]`` | ("arial", 9, "bold"), ... | 76 | | axis_font_style | ***可选*** | 坐标轴文字的字体样式 | ``tuple[str, int, str]`` | ("arial", 8, "normal"), ... | 77 | | x_axis_data | ***可选*** | x_data 的值(x 坐标轴名称) | ``str`` | "X", ... | 78 | | y_axis_data | ***可选*** | y_data 的值(y 坐标轴名称) | ``any`` | "Y", ... | 79 | | x_axis_data_font_color | ***可选*** | x_data 的字体颜色 | ``str`` | "#707070", ... | 80 | | y_axis_data_font_color | ***可选*** | y_data 的字体颜色 | ``str`` | "#707070", ... | 81 | | x_axis_data_position | ***可选*** | x_data 的排布方式 | ``str`` ("top", "side") | "top" | 82 | | y_axis_data_position | ***可选*** | y_data 的排布方式 | ``str`` ("top", "side") | "top" | 83 | | x_axis_section_count | ***可选*** | x 轴上的网格线数 | ``int`` | 0<= | 84 | | y_axis_section_count | ***可选*** | y 轴上的网格线数 | ``int`` | 0<= | 85 | | x_axis_label_count | ***可选*** | x 轴标签数量 | ``int`` | 0<= | 86 | | y_axis_label_count | ***可选*** | y 轴标签数量 | ``int`` | 1<= | 87 | | x_axis_font_color | ***可选*** | x 轴标签的字体颜色 | ``str`` | "#606060", ... | 88 | | y_axis_font_color | ***可选*** | y 轴标签的字体颜色 | ``str`` | "#606060", ... | 89 | | x_axis_section_style | ***可选*** | x 轴上的网格线样式 | ``str`` ("normal", "dashed") | "normal" | 90 | | y_axis_section_style | ***可选*** | y 轴上的网格线样式 | ``str`` ("normal", "dashed") | "normal" | 91 | | x_axis_section_style_type | ***可选*** | x 轴上网格线的实线与空白的尺寸 | ``tuple[int, int]`` | (100, 50) , (50,50), ... | 92 | | y_axis_section_style_type | ***可选*** | y 轴上网格线的实线与空白的尺寸 | ``tuple[int, int]`` | (100, 50) | 93 | | x_axis_section_color | ***可选*** | x 轴上网格线的颜色 | ``str`` | "#2C2C2C", ... | 94 | | y_axis_section_color | ***可选*** | y 轴上网格线的颜色 | ``str`` | "#2C2C2C" | 95 | | y_axis_precision | ***可选*** | y 轴值的精度 | ``int`` | 0<= | 96 | | x_axis_display_values_indices
    | ***可选*** | 显示在 x 轴上的坐标值的索引 | ``tuple[int, ...]`` | (0, 1, 2, 3, 4, 5), ... | 97 | | x_axis_point_spacing | ***可选*** | 线条宽度 | ``int`` \| ``str`` "auto" | "auto"
    1<= | 98 | | x_space | ***可选*** | x 轴和图表区域之间的空间 | ``int`` | 0<= | 99 | | y_space | ***可选*** | y 轴和图表区域之间的空间 | ``int`` | 0<= | 100 | | pointer_state | ***可选*** | 鼠标状态 | ``str`` ("enabled", "disabled") | "disabled" | 101 | | pointing_callback_function | ***可选*** | 鼠标的回调函数 | ``callable`` | function(*args)
    function(x, y) | 102 | | pointer_color | ***可选*** | 鼠标颜色 | ``str`` | "#606060", ... | 103 | | pointing_values_precision | ***可选*** | 指向值的精度 | ``int`` | 0<= | 104 | | pointer_lock | ***可选*** | 鼠标锁状态 | ``str`` ("enabled", "disabled") | "enabled" | 105 | | pointer_size | ***可选*** | 鼠标显示线的宽度 | ``int`` | 1<= | 106 | 107 | 108 | --- 109 | 110 | ### 方法 111 | 112 | | 方法 | 描述 | 支持的参数 / 必须的参数 | 返回类型 | 113 | |----------------------------|---------------------|----------------------------------------------------------------------------------------------------------------------------------|----------| 114 | | configure | 更改 LineChart(折线图)属性 | 所有属性,除了 master | ``None`` | 115 | | [show_data](#display-data) | 显示数据 | data: ``list``
    line: ``chart.Line`` | ``None`` | 116 | | place | 放置 (place) 折线图 | x: ``int``
    y: ``int``
    rely: ``float or int``
    relx: ``float or int``
    anchor: ``str`` | ``None`` | 117 | | pack | 放置 (pack) 折线图 | pady: ``int``
    padx: ``int``
    before: ``widget``
    after: ``widget``
    side: ``str``
    anchor: ``str`` | ``None`` | 118 | | grid | 放置 (grid) 折线图 | column: ``int``
    columnspan: ``int``
    padx: ``int``
    pady: ``int``
    row: ``int``
    rowspan: ``int``
    sticky: ``str`` | ``None`` | 119 | | place_forget | Place 忘编号 | - | ``None`` | 120 | | pack_forget | Pack 忘编号 | - | ``None`` | 121 | | grid_forget | Grid 忘编号 | - | ``None`` | 122 | | set_lines_visibility | 更改所有线条的可见性 | state: ``bool`` | ``None`` | 123 | | set_line_visibility | 更改特定行的可见性 | line: ``tkchart.Line``
    state: ``bool`` | ``None`` | 124 | | get_line_visibility | 获取特定生产线的可见性 | line: ``tkchart.Line`` | ``bool`` | 125 | | reset | 重置折线图 | - | ``None`` | 126 | | cget | 获取指定参数的值。 | attribute_name: ``str`` \| "\_\_all\_\_" | ``any`` | 127 | | place_info | 获取地点信息 | attribute_name: ``str`` \| "\_\_all\_\_" | ``any`` | 128 | | pack_info | 获取有关包装的信息 | attribute_name: ``str`` \| "\_\_all\_\_" | ``any`` | 129 | | grid_info | 获取网格信息 | attribute_name: ``str`` \| "\_\_all\_\_" | ``any`` | 130 | | get_line_area | 获取特定线的面积 | line: `tkchart.Line` | `float` | 131 | | get_lines_area | 获取所有线的面积 | - | `float` | 132 | | clear_data | 清除图表中所有线的数据,确保只保留最新的可见数据点。如果数据点总数超过最大可见点,则会从每条线的数据中移除旧数据。此方法确保图表仅显示基于最大可见范围的相关数据部分。 | - | ``None`` | 133 | | destroy | 销毁图表 | - | ``None`` | 134 | | get_lines_data | 获取指定范围内所有线条的数据点,可以选择步长值。 | start: `int`
    end: `int`
    step: `int` | `Dict[tkchart.Line, Tuple[int]]` | 135 | | get_line_data | 获取指定范围和步长值下某一条线的数据点。 | line: `tkchart.Line`
    start: `int`
    end: `int`
    step: `int` | `Tuple[int \| float]` | 136 | | get_x_axis_visible_point_count | 获取X轴上可见数据点的最大数量。 | - | `int` | 137 | | get_lines_visible_data | 获取所有线条当前可见的数据点,基于最大数据长度和可见点数。 | - | `Dict[tkchart.Line, Tuple[int \| float]]` | 138 | | get_line_visible_data | 获取某一条线当前可见的数据点。 | line: `tkchart.Line` | `Tuple[int \| float]` | 139 | 140 | 141 | 142 | --- 143 | 144 |
    145 | 146 | ## 2 . 创建一条线 147 | 148 | **创建折线图** | **数据显示** 149 | 150 | ``` python 151 | line = tkchart.Line() 152 | ``` 153 | 154 | ### 参数 155 | 156 | | 参数名称 | 必备参数 / 可选参数 | 描述 | 数据类型 | 示例值 | 157 | |-------------------------------------------|-------------|----------------|----------------------------------------|--------------| 158 | | master | 必须 | 主控制器 | ``tkchart.Line`` | LineChart 对象 | 159 | | [color](#line_color_size) | 可选 | 折线颜色 | ``str`` | "#768df1" | 160 | | [size](#line_color_size) | 可选 | 折线大小 | ``int`` | 1<= | 161 | | [style](#line_style) | 可选 | 折线样式(普通、虚线、点线) | ``str`` ("normal", "dashed", "dotted") | "normal" | 162 | | [style_type](#line_style_type) | 可选 | 实线与虚线尺寸 | ``tuple[int, int]`` | (10, 5) 等 | 163 | | [point_highlight](#point_highlight) | 可选 | 端点高亮状态 | ``str`` ("enabled", "disabled") | "disabled" | 164 | | [point_highlight_size](#point_highlight) | 可选 | 高亮点大小 | ``int`` | 1<= | 165 | | [point_highlight_color](#point_highlight) | 可选 | 高亮点颜色 | ``str`` | "#768df1" | 166 | | [fill](#fill) | 可选 | 是否启用填充 | ``str`` ("enabled", "disabled") | "disabled" | 167 | | [fill_color](#fill) | 可选 | 填充颜色 | ``str`` | "#5d6db6" | 168 | 169 | --- 170 | 171 | ### 方法 172 | 173 | | 方法 | 描述 | 支持的参数 | 返回类型 | 174 | |----------------|----------|------------------------------------------|----------| 175 | | configure | 更改折线图属性 | 所有属性,除了 master | ``None`` | 176 | | cget | 获取指定参数的值 | attribute_name: ``str`` \| "\_\_all\_\_" | ``any`` | 177 | | reset | 重置线对象 | - | ``None`` | 178 | | set_visible | 改变线条的可见度 | state: ``bool`` | ``None`` | 179 | | get_visibility | 获得线路的可见度 | - | ``bool`` | 180 | | clear_data | 清除特定线的数据,确保只保留最新的可见数据点。如果线的数据超过最大可见点,则会修剪旧数据。此方法允许每条线独立清除其数据,确保它始终保持在可见范围内。 | - | ``None`` | 181 | | destroy | 破坏线 | - | ``None`` | 182 | | get_data | 获取指定范围的数据点,可以选择步长值。如果没有提供参数,将返回所有可用数据。 | start: `int`
    end: `int`
    step: `int` | `Tuple[int \| float]` | 183 | | get_current_visible_data | 根据所有线条的最大数据长度和最大可见点数,返回当前可见的数据点。 | - | `Tuple[int \| float]` | 184 | | get_x_axis_visible_point_count | 获取X轴上可见数据点的最大数量。 | - | `int` | 185 | 186 |
    187 | 188 | --- 189 | 190 |
    191 | 192 | ## 3 . 数据显示 193 | 194 | **创建折线图** | **创建一条折线** 195 | 196 | 197 | ``` python 198 | import tkinter as tk 199 | import tkchart 200 | import random 201 | 202 | ## root 203 | root = tk.Tk() 204 | root.configure(bg="#151515") 205 | 206 | ## 创建折线图 207 | chart = tkchart.LineChart( 208 | master=root, 209 | x_axis_values = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10), 210 | y_axis_values = (-100,100) 211 | ) 212 | chart.pack() 213 | 214 | ## 创建一条折线 215 | line = tkchart.Line(master=chart) 216 | 217 | data = [x for x in range(-100,101)] #values -100 to 100 218 | ## 显示数据(随机) 219 | def loop(): 220 | chart.show_data(line=line, data=random.choices(data, k=1)) 221 | root.after(500, loop) 222 | loop() 223 | 224 | root.mainloop() 225 | ``` 226 | 227 |
    228 | 229 | https://github.com/Thisal-D/tkchart/assets/93121062/64440c23-63e6-4093-b027-21b00a6f5518 230 | 231 | --- 232 | 233 |
    234 | 235 |
    236 | 237 | 238 |
    239 | 240 | **返回顶部** | **使用指南** | **例子** | **查看新功能** 241 | 242 | ## 参数说明 243 | 244 |
    245 | 246 | ### LineChart 247 | 248 | - #### y_axis_values 249 | y_axis_values 是一个包含两个数值的元组。第一个值(索引 0)表示 y 轴的起始值,第二个值(索引 1)表示 y 轴的结束值。该元组定义了折线图上沿 y 轴显示的值的范围。 250 | 251 | - #### x_axis_values 252 | x_axis_values 是可以包含任何数据类型的值的集合。这些值被分配给 x 轴,从索引 0 开始一直到 x_axis_values 元组的最后一个索引。元组中的每个值对应于折线图中 x 轴上的一个点。 253 | 254 | 255 | 256 | 257 | 258 | 259 | ``` python 260 | chart = tkchart.LineChart( 261 | master=any_widget, 262 | x_axis_values=(2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025), 263 | y_axis_values=(-100, 100) 264 | ) 265 | ``` 266 | 267 | --- 268 | 269 |
    270 | 271 |
    272 | 273 | - #### x_axis_data 274 | 指折线图 x 轴上显示的值类型。 275 | **注意:"X"为默认值。** 276 | 277 | - #### y_axis_data 278 | 指折线图 y 轴上显示的值类型。 279 | **注意:"Y" 是默认值。** 280 | 281 | - #### x_axis_data_font_color 282 | 指应用于表示折线图 x_axis_data 的标签的字体颜色。 283 | 284 | - #### y_axis_data_font_color 285 | 指应用于表示折线图 y_axis_data 的标签的字体颜色。 286 | 287 | - #### data_font_style 288 | 指应用于代表折线图 x_axis_data 和 y_axis_data 的标签的字体样式。 289 | 290 | 291 | 292 | 293 | 294 | 295 | ``` python 296 | chart = tkchart.LineChart( 297 | master=any_widget, 298 | x_axis_values=(2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025), 299 | y_axis_values=(-100, 100), 300 | y_axis_data="Y data" , 301 | x_axis_data="X data", 302 | x_axis_data_font_color="#ff0000", 303 | y_axis_data_font_color="#00ff00", 304 | data_font_style=("arial", 15, "underline") 305 | ) 306 | ``` 307 | 308 | --- 309 | 310 |
    311 | 312 |
    313 | 314 | - #### x_axis_label_count 315 | 当您有一组 x_value(例如从 2018 年到 2025 年)时,通常会显示所有这些标签。但有时为了更清晰起见,您可能只想显示其中的几个。
    316 | 例如,如果您将 x_axis_label_count 设置为 4,则意味着您只想显示 4 个标签,而不是全部 8 个。因此,折线图将自动跳过一些标签以适合您指定的数量。
    317 | **注意:len(x_axis_values) 是默认值。**
    318 | 换句话说,调整 x_axis_label_count 可以让您控制 x 轴上显示的标签数量,使您的可视化更清晰、更易于理解。 319 |
    320 | -**如果有 9 个标签,您可以将其限制为:3、1。** 321 | -**如果有 20 个标签,您可以将其限制为:10, 5, 4, 2, 1。** 322 | -**如果有 15 个标签,您可以将其限制为:5、3、1。** 323 | 324 | #### 在某些情况下,使用 x_axis_label_count 参数可能不足以满足您的需求。在这种情况下,您可以利用 x_axis_display_values_indices 参数来精确控制 x 轴上显示的值。 325 | 326 | - #### y_axis_label_count 327 | 默认情况下,如果将 y 轴值设置为 -100 到 100 范围,则 y 轴上将仅显示极值(-100 和 100 两个数字)。但是,您可以选择使用 y_axis_label_count 参数调整显示的标签数量。
    328 | 例如,如果将 y_axis_label_count 设置为 3,系统会将 y 轴范围(-100 到 100)划分为相等的间隔,并按这些间隔显示标签。因此,对于本例,标签计数为 3,您可能会看到 -100、0 和 100 处的标签。
    329 | 总之,调整 y_axis_label_count 参数允许您控制 y 轴上显示的标签数量,从而可以根据您的偏好和要求灵活地自定义可视化效果。 330 | 331 | 332 | 333 | 334 | 335 | 336 | ``` python 337 | chart = tkchart.LineChart( 338 | master=any_widget, 339 | x_axis_values=(2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025), 340 | y_axis_values=(-100, 100), 341 | x_axis_label_count=4, 342 | y_axis_label_count=10 343 | ) 344 | ``` 345 | 346 | --- 347 | 348 |
    349 | 350 |
    351 | 352 | - #### x_axis_display_values_indices 353 | 假设您有一组代表从 2018 年到 2025 年的 x 轴值:(2018、2019、2020、2021、2022、2023、2024、2025)。通常,所有这些值都会显示在 x 轴上。
    354 | 但是,在某些情况下,您可能只想显示特定年份而不是全部。在这种情况下,您可以使用 x_axis_display_values_indices 参数来控制在 x 轴上显示哪些值。
    355 | 例如,如果您只想显示 2019 年、2022 年和 2025 年,则可以在 x_axis_display_values_indices 参数中指定它们的索引。因此,如果 2019 年的索引为 1、2022 年为 4、2025 年为 7(假设基于 0 的索引),则您可以将 x_axis_display_values_indices 设置为 (1, 4, 7)。
    356 | 这样,通过设置要显示的值的索引,您可以精确控制可视化中 X 轴上显示的值,从而允许您根据您的特定要求对其进行定制。 357 | 358 | 359 | 360 | 361 | 362 | 363 | ``` python 364 | chart = tkchart.LineChart( 365 | master=any_widget, 366 | x_axis_values=(2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025), 367 | y_axis_values=(-100, 100), 368 | x_axis_display_values_indices=(1, 4, 7) 369 | ) 370 | ``` 371 | 372 | --- 373 | 374 |
    375 | 376 |
    377 | 378 | - #### x_axis_data_position 379 | x_axis_data_position 参数确定 x_axis_data 的文字布局。 380 | 381 | 它有两个支持的值: 382 | - "top" 383 | - "side" 384 | 385 | **注意:“top”是默认位置** 386 | 387 | - #### y_axis_data_position 388 | y_axis_data_position 参数确定 y_axis_data 的文字布局。 389 | 390 | 它有两个支持的值: 391 | - "top" 392 | - "side" 393 | 394 | **注意:“top”是默认位置** 395 | 396 |
    397 | 398 | 在"top"、"side"之间进行选择分别确定 x/y_axis_data 是水平放置在数据点上方还是垂直放置在数据点旁边。此参数允许您根据您的喜好和可用空间自定义折线图的布局。 399 | 400 | 401 | 402 | 403 | 404 | 405 | ``` python 406 | chart = tkchart.LineChart( 407 | master=any_widget, 408 | x_axis_values=(2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025), 409 | y_axis_values=(-100, 100), 410 | x_axis_data_position="side", 411 | y_axis_data_position="top" 412 | ) 413 | ``` 414 | 415 | --- 416 | 417 |
    418 | 419 |
    420 | 421 | - #### y_axis_precision 422 | y_axis_ precision 参数控制 y 轴上的值显示的小数位数。
    423 | **注意:1 是默认精度**
    424 | 例如: 425 | - 如果将 y_axis_precision 设置为 0,则 y 轴上的值将显示为整数。
    426 | - 如果将 y_axis_precision 设置为 1,则 y 轴上的值将显示一位小数。
    427 | - 如果将 y_axis_precision 设置为 2,则 y 轴上的值将显示两位小数。 428 |
    429 | 430 | 此外 : 431 | - **调整 y_axis_ precision 参数允许您控制折线图中 y 轴值的精度级别。当处理需要特定精度的数据或当您想要通过减少显示的小数位数来提高折线图的可读性时,此参数特别有用。** 432 | 433 | 434 | 435 | 436 | 437 | 438 | ``` python 439 | chart = tkchart.LineChart( 440 | master=any_widget, 441 | x_axis_values=(2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025), 442 | y_axis_values=(-100, 100), 443 | y_axis_label_count=12, 444 | y_axis_precision=4, 445 | ) 446 | ``` 447 | 448 | --- 449 | 450 |
    451 | 452 |
    453 | 454 | - #### axis_font_style 455 | 指 x 和 y 轴值的字体样式 456 | 457 | - #### x_axis_font_color 458 | 指 x 轴值的颜色 459 | 460 | - #### y_axis_font_color 461 | 指 y 轴值的颜色 462 | 463 | 464 | 465 | 466 | 467 | 468 | ``` python 469 | chart = tkchart.LineChart( 470 | master=any_widget, 471 | x_axis_values=(2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025), 472 | y_axis_values=(-100, 100), 473 | x_axis_font_color="#00FF00", 474 | y_axis_font_color="#FF0000", 475 | axis_font_style=("arial", 13, "bold") 476 | ) 477 | ``` 478 | 479 | --- 480 | 481 |
    482 | 483 |
    484 | 485 |
    486 | 487 | - #### x_axis_section_count 488 | x_axis_section_count 参数定义折线图中 x 轴范围将划分为的部分或间隔的数量。
    489 | **这里有更清晰的细分:** 490 | - 假设 x 轴上有一系列值,例如从 2018 年到 2025 年。默认情况下,此范围可能表示为连续线,没有标记任何特定部分或间隔。 491 | - 但是,如果将 x_axis_section_count 设置为一个值,例如 8,则意味着您想要将此 x 轴范围划分为等间距的部分或间隔。每个部分将代表总 x 轴范围的一个子集。 492 | - 调整 x_axis_section_count 参数允许您控制折线图中 x 轴的粒度,使查看者更容易解释数据并识别特定间隔内的趋势。 493 | 494 |
    495 | 496 | - #### y_axis_section_count 497 | y_axis_section_count 参数定义折线图中 y 轴范围将划分为的部分或间隔的数量。
    498 | **请参阅:x_axis_section_count** 了解更多... 499 | 500 | - #### x_axis_section_color 501 | 指 y 轴网格线的颜色 502 | 503 | - #### y_axis_section_color 504 | 指 x 轴网格线的颜色 505 | 506 | 507 | 508 | 509 | 510 | 511 | ``` python 512 | chart = tkchart.LineChart( 513 | master=any_widget, 514 | x_axis_section_count=8, 515 | y_axis_section_count=5, 516 | x_axis_section_color="#2C2C2C", 517 | y_axis_section_color="#2C2C2C" 518 | ) 519 | ``` 520 | 521 | --- 522 | 523 |
    524 | 525 |
    526 | 527 |
    528 | 529 | - #### x_axis_section_style 530 | x_axis_section_style 参数允许您定义折线图中沿 x 轴的部分的视觉样式。 531 | 532 | - 支持的样式: 533 | - "dashed": 当您将 x_axis_section_style 设置为“dashed”时,沿 x 轴的剖面将使用虚线显示。 534 | - "normal": 相反,当 x_axis_section_style 设置为“正常”时,沿 x 轴的截面将使用实线显示。 535 |
    536 | 537 | **注意:"normal"是默认样式。** 538 | 539 |
    540 | 541 | - #### y_axis_section_style 542 | 与 x_axis_section_style 工作方式相同, 543 | 有关更多信息,请参阅 x_axis_section_style 544 | 545 |
    546 | 547 | - #### x_axis_section_style_type 548 | x_axis_section_style_type 参数是一个包含两个整数值的元组,指定当 x_axis_section_style 设置为“dashed”时使用的破折号样式。
    549 | 例如:
    550 | - 如果将 x_axis_section_style_type 设置为 (20, 10),则意味着: 551 | - 每个破折号的宽度为 20 像素。 552 | - 破折号之间的间距为 10 553 |
    554 | 555 | 556 | 这些值确定用于表示沿 x 轴的部分的虚线或标记的视觉外观。通过调整这些值,您可以根据您的偏好或可视化要求自定义虚线部分的外观。 557 | 558 |
    559 | 560 | - #### y_axis_section_style_type 561 | 与 x_axis_section_style_type 工作相同, 562 | 请参阅 x_axis_section_style_type 了解更多信息 563 | 564 | 565 | 566 | 567 | 568 | 569 | ``` python 570 | chart = tkchart.LineChart( 571 | master=any_widget, 572 | x_axis_section_count=8, 573 | y_axis_section_count=5, 574 | x_axis_section_style="dashed", 575 | x_axis_section_style_type=(20,10), 576 | y_axis_section_style="dashed", 577 | y_axis_section_style_type=(20,10), 578 | ) 579 | ``` 580 | 581 | --- 582 | 583 |
    584 | 585 | 586 |
    587 | 588 | - #### x_axis_point_spacing 589 | x_axis_point_spacing 参数允许您手动设置 x 轴上点之间的间距,通常以像素为单位测量。但是,如果您不手动设置该参数,则会根据 x_axis_values 的长度自动计算。 590 |
    591 | **注意:"auto"是默认值。** 592 |
    593 | 594 | - 将特定值配置为 x_axis_point_spacing 后,您可以通过将其配置为"auto"来重置值以设置默认值。 595 |
    596 | ``` python 597 | chart.configure( 598 | x_axis_point_spacing="auto" 599 | ) 600 | ``` 601 | 602 | 603 | 604 | 605 | 606 | 607 | ``` python 608 | chart = tkchart.LineChart( 609 | master=any_widget, 610 | x_axis_point_spacing="auto" 611 | ) 612 | ``` 613 | 614 | x_axis_point_spacing 参数是根据 x_axis_values 元组的长度自动计算的。这意味着 x 轴上点之间的间距是通过将折线图的宽度除以 x_axis_values 列表的长度来确定的。 615 | 616 | 617 | 618 | 619 | 620 | 621 | 当您将 x_axis_point_spacing 参数设置为特定值(例如 40)时,这意味着您已手动将 x 轴上的点之间的间距指定为 40 个单位(例如像素)。在这种情况下,无论 x_axis_values 元组的长度如何,折线图都将在 x 轴上的每个点之间使用用户定义的 40 个单位的间距。 622 | 623 | ``` python 624 | chart = tkchart.LineChart( 625 | master=any_widget, 626 | x_axis_point_spacing=40 627 | ) 628 | ``` 629 | 630 | --- 631 | 632 |
    633 | 634 | ### Line 635 | 636 |
    637 | 638 | - #### color 639 | 指的是线条的颜色。 640 | 641 | - #### size 642 | 指线条的尺寸(粗细)。
    643 | **注:1 为默认尺寸** 644 |
    645 | 646 | 647 | 648 | 649 | 650 | 651 | ``` python 652 | line = tkchart.Line( 653 | master=chart, 654 | color="#30ACC7", 655 | size=5 656 | ) 657 | ``` 658 | 659 | --- 660 | 661 |
    662 | 663 |
    664 | 665 | - #### style 666 | style 参数允许您定义线条的视觉样式。 667 |
    668 | - 支持的样式: 669 | - "dashed": 当样式设置为"dashed"时,折线条显示为虚线。 670 | - "dotted": 当样式设置为"dotted"时,折线显示为点虚线。 671 | - "normal": 当样式设置为"normal"时,线条显示为实线。 672 |
    673 | **注意:"normal"是默认样式。** 674 | 675 | 676 | 677 | 678 | 679 | 680 | ``` python 681 | line = tkchart.Line( 682 | master=chart, 683 | line_style="dashed" 684 | ) 685 | ``` 686 | 687 | --- 688 | 689 |
    690 | 691 |
    692 | 693 | - #### style_type 694 | style_type 参数是一个包含两个整数值的元组,指定样式设置为"dashed"或"dotted"时使用的破折号和点的样式。 695 | 696 | 例如: 697 | - 如果将 style_type 设置为 (20, 10),则意味着: 698 | - 每个破折号的宽度或每个点的大小为 20 像素。 699 | - 破折号或点之间的间距为 10 个像素。 700 | 701 | **注意 在"dotted"风格下 , size 参数无关紧要,因为点的大小是由 style_type 元组确定的固定大小。**
    702 | **注意 在"normal"风格下,style_type 参数无效。** 703 | 704 | 705 | 706 | 707 | 708 | 709 | ``` python 710 | line = tkchart.Line( 711 | master=chart, 712 | line_style="dashed", 713 | line_style_type=(10,2) 714 | ) 715 | ``` 716 | 717 | --- 718 | 719 |
    720 | 721 |
    722 | 723 | - #### point_highlight 724 | point_highlight 参数用于控制点高亮。 725 |
    726 | - 支持的值: 727 | - "enabled": 启用点高亮显示。 728 | - "disabled": 禁用点高亮显示。 729 | 730 | - #### point_highlight_size 731 | point_highlight_size 用于设置高亮点的大小。 732 | 733 | - #### point_highlight_color 734 | 高亮点的颜色。 735 | 736 | 737 | 738 | 739 | 740 | 741 | ``` python 742 | line = tkchart.Line( 743 | master=chart, 744 | point_highlight="enabled", 745 | point_highlight_color="#80CCFF", 746 | point_highlight_size=8 747 | ) 748 | ``` 749 | 750 | --- 751 | 752 |
    753 | 754 |
    755 | 756 | - #### fill 757 | fill 参数用于控制是否启用或禁用行填充。 758 |
    759 | - 支持的值: 760 | - "enabled": 启用线条填充。 761 | - "disabled": 禁用线条填充。 762 | 763 | - #### fill_color 764 | fill_color 参数用于指定填充的颜色。 765 | 766 | 767 | 768 | 769 | 770 | 771 | ``` python 772 | line = tkchart.Line( 773 | master=chart, 774 | fill="enabled", 775 | fill_color="#5D6DB6" 776 | ) 777 | ``` 778 | 779 |
    780 | 781 | --- 782 | 783 |
    784 | 785 | **回到顶部** | **使用指南** | **参数说明** | **查看新功能** 786 | 787 | ## [例子](https://github.com/Thisal-D/tkchart/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 | ## 链接 812 | 813 | **PyPi.org** : tkchart 814 | 815 | **GitHub.com** : tkchart 816 | 817 | --- 818 | 819 | ### 翻译贡献 820 | 821 | **翻译支持** : [有语](https://github.com/childeyouyu) 822 | 823 | **Translation by** : [youyu](https://github.com/childeyouyu) -------------------------------------------------------------------------------- /tests/main test.py: -------------------------------------------------------------------------------- 1 | import tkchart 2 | try: 3 | import customtkinter as ctk 4 | except : 5 | try: 6 | import os 7 | os.system("pip install customtkinter") 8 | os.system("pip install customtkinter --upgrade") 9 | except: 10 | pass 11 | import random 12 | 13 | root = ctk.CTk() 14 | root.geometry("1900x900") 15 | 16 | 17 | data = ([x for x in range(-1000,1001)]) 18 | x_axis_values = tuple([x for x in range(1,31)]) 19 | line_chart = tkchart.LineChart(master=root, fg_color="#101010", bg_color="#101010", 20 | x_axis_data='', y_axis_data="", 21 | width=900, height=350, 22 | axis_size=1, y_axis_precision=0, 23 | x_axis_values=x_axis_values, y_axis_values=(-1000, 1001), 24 | x_axis_label_count=20, y_axis_label_count=10, 25 | x_axis_section_count=10, y_axis_section_count=10, 26 | y_space=10, x_space=10, ) 27 | line_chart.pack() 28 | line = tkchart.Line(master=line_chart, style="normal", style_type=(10,5), size=2, color="lightblue", 29 | point_highlight="enabled", point_highlight_size=6, fill="enabled", fill_color="#707070", 30 | point_highlight_color="lightblue") 31 | 32 | def loop(): 33 | line_chart.show_data(line=line ,data=[random.choice(data)]) 34 | root.after(500, loop) 35 | loop() 36 | 37 | 38 | 39 | 40 | #line_chart.show_data(line=line ,data=[0,200,400,600,800,1000,800,600,400,200]) 41 | #line_chart.show_data(line=line ,data=[0,200,0,600,200,1000,400,600,1000,0]) 42 | 43 | 44 | frame = ctk.CTkScrollableFrame(master=root, width=1000, height=900, fg_color=("#FFFFFF","#151515")) 45 | frame.pack(pady=100) 46 | 47 | def line_chart_configure(**kwrgs): 48 | line_chart.configure(**kwrgs) 49 | 50 | def line_configure(**kwrgs): 51 | line.configure(**kwrgs) 52 | 53 | 54 | row = 1 55 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Line Chart Attributes : ", font=("Arial",25,"bold")).grid(row=row, column=1) 56 | row += 1 57 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Width : ").grid(row=row, column=1) 58 | column = 2 59 | for width in range(900,1600,100): 60 | 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) 61 | column += 1 62 | 63 | row += 1 64 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 65 | row += 1 66 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Height : ").grid(row=row, column=1) 67 | column = 2 68 | for height in range(350,900,50): 69 | 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) 70 | column += 1 71 | 72 | row += 1 73 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 74 | row += 1 75 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Axis Size : ").grid(row=row, column=1) 76 | column = 2 77 | for axis_size in range(1,9,1): 78 | 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) 79 | column += 1 80 | 81 | row += 1 82 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 83 | row += 1 84 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Y Axis Labels : ").grid(row=row, column=1) 85 | column = 2 86 | for y_axis_label_count in range(0,14,2): 87 | 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) 88 | column += 1 89 | 90 | row += 1 91 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 92 | row += 1 93 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="X Axis Labels : ").grid(row=row, column=1) 94 | column = 2 95 | for x_axis_label_count in [0, 1, 2, 4, 5, 10, 20]: 96 | 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) 97 | column += 1 98 | 99 | row += 1 100 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 101 | row += 1 102 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Y Axis Precision : ").grid(row=row, column=1) 103 | column = 2 104 | for y_axis_precision in range(0,9,1): 105 | 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) 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 values : ").grid(row=row, column=1) 112 | column = 2 113 | values = [(-1000, 1000), (0, 1000), (-2000, 1000), (0, 2000), (-5000,2000)] 114 | for i in range(5): 115 | 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) 116 | column += 1 117 | 118 | row += 1 119 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 120 | row += 1 121 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="X Axis Values : ").grid(row=row, column=1) 122 | column = 2 123 | for x_axis_values in range(1, 90, 10): 124 | ctk.CTkButton(master=frame, text="range({},{})".format(x_axis_values,x_axis_values+20), width=90, height=30, command=lambda x_axis_values_=[x for x in range(x_axis_values,x_axis_values+20)]: line_chart_configure(x_axis_values=tuple(x_axis_values_))).grid(row=row, column=column, padx=10, pady=2) 125 | column += 1 126 | 127 | row += 1 128 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 129 | row += 1 130 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Y Axis Sections : ").grid(row=row, column=1) 131 | column = 2 132 | for y_axis_section_count in range(0, 14, 2): 133 | 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) 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="X Axis Sections : ").grid(row=row, column=1) 140 | column = 2 141 | for x_axis_section_count in range(0, 14, 2): 142 | 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) 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 xis point spacing : ").grid(row=row, column=1) 149 | 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) 150 | column = 3 151 | for x_axis_point_spacing in range(10, 40, 5): 152 | 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) 153 | column += 1 154 | 155 | row += 1 156 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 157 | row += 1 158 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Y Space : ").grid(row=row, column=1) 159 | column = 2 160 | for y_space in range(0, 90, 10): 161 | 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) 162 | column += 1 163 | 164 | row += 1 165 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 166 | row += 1 167 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="X Space : ").grid(row=row, column=1) 168 | column = 2 169 | for x_space in range(0, 90, 10): 170 | 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) 171 | column += 1 172 | 173 | row += 1 174 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 175 | row += 1 176 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Y Axis Data : ").grid(row=row, column=1) 177 | column = 2 178 | 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) 179 | column += 1 180 | 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) 181 | 182 | row += 1 183 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 184 | row += 1 185 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="X Axis Data : ").grid(row=row, column=1) 186 | column = 2 187 | 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) 188 | column += 1 189 | 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) 190 | 191 | row += 1 192 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 193 | row += 1 194 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="X Axis Data Position : ").grid(row=row, column=1) 195 | column = 2 196 | 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) 197 | column += 1 198 | 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) 199 | 200 | row += 1 201 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 202 | row += 1 203 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Y Axis Data Position : ").grid(row=row, column=1) 204 | column = 2 205 | 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) 206 | column += 1 207 | 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) 208 | 209 | row += 1 210 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 211 | row += 1 212 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Data Font Style : ").grid(row=row, column=1) 213 | column = 2 214 | 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) 215 | column += 1 216 | 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) 217 | column += 1 218 | 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) 219 | column += 1 220 | 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) 221 | 222 | row += 1 223 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 224 | row += 1 225 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Axis Font Style : ").grid(row=row, column=1) 226 | column = 2 227 | 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) 228 | column += 1 229 | 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) 230 | column += 1 231 | 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) 232 | column += 1 233 | 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) 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="X 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(x_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(x_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(x_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(x_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(x_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(x_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="Y Section Color : ").grid(row=row, column=1) 258 | column = 2 259 | 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) 260 | column += 1 261 | 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) 262 | column += 1 263 | 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) 264 | column += 1 265 | 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) 266 | column += 1 267 | 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) 268 | column += 1 269 | 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) 270 | column += 1 271 | 272 | 273 | row += 1 274 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 275 | row += 1 276 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="X Axis Section Style : ").grid(row=row, column=1) 277 | column = 2 278 | 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) 279 | column += 1 280 | 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) 281 | column += 1 282 | 283 | row += 1 284 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 285 | row += 1 286 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="X Axis Style Type : ").grid(row=row, column=1) 287 | column = 2 288 | 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) 289 | column += 1 290 | 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) 291 | column += 1 292 | 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) 293 | column += 1 294 | 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) 295 | column += 1 296 | 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) 297 | column += 1 298 | 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) 299 | column += 1 300 | 301 | row += 1 302 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 303 | row += 1 304 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Y Axis Section Style : ").grid(row=row, column=1) 305 | column = 2 306 | 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) 307 | column += 1 308 | 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) 309 | column += 1 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="Y Axis Style Type : ").grid(row=row, column=1) 315 | column = 2 316 | 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) 317 | column += 1 318 | 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) 319 | column += 1 320 | 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) 321 | column += 1 322 | 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) 323 | column += 1 324 | 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) 325 | column += 1 326 | 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) 327 | column += 1 328 | 329 | 330 | row += 1 331 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 332 | row += 1 333 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Axis Color : ").grid(row=row, column=1) 334 | column = 2 335 | 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) 336 | column += 1 337 | 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) 338 | column += 1 339 | 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) 340 | column += 1 341 | 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) 342 | column += 1 343 | 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) 344 | column += 1 345 | 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) 346 | column += 1 347 | 348 | row += 1 349 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 350 | row += 1 351 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="BG Color : ").grid(row=row, column=1) 352 | column = 2 353 | 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) 354 | column += 1 355 | 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) 356 | column += 1 357 | 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) 358 | column += 1 359 | 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) 360 | column += 1 361 | 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) 362 | column += 1 363 | 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) 364 | column += 1 365 | 366 | row += 1 367 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 368 | row += 1 369 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="FG Color : ").grid(row=row, column=1) 370 | column = 2 371 | 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) 372 | column += 1 373 | 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) 374 | column += 1 375 | 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) 376 | column += 1 377 | 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) 378 | column += 1 379 | 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) 380 | column += 1 381 | 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) 382 | column += 1 383 | 384 | row += 1 385 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 386 | row += 1 387 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Y Axis Font Color : ").grid(row=row, column=1) 388 | column = 2 389 | 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) 390 | column += 1 391 | 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) 392 | column += 1 393 | 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) 394 | column += 1 395 | 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) 396 | column += 1 397 | 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) 398 | column += 1 399 | 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) 400 | column += 1 401 | 402 | row += 1 403 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 404 | row += 1 405 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="X Axis Font Color : ").grid(row=row, column=1) 406 | column = 2 407 | 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) 408 | column += 1 409 | 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) 410 | column += 1 411 | 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) 412 | column += 1 413 | 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) 414 | column += 1 415 | 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) 416 | column += 1 417 | 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) 418 | column += 1 419 | 420 | row += 1 421 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 422 | row += 1 423 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Y Axis Data Font Color : ").grid(row=row, column=1) 424 | column = 2 425 | 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) 426 | column += 1 427 | 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) 428 | column += 1 429 | 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) 430 | column += 1 431 | 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) 432 | column += 1 433 | 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) 434 | column += 1 435 | 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) 436 | column += 1 437 | 438 | row += 1 439 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 440 | row += 1 441 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="X Axis Data Font Color : ").grid(row=row, column=1) 442 | column = 2 443 | 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) 444 | column += 1 445 | 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) 446 | column += 1 447 | 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) 448 | column += 1 449 | 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) 450 | column += 1 451 | 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) 452 | column += 1 453 | 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) 454 | column += 1 455 | 456 | row += 1 457 | ctk.CTkFrame(master=frame ,height=10, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 458 | 459 | row += 1 460 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Line Attributes : ", font=("Arial",25,"bold")).grid(row=row, column=1) 461 | 462 | row += 1 463 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 464 | row += 1 465 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Size : ").grid(row=row, column=1) 466 | column = 2 467 | 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) 468 | column += 1 469 | 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) 470 | column += 1 471 | 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) 472 | 473 | row += 1 474 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 475 | row += 1 476 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Style : ").grid(row=row, column=1) 477 | column = 2 478 | 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) 479 | column += 1 480 | 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) 481 | column += 1 482 | 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) 483 | 484 | 485 | row += 1 486 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 487 | row += 1 488 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Style Type : ").grid(row=row, column=1) 489 | column = 2 490 | 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) 491 | column += 1 492 | 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) 493 | column += 1 494 | 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) 495 | column += 1 496 | 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) 497 | column += 1 498 | 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) 499 | 500 | 501 | 502 | row += 1 503 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 504 | row += 1 505 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Color : ").grid(row=row, column=1) 506 | column = 2 507 | 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) 508 | column += 1 509 | 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) 510 | column += 1 511 | 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) 512 | column += 1 513 | 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) 514 | column += 1 515 | 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) 516 | 517 | 518 | 519 | row += 1 520 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 521 | row += 1 522 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Point Hightlight : ").grid(row=row, column=1) 523 | column = 2 524 | 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) 525 | column += 1 526 | 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) 527 | column += 1 528 | 529 | 530 | 531 | row += 1 532 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 533 | row += 1 534 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Point Hightlight Size : ").grid(row=row, column=1) 535 | column = 2 536 | 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) 537 | column += 1 538 | 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) 539 | column += 1 540 | 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) 541 | column += 1 542 | 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) 543 | column += 1 544 | 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) 545 | 546 | 547 | 548 | row += 1 549 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 550 | row += 1 551 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Point Hightlight Color : ").grid(row=row, column=1) 552 | column = 2 553 | 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) 554 | column += 1 555 | 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) 556 | column += 1 557 | 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) 558 | column += 1 559 | 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) 560 | column += 1 561 | 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) 562 | 563 | 564 | 565 | 566 | row += 1 567 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 568 | row += 1 569 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Fill : ").grid(row=row, column=1) 570 | column = 2 571 | 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) 572 | column += 1 573 | 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) 574 | column += 1 575 | 576 | 577 | 578 | row += 1 579 | ctk.CTkFrame(master=frame ,height=2, width=1000, fg_color=("#EEEEEE", "#202020")).grid(row=row, columnspan=9) 580 | row += 1 581 | ctk.CTkLabel(text_color=("black", "white"), master=frame, text="Point Hightlight Color : ").grid(row=row, column=1) 582 | column = 2 583 | 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) 584 | column += 1 585 | 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) 586 | column += 1 587 | 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) 588 | column += 1 589 | 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) 590 | column += 1 591 | 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) 592 | 593 | 594 | root.mainloop() --------------------------------------------------------------------------------