|
| 1 | +""" pyplots.ai |
| 2 | +line-realtime: Real-Time Updating Line Chart |
| 3 | +Library: letsplot 4.8.2 | Python 3.13.11 |
| 4 | +Quality: 91/100 | Created: 2025-12-31 |
| 5 | +""" |
| 6 | + |
| 7 | +import numpy as np |
| 8 | +import pandas as pd |
| 9 | +from lets_plot import ( |
| 10 | + LetsPlot, |
| 11 | + aes, |
| 12 | + element_blank, |
| 13 | + element_line, |
| 14 | + element_text, |
| 15 | + geom_area, |
| 16 | + geom_hline, |
| 17 | + geom_line, |
| 18 | + geom_point, |
| 19 | + geom_text, |
| 20 | + ggplot, |
| 21 | + ggsize, |
| 22 | + labs, |
| 23 | + scale_alpha_identity, |
| 24 | + scale_y_continuous, |
| 25 | + theme, |
| 26 | + theme_minimal, |
| 27 | +) |
| 28 | +from lets_plot.export import ggsave |
| 29 | + |
| 30 | + |
| 31 | +LetsPlot.setup_html() |
| 32 | + |
| 33 | +# Data - Simulated CPU usage with real-time streaming effect |
| 34 | +np.random.seed(42) |
| 35 | +n_points = 100 |
| 36 | + |
| 37 | +# Generate realistic CPU usage with some noise and occasional spikes |
| 38 | +base_usage = 35 + 15 * np.sin(np.linspace(0, 4 * np.pi, n_points)) # Oscillating base |
| 39 | +noise = np.random.normal(0, 5, n_points) |
| 40 | +spikes = np.zeros(n_points) |
| 41 | +spike_indices = [25, 48, 72, 88] |
| 42 | +for idx in spike_indices: |
| 43 | + spikes[idx : idx + 3] = np.array([15, 25, 10])[: min(3, n_points - idx)] |
| 44 | +cpu_usage = np.clip(base_usage + noise + spikes, 0, 100) |
| 45 | + |
| 46 | +# Create alpha gradient for fade effect (older points fade out) |
| 47 | +alpha_values = np.linspace(0.2, 1.0, n_points) |
| 48 | + |
| 49 | +# Use numeric index for x-axis |
| 50 | +df = pd.DataFrame({"x_idx": range(n_points), "cpu_usage": cpu_usage, "alpha": alpha_values}) |
| 51 | + |
| 52 | +# Get latest value for annotation |
| 53 | +latest_value = cpu_usage[-1] |
| 54 | + |
| 55 | +# Create annotation dataframes |
| 56 | +annotation_current = pd.DataFrame( |
| 57 | + {"x_idx": [n_points - 1], "cpu_usage": [latest_value + 8], "label": [f"Current: {latest_value:.1f}%"]} |
| 58 | +) |
| 59 | +annotation_fade = pd.DataFrame({"x_idx": [5], "cpu_usage": [10], "label": ["← older data fades"]}) |
| 60 | +annotation_threshold = pd.DataFrame({"x_idx": [n_points - 1], "cpu_usage": [83], "label": ["Warning threshold"]}) |
| 61 | + |
| 62 | +# Create the plot with streaming visualization effect |
| 63 | +plot = ( |
| 64 | + ggplot(df, aes(x="x_idx", y="cpu_usage")) |
| 65 | + # Main line |
| 66 | + + geom_line(color="#306998", size=2.5, alpha=0.9) |
| 67 | + # Add area fill for visual depth |
| 68 | + + geom_area(fill="#306998", alpha=0.15) |
| 69 | + # Add points with size/alpha gradient to show streaming direction |
| 70 | + + geom_point(aes(alpha="alpha"), color="#306998", size=3, show_legend=False) |
| 71 | + # Highlight the latest point prominently |
| 72 | + + geom_point( |
| 73 | + data=df.tail(1), |
| 74 | + mapping=aes(x="x_idx", y="cpu_usage"), |
| 75 | + color="#FFD43B", |
| 76 | + size=8, |
| 77 | + shape=21, |
| 78 | + fill="#FFD43B", |
| 79 | + stroke=2, |
| 80 | + ) |
| 81 | + # Add horizontal reference lines for CPU thresholds |
| 82 | + + geom_hline(yintercept=80, linetype="dashed", color="#DC2626", alpha=0.6, size=1) |
| 83 | + + geom_hline(yintercept=50, linetype="dotted", color="#888888", alpha=0.4, size=0.8) |
| 84 | + # Add text annotations using geom_text |
| 85 | + + geom_text( |
| 86 | + data=annotation_current, |
| 87 | + mapping=aes(x="x_idx", y="cpu_usage", label="label"), |
| 88 | + color="#FFD43B", |
| 89 | + size=16, |
| 90 | + fontface="bold", |
| 91 | + hjust=1, |
| 92 | + ) |
| 93 | + + geom_text( |
| 94 | + data=annotation_fade, mapping=aes(x="x_idx", y="cpu_usage", label="label"), color="#888888", size=12, hjust=0 |
| 95 | + ) |
| 96 | + + geom_text( |
| 97 | + data=annotation_threshold, |
| 98 | + mapping=aes(x="x_idx", y="cpu_usage", label="label"), |
| 99 | + color="#DC2626", |
| 100 | + size=11, |
| 101 | + hjust=1, |
| 102 | + ) |
| 103 | + # Labels and title |
| 104 | + + labs(title="line-realtime · letsplot · pyplots.ai", x="Time (samples at 100ms interval)", y="CPU Usage (%)") |
| 105 | + # Scale configuration |
| 106 | + + scale_y_continuous(limits=[0, 100], breaks=[0, 25, 50, 75, 100]) |
| 107 | + + scale_alpha_identity() |
| 108 | + # Theme for large canvas |
| 109 | + + theme_minimal() |
| 110 | + + theme( |
| 111 | + plot_title=element_text(size=28, face="bold"), |
| 112 | + axis_title=element_text(size=22), |
| 113 | + axis_text=element_text(size=16), |
| 114 | + panel_grid_major=element_line(color="#cccccc", size=0.5), |
| 115 | + panel_grid_minor=element_blank(), |
| 116 | + ) |
| 117 | + # Set figure size (will be scaled 3x to 4800x2700) |
| 118 | + + ggsize(1600, 900) |
| 119 | +) |
| 120 | + |
| 121 | +# Save PNG (scale=3 gives 4800x2700) |
| 122 | +ggsave(plot, "plot.png", path=".", scale=3) |
| 123 | + |
| 124 | +# Save HTML for interactivity |
| 125 | +ggsave(plot, "plot.html", path=".") |
0 commit comments