-
Notifications
You must be signed in to change notification settings - Fork 1
Multi Chart Support
- Introduction
- Managing Multiple Chart Instances
- Event-Driven Layout Change Handling
- Chart Context Management
- Indicator Synchronization and Data Isolation
- Resource Management and Performance
- Conclusion
PyTradingView provides comprehensive support for managing multiple chart instances within a single widget layout. This document details the architecture and implementation of multi-chart functionality, focusing on the TVWidget and TVChart APIs, event-driven layout change handling, and the ChartContextManager's role in maintaining isolated indicator states. The system automatically reinitializes all charts during layout switches and provides mechanisms for synchronizing indicators across charts while ensuring data isolation between panes.
The TVWidget API provides several methods for managing multiple chart instances within a single widget layout. The chartsCount() method returns the number of charts in the current layout, allowing developers to programmatically determine the layout configuration. This method is essential for dynamically adapting application behavior based on the number of active charts.
To access individual charts, developers can use the chart(index) method, which returns the chart API instance at the specified zero-based index. This method enables targeted operations on specific charts within a multi-chart layout. For example, when working with a two-chart layout, widget.chart(0) would return the first chart while widget.chart(1) would return the second.
The activeChart() method provides access to the currently active chart in the layout, which is particularly useful for operations that should affect only the user's current focus. This method can be used in combination with the activeChartIndex() method, which returns the zero-based index of the currently active chart. Together, these methods enable applications to respond appropriately to user interactions that change the active chart.
classDiagram
class TVWidget {
+activeChart() TVChart
+activeChartIndex() int
+chart(index : int) TVChart
+chartsCount() int
}
class TVChart {
+onDataLoaded() TVSubscription
+exportData(callback) None
+getSeries() TVSeries
}
TVWidget --> TVChart : "contains"
The multi-chart system in PyTradingView employs an event-driven approach to handle layout changes. The core mechanism is the 'layout_changed' subscription, which developers can subscribe to using the subscribe() method on the TVWidget instance. When a user switches between different chart layouts (e.g., from a single chart to a two-chart layout), this event is triggered, allowing the application to respond appropriately.
The internal _handle_layout_changed logic in TVEngineRuntime manages the reinitialization process when layout changes occur. This method is automatically called when the 'layout_changed' event is fired. The process involves cleaning up old chart contexts and reinitializing all charts in the new layout. This ensures that indicators and other components are properly configured for the new layout configuration.
The event handling flow begins with the _subscribe_layout_changed_event method, which registers a synchronous wrapper function to handle the layout change event. This wrapper function creates an asynchronous task to execute the _handle_layout_changed method, ensuring that the layout change processing does not block the main execution thread. This design pattern allows for responsive user interfaces while performing potentially time-consuming reinitialization operations.
sequenceDiagram
participant User
participant Widget as TVWidget
participant Engine as TVEngineRuntime
participant Context as ChartContextManager
User->>Widget : Change layout (e.g., 1 chart → 2 charts)
Widget->>Widget : Fire 'layout_changed' event
Widget->>Engine : Call subscribed callback
Engine->>Engine : Create async task for _handle_layout_changed
Engine->>Engine : await _cleanup_all_charts()
Engine->>Context : Clear all chart contexts
Engine->>Engine : await _initialize_all_charts()
Engine->>Widget : Get chartsCount()
loop For each chart index
Engine->>Widget : chart(index)
Engine->>Context : create_context(chart_id, chart)
Engine->>Engine : _setup_chart_data_listener()
end
Engine-->>User : Layout reinitialization complete
The ChartContextManager plays a crucial role in maintaining isolated indicator states across multiple charts. This component ensures that each chart maintains its own independent collection of indicator instances, drawing object references, and chart state cache. This isolation prevents unintended interactions between indicators on different charts while allowing for targeted operations on specific charts.
The ChartContextManager uses a dictionary-based storage system where each chart is identified by a unique chart ID (typically in the format "chart_X" where X is the zero-based index). For each chart, a ChartContext object is created and stored, containing references to the TVChart instance, active indicators, and current symbol and interval information. This design enables efficient lookup and management of chart-specific data.
Key methods provided by the ChartContextManager include create_context() for initializing a new chart context, get_context() for retrieving an existing context by chart ID, and remove_context() for cleanly removing a context when a chart is no longer needed. The manager also provides utility methods like get_all_contexts() for accessing all active contexts and clear_all() for resetting the entire system during layout changes.
classDiagram
class ChartContextManager {
+create_context(chart_id, chart) ChartContext
+get_context(chart_id) ChartContext
+remove_context(chart_id) ChartContext
+get_all_contexts() Dict[str, ChartContext]
+clear_all() None
+get_chart_ids() List[str]
+get_charts_with_indicator(name) List[str]
}
class ChartContext {
+chart_id : str
+chart : TVChart
+active_indicators : Dict[str, TVIndicator]
+symbol : str
+interval : str
+add_indicator(name, indicator) None
+remove_indicator(name) TVIndicator
+get_indicator(name) TVIndicator
+has_indicator(name) bool
+clear_all_indicators() None
+get_indicator_names() List[str]
+update_symbol_interval(symbol, interval) None
}
ChartContextManager --> ChartContext : "manages"
PyTradingView provides mechanisms for both synchronizing indicators across multiple charts and maintaining data isolation between panes. The system automatically reinitializes all charts during layout switches, ensuring that indicators are properly configured for the new layout. When a layout change occurs, the engine cleans up old chart contexts and creates new ones for each chart in the updated layout.
For indicator synchronization, developers can use the activate_indicator() method with a specific chart ID to activate an indicator on a particular chart, or omit the chart ID to activate it on all charts. This allows for flexible configuration where certain indicators can be shared across all charts while others remain specific to individual charts. The get_active_indicators() method can be used to retrieve the current set of active indicators, either for a specific chart or across all charts.
Data isolation is maintained through the ChartContextManager, which ensures that each chart's indicator instances operate on independent data sets. When data is loaded for a chart, the system exports the data and processes it within the context of that specific chart. This prevents cross-contamination of data between charts while still allowing for coordinated analysis when desired. The run_indicators_for_chart() method executes indicators on a per-chart basis, ensuring that calculations are performed in the appropriate context.
Common issues in this area include improper resource cleanup during layout changes and subscription management. The system addresses these by automatically cleaning up subscriptions and indicator states when charts are removed or layouts are changed. Developers should ensure that any custom subscriptions are properly managed and cleaned up to prevent memory leaks.
flowchart TD
A[Layout Change Detected] --> B[Clean Up Old Chart Contexts]
B --> C[Get New Chart Count]
C --> D[Initialize Each Chart]
D --> E[Create Chart Context]
E --> F[Activate Default Indicators]
F --> G[Set Up Data Listeners]
G --> H[Wait for Data Load]
H --> I[Export Chart Data]
I --> J[Run Indicators for Chart]
J --> K[Process Results]
K --> L[Draw Indicators]
style A fill:#f9f,stroke:#333
style L fill:#bbf,stroke:#333
Managing multiple active charts simultaneously requires careful resource management to maintain performance. The system automatically handles much of this through the _cleanup_all_charts() method, which is called before reinitializing charts during layout changes. This method iterates through all chart contexts, deactivates indicators, clears drawings, and calls destroy callbacks to ensure proper cleanup of resources.
For performance optimization, developers should consider using the unloadUnusedCharts() method, which unloads invisible charts in a multi-chart layout to release memory. This is particularly useful for layouts with many charts where only a subset is visible at any given time. The unloaded charts are treated as new charts when they become visible again, which triggers reinitialization but reduces memory usage.
Subscription management is critical for preventing memory leaks. The system automatically handles subscriptions through the TVSubscription class, which tracks subscription state and provides methods for cleanup. Developers should ensure that any custom event listeners are properly unsubscribed when no longer needed, particularly during layout changes. The unsubscribe() method on TVWidget should be used to remove event listeners that are no longer required.
Performance considerations include the computational cost of running multiple indicators simultaneously across several charts. To mitigate this, the system processes indicators sequentially per chart rather than attempting parallel execution, which helps prevent overwhelming the system. Developers can further optimize performance by selectively activating indicators only on charts where they are needed, rather than activating them on all charts by default.
PyTradingView's multi-chart support provides a robust framework for managing multiple chart instances within a single widget layout. The system combines the TVWidget and TVChart APIs with the ChartContextManager to enable flexible chart management, isolated indicator states, and responsive layout changes. By leveraging the chartsCount(), chart(index), and activeChart() methods, developers can effectively navigate and manipulate multiple charts.
The event-driven approach to layout changes, centered around the 'layout_changed' subscription and the _handle_layout_changed logic in TVEngineRuntime, ensures that the system can dynamically adapt to user interactions. The automatic reinitialization of all charts during layout switches maintains consistency across the application. The ChartContextManager plays a vital role in maintaining data isolation between charts while still allowing for coordinated analysis when needed.
For optimal performance, developers should carefully manage resources, use the provided cleanup mechanisms, and consider the computational implications of running multiple indicators across several charts simultaneously. By following these practices, applications can provide a responsive and efficient multi-chart experience for users.