How to Create Line Charts Using the Outfancy LineChart Class
Outfancy renders terminal-based line charts through the LineChart class defined in outfancy/chart.py, which manages data validation, coordinate scaling, and ASCII/Unicode rendering via the plot() and render() methods.
The outfancy library provides a lightweight solution for visualizing data directly in terminal environments. To create line charts using the outfancy LineChart class, you instantiate the class, feed datasets via the plot() method, and generate output through render(). This workflow separates data ingestion from rendering, allowing you to customize symbols, colors, and margins without modifying the core algorithm.
Instantiating the Chart Object
The LineChart class is implemented in outfancy/chart.py (line 11). When instantiated, it initializes storage for global extrema (x_min, x_max, y_min, y_max) and maintains a dataset_space list to hold plotted series. This state management enables automatic scaling across multiple data series without manual coordinate transformation.
Ingesting Data via the plot() Method
To add data, pass a list of (x, y) tuples to the plot(dataset) method. Internally, plot() validates the input through check_data_integrity (chart.py line 27) and extracts coordinate lists using get_list_of_elements. The method automatically updates the global minima and maxima, ensuring the subsequent rendering phase can scale the chart to fit the terminal dimensions precisely.
The Rendering Pipeline
The render() method orchestrates terminal output by executing a multi-stage pipeline:
- Terminal sizing: Queries the current terminal dimensions using
shutil.get_terminal_size()(chart.py line 16) to compute conversion factors (x_points_per_x_pixel,y_points_per_y_pixel). - Drawing surface: Instantiates a
Windowobject fromoutfancy/window.py(line 6) to provide a mutable matrix representing the drawing surface. - Coordinate transformation: Transforms data series into screen coordinates, applying optional down-sampling via
remove_unnecesary_points_before_plottingand gap-filling through linearinterpolationwhen enabled. - Character selection: When
slope_based_charactersis True,get_char_slope(chart.py line 50) selects line characters (|,/,\,—) based on local slope, optionally wrapped in ANSI color codes. - Margin assembly: Constructs top, left, and bottom margins using
create_top_margin,create_left_margin, andcreate_down_margin, which utilizewidgets.create_matrixfromoutfancy/widgets.py(line 56) to generate axis grids.
The assembled Window renders to a final string via window.render() and returns to the caller.
Customization Options
The separation of concerns between LineChart, Window, and widgets allows extensive customization without core algorithm changes. Key configuration parameters include:
- Point symbols: Override default characters using the
point_listparameter inrender(). - Colorization: Enable ANSI colors with
color=Trueand specify series-specific codes viacolor_number_list(e.g., 34 for blue, 31 for red). - Interpolation: Control automatic gap filling with the boolean
interpolationparameter. - Slope-based rendering: Toggle
slope_based_charactersto replace custom symbols with slope-appropriate line art. - Margins: Adjust layout using
left_margin_width,margin_down_height, andmargin_top_height.
Practical Code Examples
Basic Single-Series Chart
Create a simple line chart by instantiating the class, plotting a dataset, and rendering:
from outfancy.chart import LineChart
# 1️⃣ Create the chart object
chart = LineChart()
# 2️⃣ Provide a dataset – list of (x, y) tuples
dataset = [(0, 2), (1, 5), (2, 3), (3, 8), (4, 6)]
# 3️⃣ Plot the data (you can call plot multiple times for more series)
chart.plot(dataset)
# 4️⃣ Render to a string and print
print(chart.render(plot_name='Demo Line Chart'))
Multi-Series with Custom Symbols and Colors
Plot multiple series with distinct visual styling:
from outfancy.chart import LineChart
chart = LineChart()
# Series A – blue circles
series_a = [(x, x**0.5) for x in range(0, 11)]
chart.plot(series_a)
# Series B – red triangles
series_b = [(x, 5 - 0.5 * x) for x in range(0, 11)]
chart.plot(series_b)
# Render with custom point characters and colourisation
print(
chart.render(
plot_name='Two Series',
point_list=['⊙', '△'], # custom symbols per series
color=True, # enable ANSI colours
color_number_list=[34, 31], # 34=blue, 31=red
interpolation=False, # disable automatic gap filling
slope_based_characters=False # keep the chosen symbols unchanged
)
)
Advanced Margin and Slope Configuration
Adjust layout dimensions and enable slope-based character replacement:
from outfancy.chart import LineChart
chart = LineChart()
chart.plot([(i, i*i) for i in range(0, 21)])
print(
chart.render(
plot_name='Quadratic',
left_margin_width=10,
margin_down_height=4,
margin_top_height=2,
slope_based_characters=True, # let the class replace symbols by slopes
background_point='·' # light-dot background
)
)
Summary
- The
LineChartclass inoutfancy/chart.pyprovides the primary interface for creating terminal-based line charts. - Data ingestion occurs through
plot(), which validates input viacheck_data_integrityand updates global extrema for automatic scaling. - Rendering happens through
render(), which calculates terminal-relative coordinates, manages aWindowdrawing surface fromoutfancy/window.py, and assembles margins using utilities fromoutfancy/widgets.py. - Customization options include slope-based character selection (
|,/,\,—), ANSI color codes, interpolation control, and adjustable margin widths. - The architecture separates chart logic from terminal rendering, enabling flexible visual customization without core algorithm modification.
Frequently Asked Questions
How does LineChart handle automatic scaling?
The class tracks global minima and maxima (x_min, x_max, y_min, y_max) across all plotted series. During rendering, it queries the terminal size via shutil.get_terminal_size() and computes conversion factors (x_points_per_x_pixel, y_points_per_y_pixel) to map data coordinates to screen pixels automatically.
Can I plot multiple data series on the same chart?
Yes. Call plot(dataset) multiple times on the same LineChart instance before invoking render(). Each call appends to the internal dataset_space list. You can differentiate series using the point_list and color_number_list parameters in render() to assign unique symbols and colors per series.
What are slope-based characters and when should I use them?
When slope_based_characters=True, the get_char_slope method (chart.py line 50) analyzes the local slope between points and selects appropriate line drawing characters: vertical bars (|), forward slashes (/), backslashes (\), or horizontal em-dashes (—). This creates smoother visual connections between points compared to static symbols, especially for steep gradients.
How do I disable interpolation between data points?
Pass interpolation=False to the render() method. By default, the renderer may fill gaps linearly, but setting this parameter to False ensures the chart displays only the exact data points provided without generating intermediate coordinate values.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →