term-plot-mc 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Mehdi Maleki
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,194 @@
1
+ Metadata-Version: 2.4
2
+ Name: term-plot-mc
3
+ Version: 0.1.0
4
+ Summary: Draw simple plots and charts in the terminal using ASCII symbols
5
+ Author-email: Mehdi Maleki <mosioc79@gmail.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/mosioc/term-plot
8
+ Project-URL: Repository, https://github.com/mosioc/term-plot
9
+ Project-URL: Issues, https://github.com/mosioc/term-plot/issues
10
+ Keywords: terminal,ascii,plot,chart,visualization,cli
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.8
16
+ Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
+ Classifier: Topic :: Terminals
22
+ Requires-Python: >=3.8
23
+ Description-Content-Type: text/markdown
24
+ License-File: LICENSE
25
+ Dynamic: license-file
26
+
27
+ # Terminal Plot
28
+
29
+ > Draw beautiful plots and charts in your terminal using ASCII and Unicode symbols
30
+
31
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
32
+ [![Python 3.8+](https://img.shields.io/badge/python-3.8+-blue.svg)](https://www.python.org/downloads/)
33
+
34
+ ## Features
35
+
36
+ - **Bar Charts** - Horizontal and vertical bar charts for categorical data
37
+ - **Line Charts** - Single and multi-series line plots with automatic scaling
38
+ - **Scatter Plots** - Visualize correlations and relationships
39
+ - **Histograms** - Show data distributions with customizable bins
40
+ - **Dual Modes** - Beautiful Unicode symbols or ASCII for compatibility
41
+ - **Color Support** - Optional ANSI colors for better visualization
42
+ - **Zero Dependencies** - Pure Python, works anywhere
43
+ - **Lightweight** - Fast and minimal resource usage
44
+
45
+ ## Installation
46
+
47
+ ### From PyPI (once published)
48
+
49
+ ```bash
50
+ pip install term-plot
51
+ ```
52
+
53
+ ### From source
54
+
55
+ ```bash
56
+ git clone https://github.com/yourusername/term-plot.git
57
+ cd term-plot
58
+ pip install -e .
59
+ ```
60
+
61
+ ## Quick Start
62
+
63
+ ### Bar Chart
64
+
65
+ ```python
66
+ from term_plot import BarChart
67
+
68
+ # Simple horizontal bar chart
69
+ data = [23, 45, 12, 67, 34, 89, 56]
70
+ labels = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
71
+
72
+ chart = BarChart(data, labels=labels, title="Daily Sales", width=50)
73
+ print(chart.horizontal())
74
+
75
+ # Vertical bar chart
76
+ chart = BarChart(data, labels=labels, title="Daily Sales", height=15)
77
+ print(chart.vertical())
78
+ ```
79
+
80
+ ### Line Chart
81
+
82
+ ```python
83
+ from term_plot import LineChart
84
+
85
+ # Single series
86
+ data = [1, 3, 7, 4, 8, 6, 9, 12, 10]
87
+ chart = LineChart(data, title="Temperature Over Time", width=60, height=15)
88
+ print(chart.plot())
89
+
90
+ # Multiple series
91
+ data = {
92
+ "Product A": [5, 7, 9, 12, 15, 18, 20],
93
+ "Product B": [3, 5, 8, 10, 12, 15, 17]
94
+ }
95
+ chart = LineChart(data, title="Sales Comparison", width=70, height=20)
96
+ print(chart.plot())
97
+ ```
98
+
99
+ ### Scatter Plot
100
+
101
+ ```python
102
+ from term_plot import ScatterPlot
103
+
104
+ x_data = [1, 2, 3, 4, 5, 6, 7, 8, 9]
105
+ y_data = [2, 4, 3, 5, 7, 6, 8, 9, 8]
106
+
107
+ chart = ScatterPlot(x_data, y_data, title="Correlation Plot", width=50, height=15)
108
+ print(chart.plot())
109
+ ```
110
+
111
+ ### Histogram
112
+
113
+ ```python
114
+ from term_plot import Histogram
115
+ import random
116
+
117
+ # Generate sample data
118
+ data = [random.gauss(50, 15) for _ in range(1000)]
119
+
120
+ chart = Histogram(data, bins=15, title="Test Score Distribution", width=60, height=15)
121
+ print(chart.plot())
122
+ ```
123
+
124
+ ## Customization Options
125
+
126
+ ### ASCII vs Unicode
127
+
128
+ ```python
129
+ # Unicode mode (default) - prettier but requires Unicode support
130
+ chart = BarChart(data, labels=labels, use_unicode=True)
131
+
132
+ # ASCII mode - works everywhere
133
+ chart = BarChart(data, labels=labels, use_unicode=False)
134
+ ```
135
+
136
+ ### Colors
137
+
138
+ ```python
139
+ # With colors (default)
140
+ chart = BarChart(data, labels=labels, color=True)
141
+
142
+ # Without colors
143
+ chart = BarChart(data, labels=labels, color=False)
144
+ ```
145
+
146
+ ### Size Control
147
+
148
+ ```python
149
+ # Custom width and height
150
+ chart = LineChart(data, width=80, height=25)
151
+ ```
152
+
153
+ ## Examples
154
+
155
+ Check out the `examples/` directory for more:
156
+
157
+ - `bar_chart_example.py` - Various bar chart styles
158
+ - `line_chart_example.py` - Line chart examples including sine waves
159
+ - `demo_all.py` - Comprehensive demo of all chart types
160
+
161
+ Run examples:
162
+
163
+ ```bash
164
+ cd examples
165
+ python demo_all.py
166
+ ```
167
+
168
+ ## Testing
169
+
170
+ ```bash
171
+ # Install development dependencies
172
+ pip install -e ".[dev]"
173
+
174
+ # Run tests
175
+ pytest
176
+
177
+ # Run tests with coverage
178
+ pytest --cov=term_plot
179
+ ```
180
+
181
+ ## Requirements
182
+
183
+ - Python 3.8 or higher
184
+ - No external dependencies!
185
+
186
+ ## License
187
+
188
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
189
+
190
+ ## Acknowledgments
191
+
192
+ - Inspired by various terminal plotting libraries
193
+ - Unicode block elements from the Unicode standard
194
+ - ANSI color codes for terminal colors
@@ -0,0 +1,168 @@
1
+ # Terminal Plot
2
+
3
+ > Draw beautiful plots and charts in your terminal using ASCII and Unicode symbols
4
+
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
+ [![Python 3.8+](https://img.shields.io/badge/python-3.8+-blue.svg)](https://www.python.org/downloads/)
7
+
8
+ ## Features
9
+
10
+ - **Bar Charts** - Horizontal and vertical bar charts for categorical data
11
+ - **Line Charts** - Single and multi-series line plots with automatic scaling
12
+ - **Scatter Plots** - Visualize correlations and relationships
13
+ - **Histograms** - Show data distributions with customizable bins
14
+ - **Dual Modes** - Beautiful Unicode symbols or ASCII for compatibility
15
+ - **Color Support** - Optional ANSI colors for better visualization
16
+ - **Zero Dependencies** - Pure Python, works anywhere
17
+ - **Lightweight** - Fast and minimal resource usage
18
+
19
+ ## Installation
20
+
21
+ ### From PyPI (once published)
22
+
23
+ ```bash
24
+ pip install term-plot
25
+ ```
26
+
27
+ ### From source
28
+
29
+ ```bash
30
+ git clone https://github.com/yourusername/term-plot.git
31
+ cd term-plot
32
+ pip install -e .
33
+ ```
34
+
35
+ ## Quick Start
36
+
37
+ ### Bar Chart
38
+
39
+ ```python
40
+ from term_plot import BarChart
41
+
42
+ # Simple horizontal bar chart
43
+ data = [23, 45, 12, 67, 34, 89, 56]
44
+ labels = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
45
+
46
+ chart = BarChart(data, labels=labels, title="Daily Sales", width=50)
47
+ print(chart.horizontal())
48
+
49
+ # Vertical bar chart
50
+ chart = BarChart(data, labels=labels, title="Daily Sales", height=15)
51
+ print(chart.vertical())
52
+ ```
53
+
54
+ ### Line Chart
55
+
56
+ ```python
57
+ from term_plot import LineChart
58
+
59
+ # Single series
60
+ data = [1, 3, 7, 4, 8, 6, 9, 12, 10]
61
+ chart = LineChart(data, title="Temperature Over Time", width=60, height=15)
62
+ print(chart.plot())
63
+
64
+ # Multiple series
65
+ data = {
66
+ "Product A": [5, 7, 9, 12, 15, 18, 20],
67
+ "Product B": [3, 5, 8, 10, 12, 15, 17]
68
+ }
69
+ chart = LineChart(data, title="Sales Comparison", width=70, height=20)
70
+ print(chart.plot())
71
+ ```
72
+
73
+ ### Scatter Plot
74
+
75
+ ```python
76
+ from term_plot import ScatterPlot
77
+
78
+ x_data = [1, 2, 3, 4, 5, 6, 7, 8, 9]
79
+ y_data = [2, 4, 3, 5, 7, 6, 8, 9, 8]
80
+
81
+ chart = ScatterPlot(x_data, y_data, title="Correlation Plot", width=50, height=15)
82
+ print(chart.plot())
83
+ ```
84
+
85
+ ### Histogram
86
+
87
+ ```python
88
+ from term_plot import Histogram
89
+ import random
90
+
91
+ # Generate sample data
92
+ data = [random.gauss(50, 15) for _ in range(1000)]
93
+
94
+ chart = Histogram(data, bins=15, title="Test Score Distribution", width=60, height=15)
95
+ print(chart.plot())
96
+ ```
97
+
98
+ ## Customization Options
99
+
100
+ ### ASCII vs Unicode
101
+
102
+ ```python
103
+ # Unicode mode (default) - prettier but requires Unicode support
104
+ chart = BarChart(data, labels=labels, use_unicode=True)
105
+
106
+ # ASCII mode - works everywhere
107
+ chart = BarChart(data, labels=labels, use_unicode=False)
108
+ ```
109
+
110
+ ### Colors
111
+
112
+ ```python
113
+ # With colors (default)
114
+ chart = BarChart(data, labels=labels, color=True)
115
+
116
+ # Without colors
117
+ chart = BarChart(data, labels=labels, color=False)
118
+ ```
119
+
120
+ ### Size Control
121
+
122
+ ```python
123
+ # Custom width and height
124
+ chart = LineChart(data, width=80, height=25)
125
+ ```
126
+
127
+ ## Examples
128
+
129
+ Check out the `examples/` directory for more:
130
+
131
+ - `bar_chart_example.py` - Various bar chart styles
132
+ - `line_chart_example.py` - Line chart examples including sine waves
133
+ - `demo_all.py` - Comprehensive demo of all chart types
134
+
135
+ Run examples:
136
+
137
+ ```bash
138
+ cd examples
139
+ python demo_all.py
140
+ ```
141
+
142
+ ## Testing
143
+
144
+ ```bash
145
+ # Install development dependencies
146
+ pip install -e ".[dev]"
147
+
148
+ # Run tests
149
+ pytest
150
+
151
+ # Run tests with coverage
152
+ pytest --cov=term_plot
153
+ ```
154
+
155
+ ## Requirements
156
+
157
+ - Python 3.8 or higher
158
+ - No external dependencies!
159
+
160
+ ## License
161
+
162
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
163
+
164
+ ## Acknowledgments
165
+
166
+ - Inspired by various terminal plotting libraries
167
+ - Unicode block elements from the Unicode standard
168
+ - ANSI color codes for terminal colors
@@ -0,0 +1,38 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "term-plot-mc"
7
+ version = "0.1.0"
8
+ description = "Draw simple plots and charts in the terminal using ASCII symbols"
9
+ readme = "README.md"
10
+ authors = [{ name = "Mehdi Maleki", email = "mosioc79@gmail.com" }]
11
+ license = { text = "MIT" }
12
+ classifiers = [
13
+ "Development Status :: 3 - Alpha",
14
+ "Intended Audience :: Developers",
15
+ "License :: OSI Approved :: MIT License",
16
+ "Programming Language :: Python :: 3",
17
+ "Programming Language :: Python :: 3.8",
18
+ "Programming Language :: Python :: 3.9",
19
+ "Programming Language :: Python :: 3.10",
20
+ "Programming Language :: Python :: 3.11",
21
+ "Programming Language :: Python :: 3.12",
22
+ "Topic :: Software Development :: Libraries :: Python Modules",
23
+ "Topic :: Terminals",
24
+ ]
25
+ keywords = ["terminal", "ascii", "plot", "chart", "visualization", "cli"]
26
+ requires-python = ">=3.8"
27
+ dependencies = []
28
+
29
+ [project.urls]
30
+ Homepage = "https://github.com/mosioc/term-plot"
31
+ Repository = "https://github.com/mosioc/term-plot"
32
+ Issues = "https://github.com/mosioc/term-plot/issues"
33
+
34
+ [tool.setuptools.packages.find]
35
+ where = ["src"]
36
+
37
+ [tool.setuptools.package-data]
38
+ term_plot = ["py.typed"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,13 @@
1
+ """
2
+ term-plot: Draw simple plots and charts in the terminal using ASCII/Unicode symbols.
3
+ """
4
+
5
+ __version__ = "0.1.0"
6
+ __author__ = "Mosioc"
7
+
8
+ from .bar_chart import BarChart
9
+ from .line_chart import LineChart
10
+ from .scatter_plot import ScatterPlot
11
+ from .histogram import Histogram
12
+
13
+ __all__ = ["BarChart", "LineChart", "ScatterPlot", "Histogram"]
@@ -0,0 +1,139 @@
1
+ """
2
+ Bar chart implementation for terminal.
3
+ """
4
+
5
+ from .utils import normalize_data, truncate_label, Symbols
6
+
7
+
8
+ class BarChart:
9
+ """Create horizontal or vertical bar charts in the terminal."""
10
+
11
+ def __init__(self, data, labels=None, title="", width=50, height=20,
12
+ use_unicode=True, color=True):
13
+ """
14
+ Initialize a bar chart.
15
+
16
+ Args:
17
+ data: List of numeric values
18
+ labels: List of labels for each bar (optional)
19
+ title: Chart title
20
+ width: Maximum width of the chart
21
+ height: Maximum height of bars (for vertical charts)
22
+ use_unicode: Use Unicode symbols (prettier) vs ASCII
23
+ color: Use ANSI colors (if supported)
24
+ """
25
+ self.data = data
26
+ self.labels = labels or [f"Item {i+1}" for i in range(len(data))]
27
+ self.title = title
28
+ self.width = width
29
+ self.height = height
30
+ self.use_unicode = use_unicode
31
+ self.color = color
32
+
33
+ if len(self.data) != len(self.labels):
34
+ raise ValueError("Data and labels must have the same length")
35
+
36
+ def horizontal(self):
37
+ """Draw a horizontal bar chart."""
38
+ if not self.data:
39
+ return "No data to display"
40
+
41
+ output = []
42
+
43
+ # title
44
+ if self.title:
45
+ output.append(f"\n{self.title}")
46
+ output.append("=" * len(self.title))
47
+
48
+ # find max label length
49
+ max_label_len = max(len(str(label)) for label in self.labels)
50
+ max_label_len = min(max_label_len, 20) # Cap at 20 chars
51
+
52
+ # normalize data to fit width
53
+ bar_width = self.width - max_label_len - 10 # Space for label and value
54
+ normalized = normalize_data(self.data, 0, bar_width)
55
+
56
+ # choose symbols
57
+ if self.use_unicode:
58
+ bar_char = Symbols.UNICODE_FULL_BLOCK
59
+ else:
60
+ bar_char = Symbols.ASCII_BLOCK
61
+
62
+ # draw bars
63
+ for i, (label, value, norm_value) in enumerate(zip(self.labels, self.data, normalized)):
64
+ label_str = truncate_label(label, max_label_len).ljust(max_label_len)
65
+ bar_len = int(norm_value)
66
+ bar = bar_char * bar_len
67
+
68
+ # add color if enabled
69
+ if self.color:
70
+ colors = ['\033[91m', '\033[92m', '\033[93m', '\033[94m', '\033[95m', '\033[96m']
71
+ color_code = colors[i % len(colors)]
72
+ reset_code = '\033[0m'
73
+ bar = f"{color_code}{bar}{reset_code}"
74
+
75
+ output.append(f"{label_str} | {bar} {value:.2f}")
76
+
77
+ return "\n".join(output)
78
+
79
+ def vertical(self):
80
+ """Draw a vertical bar chart."""
81
+ if not self.data:
82
+ return "No data to display"
83
+
84
+ output = []
85
+
86
+ # title
87
+ if self.title:
88
+ output.append(f"\n{self.title}")
89
+ output.append("=" * len(self.title))
90
+
91
+ # normalize data to height
92
+ normalized = normalize_data(self.data, 0, self.height)
93
+
94
+ # choose symbols
95
+ if self.use_unicode:
96
+ bar_char = Symbols.UNICODE_FULL_BLOCK
97
+ h_line = Symbols.UNICODE_HORIZONTAL
98
+ else:
99
+ bar_char = Symbols.ASCII_BLOCK
100
+ h_line = Symbols.ASCII_HORIZONTAL
101
+
102
+ # draw from top to bottom
103
+ for level in range(self.height, 0, -1):
104
+ line = ""
105
+ for i, norm_value in enumerate(normalized):
106
+ if norm_value >= level:
107
+ char = bar_char * 3
108
+ if self.color:
109
+ colors = ['\033[91m', '\033[92m', '\033[93m', '\033[94m', '\033[95m', '\033[96m']
110
+ color_code = colors[i % len(colors)]
111
+ reset_code = '\033[0m'
112
+ char = f"{color_code}{char}{reset_code}"
113
+ line += char + " "
114
+ else:
115
+ line += " "
116
+ output.append(line)
117
+
118
+ # draw x-axis
119
+ output.append(h_line * (len(self.data) * 4))
120
+
121
+ # draw labels
122
+ label_line = ""
123
+ for label in self.labels:
124
+ label_str = truncate_label(label, 3)
125
+ label_line += label_str.center(4)
126
+ output.append(label_line)
127
+
128
+ # draw values
129
+ value_line = ""
130
+ for value in self.data:
131
+ value_str = f"{value:.1f}"
132
+ value_line += truncate_label(value_str, 3).center(4)
133
+ output.append(value_line)
134
+
135
+ return "\n".join(output)
136
+
137
+ def __str__(self):
138
+ """Default to horizontal bar chart."""
139
+ return self.horizontal()
@@ -0,0 +1,104 @@
1
+ """
2
+ Histogram implementation for terminal.
3
+ """
4
+
5
+ from .utils import Symbols
6
+
7
+
8
+ class Histogram:
9
+ """Create histograms in the terminal."""
10
+
11
+ def __init__(self, data, bins=10, title="", width=60, height=20, use_unicode=True):
12
+ """
13
+ Initialize a histogram.
14
+
15
+ Args:
16
+ data: List of numeric values
17
+ bins: Number of bins (default 10)
18
+ title: Chart title
19
+ width: Chart width in characters
20
+ height: Chart height in lines
21
+ use_unicode: Use Unicode symbols vs ASCII
22
+ """
23
+ self.data = data
24
+ self.bins = bins
25
+ self.title = title
26
+ self.width = width
27
+ self.height = height
28
+ self.use_unicode = use_unicode
29
+
30
+ def plot(self):
31
+ """Draw the histogram."""
32
+ if not self.data:
33
+ return "No data to display"
34
+
35
+ output = []
36
+
37
+ # title
38
+ if self.title:
39
+ output.append(f"\n{self.title}")
40
+ output.append("=" * len(self.title))
41
+
42
+ # calculate bins
43
+ data_min = min(self.data)
44
+ data_max = max(self.data)
45
+
46
+ if data_min == data_max:
47
+ return "All values are the same, cannot create histogram"
48
+
49
+ bin_width = (data_max - data_min) / self.bins
50
+ bin_counts = [0] * self.bins
51
+ bin_edges = [data_min + i * bin_width for i in range(self.bins + 1)]
52
+
53
+ # count values in each bin
54
+ for value in self.data:
55
+ bin_idx = min(int((value - data_min) / bin_width), self.bins - 1)
56
+ bin_counts[bin_idx] += 1
57
+
58
+ # choose symbols
59
+ if self.use_unicode:
60
+ bar_char = Symbols.UNICODE_FULL_BLOCK
61
+ h_char = Symbols.UNICODE_HORIZONTAL
62
+ else:
63
+ bar_char = Symbols.ASCII_BLOCK
64
+ h_char = Symbols.ASCII_HORIZONTAL
65
+
66
+ # scale to height
67
+ max_count = max(bin_counts) if bin_counts else 1
68
+
69
+ # draw histogram from top to bottom
70
+ for level in range(self.height, 0, -1):
71
+ line = ""
72
+ threshold = (level / self.height) * max_count
73
+
74
+ for count in bin_counts:
75
+ if count >= threshold:
76
+ line += bar_char * 3 + " "
77
+ else:
78
+ line += " "
79
+ output.append(line)
80
+
81
+ # draw x-axis
82
+ output.append(h_char * (self.bins * 4))
83
+
84
+ # draw bin labels
85
+ label_line = ""
86
+ for i in range(self.bins):
87
+ bin_start = bin_edges[i]
88
+ label = f"{bin_start:.1f}"
89
+ if len(label) > 3:
90
+ label = label[:3]
91
+ label_line += label.center(4)
92
+ output.append(label_line)
93
+
94
+ # statistics
95
+ output.append(f"\nTotal values: {len(self.data)}")
96
+ output.append(f"Range: {data_min:.2f} to {data_max:.2f}")
97
+ output.append(f"Mean: {sum(self.data)/len(self.data):.2f}")
98
+ output.append(f"Max frequency: {max_count}")
99
+
100
+ return "\n".join(output)
101
+
102
+ def __str__(self):
103
+ """Default string representation."""
104
+ return self.plot()
@@ -0,0 +1,164 @@
1
+ """
2
+ Line chart implementation for terminal.
3
+ """
4
+
5
+ from .utils import normalize_data, Symbols
6
+
7
+
8
+ class LineChart:
9
+ """Create line charts in the terminal."""
10
+
11
+ def __init__(self, data, title="", width=60, height=20, use_unicode=True):
12
+ """
13
+ Initialize a line chart.
14
+
15
+ Args:
16
+ data: List of numeric values or dict of {label: values} for multiple lines
17
+ title: Chart title
18
+ width: Chart width in characters
19
+ height: Chart height in lines
20
+ use_unicode: Use Unicode symbols vs ASCII
21
+ """
22
+ # support both single series and multiple series
23
+ if isinstance(data, dict):
24
+ self.data = data
25
+ self.multi_series = True
26
+ else:
27
+ self.data = {"Series 1": data}
28
+ self.multi_series = False
29
+
30
+ self.title = title
31
+ self.width = width
32
+ self.height = height
33
+ self.use_unicode = use_unicode
34
+
35
+ def plot(self):
36
+ """Draw the line chart."""
37
+ if not self.data:
38
+ return "No data to display"
39
+
40
+ output = []
41
+
42
+ # title
43
+ if self.title:
44
+ output.append(f"\n{self.title}")
45
+ output.append("=" * len(self.title))
46
+
47
+ # create the canvas
48
+ canvas = [[' ' for _ in range(self.width)] for _ in range(self.height)]
49
+
50
+ # choose symbols
51
+ if self.use_unicode:
52
+ point_char = Symbols.UNICODE_DOT
53
+ line_chars = ['•', '○', '◆', '◇', '▪', '▫']
54
+ else:
55
+ point_char = Symbols.ASCII_POINT
56
+ line_chars = ['*', 'o', '+', 'x', '#', '@']
57
+
58
+ # plot each series
59
+ series_idx = 0
60
+ all_values = []
61
+ for values in self.data.values():
62
+ all_values.extend(values)
63
+
64
+ # normalize all data together for consistent scale
65
+ if all_values:
66
+ global_min = min(all_values)
67
+ global_max = max(all_values)
68
+ else:
69
+ return "No data to display"
70
+
71
+ for label, values in self.data.items():
72
+ if not values:
73
+ continue
74
+
75
+ char = line_chars[series_idx % len(line_chars)]
76
+
77
+ # normalize to height
78
+ normalized = normalize_data(values, 0, self.height - 1)
79
+
80
+ # calculate x positions
81
+ if len(values) > 1:
82
+ x_step = (self.width - 1) / (len(values) - 1)
83
+ else:
84
+ x_step = 0
85
+
86
+ # plot points and connect them
87
+ for i, norm_value in enumerate(normalized):
88
+ x = int(i * x_step)
89
+ y = self.height - 1 - int(norm_value)
90
+
91
+ if 0 <= x < self.width and 0 <= y < self.height:
92
+ canvas[y][x] = char
93
+
94
+ # draw line to next point
95
+ if i < len(normalized) - 1:
96
+ next_x = int((i + 1) * x_step)
97
+ next_y = self.height - 1 - int(normalized[i + 1])
98
+
99
+ # simple line drawing between points
100
+ self._draw_line(canvas, x, y, next_x, next_y, char)
101
+
102
+ series_idx += 1
103
+
104
+ # add y-axis
105
+ if self.use_unicode:
106
+ v_char = Symbols.UNICODE_VERTICAL
107
+ else:
108
+ v_char = Symbols.ASCII_VERTICAL
109
+
110
+ for y in range(self.height):
111
+ canvas[y][0] = v_char
112
+
113
+ # convert canvas to string
114
+ for row in canvas:
115
+ output.append(''.join(row))
116
+
117
+ # add x-axis
118
+ if self.use_unicode:
119
+ h_char = Symbols.UNICODE_HORIZONTAL
120
+ else:
121
+ h_char = Symbols.ASCII_HORIZONTAL
122
+ output.append(h_char * self.width)
123
+
124
+ # add legend if multiple series
125
+ if self.multi_series and len(self.data) > 1:
126
+ output.append("\nLegend:")
127
+ for idx, label in enumerate(self.data.keys()):
128
+ char = line_chars[idx % len(line_chars)]
129
+ output.append(f" {char} {label}")
130
+
131
+ # add scale info
132
+ output.append(f"\nScale: {global_min:.2f} to {global_max:.2f}")
133
+
134
+ return "\n".join(output)
135
+
136
+ def _draw_line(self, canvas, x1, y1, x2, y2, char):
137
+ """Draw a simple line between two points using Bresenham's algorithm."""
138
+ dx = abs(x2 - x1)
139
+ dy = abs(y2 - y1)
140
+ sx = 1 if x1 < x2 else -1
141
+ sy = 1 if y1 < y2 else -1
142
+ err = dx - dy
143
+
144
+ x, y = x1, y1
145
+
146
+ while True:
147
+ if 0 <= x < self.width and 0 <= y < self.height:
148
+ if canvas[y][x] == ' ' or canvas[y][x] in ['│', '|']:
149
+ canvas[y][x] = char
150
+
151
+ if x == x2 and y == y2:
152
+ break
153
+
154
+ e2 = 2 * err
155
+ if e2 > -dy:
156
+ err -= dy
157
+ x += sx
158
+ if e2 < dx:
159
+ err += dx
160
+ y += sy
161
+
162
+ def __str__(self):
163
+ """Default string representation."""
164
+ return self.plot()
@@ -0,0 +1,93 @@
1
+ """
2
+ Scatter plot implementation for terminal.
3
+ """
4
+
5
+ from .utils import normalize_data, Symbols
6
+
7
+
8
+ class ScatterPlot:
9
+ """Create scatter plots in the terminal."""
10
+
11
+ def __init__(self, x_data, y_data, title="", width=60, height=20, use_unicode=True):
12
+ """
13
+ Initialize a scatter plot.
14
+
15
+ Args:
16
+ x_data: List of x coordinates
17
+ y_data: List of y coordinates
18
+ title: Chart title
19
+ width: Chart width in characters
20
+ height: Chart height in lines
21
+ use_unicode: Use Unicode symbols vs ASCII
22
+ """
23
+ if len(x_data) != len(y_data):
24
+ raise ValueError("x_data and y_data must have the same length")
25
+
26
+ self.x_data = x_data
27
+ self.y_data = y_data
28
+ self.title = title
29
+ self.width = width
30
+ self.height = height
31
+ self.use_unicode = use_unicode
32
+
33
+ def plot(self):
34
+ """Draw the scatter plot."""
35
+ if not self.x_data or not self.y_data:
36
+ return "No data to display"
37
+
38
+ output = []
39
+
40
+ # title
41
+ if self.title:
42
+ output.append(f"\n{self.title}")
43
+ output.append("=" * len(self.title))
44
+
45
+ # create the canvas
46
+ canvas = [[' ' for _ in range(self.width)] for _ in range(self.height)]
47
+
48
+ # choose symbols
49
+ if self.use_unicode:
50
+ point_char = Symbols.UNICODE_DOT
51
+ v_char = Symbols.UNICODE_VERTICAL
52
+ h_char = Symbols.UNICODE_HORIZONTAL
53
+ else:
54
+ point_char = Symbols.ASCII_POINT
55
+ v_char = Symbols.ASCII_VERTICAL
56
+ h_char = Symbols.ASCII_HORIZONTAL
57
+
58
+ # normalize data
59
+ x_normalized = normalize_data(self.x_data, 1, self.width - 1)
60
+ y_normalized = normalize_data(self.y_data, 0, self.height - 1)
61
+
62
+ # plot points
63
+ for x, y in zip(x_normalized, y_normalized):
64
+ x_pos = int(x)
65
+ y_pos = self.height - 1 - int(y)
66
+
67
+ if 0 <= x_pos < self.width and 0 <= y_pos < self.height:
68
+ canvas[y_pos][x_pos] = point_char
69
+
70
+ # add y-axis
71
+ for y in range(self.height):
72
+ if canvas[y][0] == ' ':
73
+ canvas[y][0] = v_char
74
+
75
+ # convert canvas to string
76
+ for row in canvas:
77
+ output.append(''.join(row))
78
+
79
+ # add x-axis
80
+ output.append(h_char * self.width)
81
+
82
+ # add scale info
83
+ x_min, x_max = min(self.x_data), max(self.x_data)
84
+ y_min, y_max = min(self.y_data), max(self.y_data)
85
+ output.append(f"\nX: {x_min:.2f} to {x_max:.2f}")
86
+ output.append(f"Y: {y_min:.2f} to {y_max:.2f}")
87
+ output.append(f"Points: {len(self.x_data)}")
88
+
89
+ return "\n".join(output)
90
+
91
+ def __str__(self):
92
+ """Default string representation."""
93
+ return self.plot()
@@ -0,0 +1,73 @@
1
+ """
2
+ Utility functions for terminal plotting.
3
+ """
4
+
5
+ def normalize_data(data, min_val=0, max_val=100):
6
+ """Normalize data to a specific range."""
7
+ if not data:
8
+ return []
9
+
10
+ data_min = min(data)
11
+ data_max = max(data)
12
+
13
+ if data_max == data_min:
14
+ return [min_val] * len(data)
15
+
16
+ scale = (max_val - min_val) / (data_max - data_min)
17
+ return [min_val + (x - data_min) * scale for x in data]
18
+
19
+
20
+ def get_terminal_width():
21
+ """Get the current terminal width."""
22
+ import shutil
23
+ return shutil.get_terminal_size().columns
24
+
25
+
26
+ def get_terminal_height():
27
+ """Get the current terminal height."""
28
+ import shutil
29
+ return shutil.get_terminal_size().lines
30
+
31
+
32
+ def truncate_label(label, max_length):
33
+ """Truncate label to max_length with ellipsis if needed."""
34
+ label = str(label)
35
+ if len(label) <= max_length:
36
+ return label
37
+ return label[:max_length-3] + "..."
38
+
39
+
40
+ class Symbols:
41
+ """ASCII and Unicode symbols for plotting."""
42
+
43
+ # ASCII symbols
44
+ ASCII_HORIZONTAL = "-"
45
+ ASCII_VERTICAL = "|"
46
+ ASCII_BLOCK = "#"
47
+ ASCII_POINT = "*"
48
+ ASCII_CORNER = "+"
49
+
50
+ # unicode symbols (prettier but may not work on all terminals)
51
+ UNICODE_HORIZONTAL = "─"
52
+ UNICODE_VERTICAL = "│"
53
+ UNICODE_CORNER_TL = "┌"
54
+ UNICODE_CORNER_TR = "┐"
55
+ UNICODE_CORNER_BL = "└"
56
+ UNICODE_CORNER_BR = "┘"
57
+ UNICODE_CROSS = "┼"
58
+ UNICODE_T_DOWN = "┬"
59
+ UNICODE_T_UP = "┴"
60
+ UNICODE_T_RIGHT = "├"
61
+ UNICODE_T_LEFT = "┤"
62
+
63
+ # block elements
64
+ UNICODE_BLOCKS = ["▁", "▂", "▃", "▄", "▅", "▆", "▇", "█"]
65
+ UNICODE_FULL_BLOCK = "█"
66
+ UNICODE_LIGHT_SHADE = "░"
67
+ UNICODE_MEDIUM_SHADE = "▒"
68
+ UNICODE_DARK_SHADE = "▓"
69
+
70
+ # dots and points
71
+ UNICODE_DOT = "•"
72
+ UNICODE_CIRCLE = "○"
73
+ UNICODE_SQUARE = "■"
@@ -0,0 +1,194 @@
1
+ Metadata-Version: 2.4
2
+ Name: term-plot-mc
3
+ Version: 0.1.0
4
+ Summary: Draw simple plots and charts in the terminal using ASCII symbols
5
+ Author-email: Mehdi Maleki <mosioc79@gmail.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/mosioc/term-plot
8
+ Project-URL: Repository, https://github.com/mosioc/term-plot
9
+ Project-URL: Issues, https://github.com/mosioc/term-plot/issues
10
+ Keywords: terminal,ascii,plot,chart,visualization,cli
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.8
16
+ Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
+ Classifier: Topic :: Terminals
22
+ Requires-Python: >=3.8
23
+ Description-Content-Type: text/markdown
24
+ License-File: LICENSE
25
+ Dynamic: license-file
26
+
27
+ # Terminal Plot
28
+
29
+ > Draw beautiful plots and charts in your terminal using ASCII and Unicode symbols
30
+
31
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
32
+ [![Python 3.8+](https://img.shields.io/badge/python-3.8+-blue.svg)](https://www.python.org/downloads/)
33
+
34
+ ## Features
35
+
36
+ - **Bar Charts** - Horizontal and vertical bar charts for categorical data
37
+ - **Line Charts** - Single and multi-series line plots with automatic scaling
38
+ - **Scatter Plots** - Visualize correlations and relationships
39
+ - **Histograms** - Show data distributions with customizable bins
40
+ - **Dual Modes** - Beautiful Unicode symbols or ASCII for compatibility
41
+ - **Color Support** - Optional ANSI colors for better visualization
42
+ - **Zero Dependencies** - Pure Python, works anywhere
43
+ - **Lightweight** - Fast and minimal resource usage
44
+
45
+ ## Installation
46
+
47
+ ### From PyPI (once published)
48
+
49
+ ```bash
50
+ pip install term-plot
51
+ ```
52
+
53
+ ### From source
54
+
55
+ ```bash
56
+ git clone https://github.com/yourusername/term-plot.git
57
+ cd term-plot
58
+ pip install -e .
59
+ ```
60
+
61
+ ## Quick Start
62
+
63
+ ### Bar Chart
64
+
65
+ ```python
66
+ from term_plot import BarChart
67
+
68
+ # Simple horizontal bar chart
69
+ data = [23, 45, 12, 67, 34, 89, 56]
70
+ labels = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
71
+
72
+ chart = BarChart(data, labels=labels, title="Daily Sales", width=50)
73
+ print(chart.horizontal())
74
+
75
+ # Vertical bar chart
76
+ chart = BarChart(data, labels=labels, title="Daily Sales", height=15)
77
+ print(chart.vertical())
78
+ ```
79
+
80
+ ### Line Chart
81
+
82
+ ```python
83
+ from term_plot import LineChart
84
+
85
+ # Single series
86
+ data = [1, 3, 7, 4, 8, 6, 9, 12, 10]
87
+ chart = LineChart(data, title="Temperature Over Time", width=60, height=15)
88
+ print(chart.plot())
89
+
90
+ # Multiple series
91
+ data = {
92
+ "Product A": [5, 7, 9, 12, 15, 18, 20],
93
+ "Product B": [3, 5, 8, 10, 12, 15, 17]
94
+ }
95
+ chart = LineChart(data, title="Sales Comparison", width=70, height=20)
96
+ print(chart.plot())
97
+ ```
98
+
99
+ ### Scatter Plot
100
+
101
+ ```python
102
+ from term_plot import ScatterPlot
103
+
104
+ x_data = [1, 2, 3, 4, 5, 6, 7, 8, 9]
105
+ y_data = [2, 4, 3, 5, 7, 6, 8, 9, 8]
106
+
107
+ chart = ScatterPlot(x_data, y_data, title="Correlation Plot", width=50, height=15)
108
+ print(chart.plot())
109
+ ```
110
+
111
+ ### Histogram
112
+
113
+ ```python
114
+ from term_plot import Histogram
115
+ import random
116
+
117
+ # Generate sample data
118
+ data = [random.gauss(50, 15) for _ in range(1000)]
119
+
120
+ chart = Histogram(data, bins=15, title="Test Score Distribution", width=60, height=15)
121
+ print(chart.plot())
122
+ ```
123
+
124
+ ## Customization Options
125
+
126
+ ### ASCII vs Unicode
127
+
128
+ ```python
129
+ # Unicode mode (default) - prettier but requires Unicode support
130
+ chart = BarChart(data, labels=labels, use_unicode=True)
131
+
132
+ # ASCII mode - works everywhere
133
+ chart = BarChart(data, labels=labels, use_unicode=False)
134
+ ```
135
+
136
+ ### Colors
137
+
138
+ ```python
139
+ # With colors (default)
140
+ chart = BarChart(data, labels=labels, color=True)
141
+
142
+ # Without colors
143
+ chart = BarChart(data, labels=labels, color=False)
144
+ ```
145
+
146
+ ### Size Control
147
+
148
+ ```python
149
+ # Custom width and height
150
+ chart = LineChart(data, width=80, height=25)
151
+ ```
152
+
153
+ ## Examples
154
+
155
+ Check out the `examples/` directory for more:
156
+
157
+ - `bar_chart_example.py` - Various bar chart styles
158
+ - `line_chart_example.py` - Line chart examples including sine waves
159
+ - `demo_all.py` - Comprehensive demo of all chart types
160
+
161
+ Run examples:
162
+
163
+ ```bash
164
+ cd examples
165
+ python demo_all.py
166
+ ```
167
+
168
+ ## Testing
169
+
170
+ ```bash
171
+ # Install development dependencies
172
+ pip install -e ".[dev]"
173
+
174
+ # Run tests
175
+ pytest
176
+
177
+ # Run tests with coverage
178
+ pytest --cov=term_plot
179
+ ```
180
+
181
+ ## Requirements
182
+
183
+ - Python 3.8 or higher
184
+ - No external dependencies!
185
+
186
+ ## License
187
+
188
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
189
+
190
+ ## Acknowledgments
191
+
192
+ - Inspired by various terminal plotting libraries
193
+ - Unicode block elements from the Unicode standard
194
+ - ANSI color codes for terminal colors
@@ -0,0 +1,15 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ src/term_plot/__init__.py
5
+ src/term_plot/bar_chart.py
6
+ src/term_plot/histogram.py
7
+ src/term_plot/line_chart.py
8
+ src/term_plot/scatter_plot.py
9
+ src/term_plot/utils.py
10
+ src/term_plot_mc.egg-info/PKG-INFO
11
+ src/term_plot_mc.egg-info/SOURCES.txt
12
+ src/term_plot_mc.egg-info/dependency_links.txt
13
+ src/term_plot_mc.egg-info/top_level.txt
14
+ tests/test_bar_chart.py
15
+ tests/test_utils.py
@@ -0,0 +1,86 @@
1
+ """
2
+ Tests for BarChart class.
3
+ """
4
+
5
+ import pytest
6
+ from term_plot import BarChart
7
+
8
+
9
+ def test_bar_chart_creation():
10
+ """Test basic bar chart creation."""
11
+ data = [1, 2, 3, 4, 5]
12
+ labels = ['A', 'B', 'C', 'D', 'E']
13
+
14
+ chart = BarChart(data, labels=labels)
15
+ assert chart.data == data
16
+ assert chart.labels == labels
17
+
18
+
19
+ def test_bar_chart_mismatched_lengths():
20
+ """Test that mismatched data and labels raises error."""
21
+ data = [1, 2, 3]
22
+ labels = ['A', 'B']
23
+
24
+ with pytest.raises(ValueError):
25
+ BarChart(data, labels=labels)
26
+
27
+
28
+ def test_bar_chart_horizontal():
29
+ """Test horizontal bar chart generation."""
30
+ data = [10, 20, 30]
31
+ labels = ['X', 'Y', 'Z']
32
+
33
+ chart = BarChart(data, labels=labels, title="Test Chart")
34
+ output = chart.horizontal()
35
+
36
+ assert "Test Chart" in output
37
+ assert "X" in output
38
+ assert "Y" in output
39
+ assert "Z" in output
40
+
41
+
42
+ def test_bar_chart_vertical():
43
+ """Test vertical bar chart generation."""
44
+ data = [5, 10, 15]
45
+ labels = ['A', 'B', 'C']
46
+
47
+ chart = BarChart(data, labels=labels)
48
+ output = chart.vertical()
49
+
50
+ assert output is not None
51
+ assert len(output) > 0
52
+
53
+
54
+ def test_bar_chart_empty_data():
55
+ """Test bar chart with empty data."""
56
+ data = []
57
+ labels = []
58
+
59
+ chart = BarChart(data, labels=labels)
60
+ output = chart.horizontal()
61
+
62
+ assert "No data" in output
63
+
64
+
65
+ def test_bar_chart_auto_labels():
66
+ """Test automatic label generation."""
67
+ data = [1, 2, 3]
68
+
69
+ chart = BarChart(data)
70
+ assert len(chart.labels) == len(data)
71
+ assert chart.labels[0] == "Item 1"
72
+
73
+
74
+ def test_bar_chart_unicode_vs_ascii():
75
+ """Test Unicode vs ASCII mode."""
76
+ data = [10, 20]
77
+ labels = ['A', 'B']
78
+
79
+ unicode_chart = BarChart(data, labels=labels, use_unicode=True)
80
+ ascii_chart = BarChart(data, labels=labels, use_unicode=False)
81
+
82
+ unicode_output = unicode_chart.horizontal()
83
+ ascii_output = ascii_chart.horizontal()
84
+
85
+ # They should be different
86
+ assert unicode_output != ascii_output
@@ -0,0 +1,53 @@
1
+ """
2
+ Tests for utility functions.
3
+ """
4
+
5
+ import pytest
6
+ from term_plot.utils import normalize_data, truncate_label, Symbols
7
+
8
+
9
+ def test_normalize_data():
10
+ """Test data normalization."""
11
+ data = [0, 50, 100]
12
+ normalized = normalize_data(data, 0, 10)
13
+
14
+ assert normalized[0] == 0
15
+ assert normalized[1] == 5
16
+ assert normalized[2] == 10
17
+
18
+
19
+ def test_normalize_data_same_values():
20
+ """Test normalization with same values."""
21
+ data = [5, 5, 5]
22
+ normalized = normalize_data(data, 0, 10)
23
+
24
+ # all values should be the same (min_val)
25
+ assert all(v == 0 for v in normalized)
26
+
27
+
28
+ def test_normalize_data_empty():
29
+ """Test normalization with empty data."""
30
+ data = []
31
+ normalized = normalize_data(data)
32
+
33
+ assert normalized == []
34
+
35
+
36
+ def test_truncate_label():
37
+ """Test label truncation."""
38
+ # short label
39
+ assert truncate_label("Test", 10) == "Test"
40
+
41
+ # song label
42
+ assert truncate_label("ThisIsAVeryLongLabel", 10) == "ThisIs..."
43
+
44
+ # exact length
45
+ assert truncate_label("ExactLen", 8) == "ExactLen"
46
+
47
+
48
+ def test_symbols_exist():
49
+ """Test that symbol constants exist."""
50
+ assert hasattr(Symbols, 'ASCII_BLOCK')
51
+ assert hasattr(Symbols, 'UNICODE_FULL_BLOCK')
52
+ assert hasattr(Symbols, 'ASCII_HORIZONTAL')
53
+ assert hasattr(Symbols, 'UNICODE_DOT')