DEV Community

jaimin patel
jaimin patel

Posted on

šŸš€ Integrating a Custom Charting Library into a Textual Custom Widget – Elevate Your TUI Charts! šŸ“Š

Hey Devs! šŸ‘‹

Ever wished your terminal-based applications could have interactive, dynamic charts? Well, we just made it happen by integrating a custom charting library into a Textual custom widget! šŸŽØāœØ

Why This Matters?
Textual is an incredible framework for building rich, interactive terminal applications, but charting support is limited out of the box. So, we built a custom widget that seamlessly integrates with an external charting library to bring smooth, interactive financial & technical charts directly inside a TUI.

šŸš€ How We Did It
āœ… Built a Custom ChartWidget inside Textual
āœ… Integrated Plotly (or any other charting library) for rendering dynamic charts
āœ… Used asyncio for smooth updates without UI freezing
āœ… Enabled multiple chart types (Line, Bar, Candlestick, etc.)
āœ… Created a Switch & Collapsible UI to toggle charts on demand

from textual.widget import Widget
from textual.containers import Horizontal, Container
from textual.widgets import Button, Static, Switch
import asyncio
import plotly.graph_objects as go

class ChartWidget(Widget):
    """A custom Textual widget to display dynamic charts."""

    def __init__(self, chart_type="line", title="Chart", widget_id="chart_widget", **kwargs):
        super().__init__(id=widget_id, **kwargs)
        self.chart_type = chart_type
        self.title = title
        self.chart_path = None  # Stores chart file path

    def compose(self):
        with Container():
            yield Static(f"šŸ“Š {self.title}", classes="chart-title")
            yield Switch(value=True, id=f"{self.id}_toggle", label="Show Chart", classes="toggle-switch")
            with Horizontal():
                yield Button("Open", id=f"{self.id}_open_chart")
                yield Button("Close", id=f"{self.id}_close_chart")

    async def generate_chart(self, data):
        """Generates an interactive chart asynchronously."""
        self.chart_path = await asyncio.to_thread(self._render_chart, data)

    def _render_chart(self, data):
        """Handles chart rendering using Plotly."""
        fig = go.Figure()
        fig.add_trace(go.Scatter(x=data["x"], y=data["y"], mode="lines", name="Line Chart"))
        chart_path = f"{self.title}.html"
        fig.write_html(chart_path)
        return chart_path

Enter fullscreen mode Exit fullscreen mode

šŸš€ What's Next?
We are expanding this to support real-time streaming charts inside Textual! Drop a šŸ”„ in the comments if you're excited! Would love to hear your thoughts! šŸ’¬šŸ‘‡

šŸ”— Check out the full implementation & contribute to the repo:Fincept Terminal

Python #Textual #TUI #Charting #Async #DataVisualization #Developers

Top comments (0)