|
1 | 1 | """ |
2 | | -line-basic: Basic Line Chart |
| 2 | +line-basic: Basic Line Plot |
3 | 3 | Library: altair |
4 | 4 | """ |
5 | 5 |
|
6 | | -from typing import TYPE_CHECKING |
7 | | - |
8 | 6 | import altair as alt |
9 | 7 | import pandas as pd |
10 | 8 |
|
11 | 9 |
|
12 | | -if TYPE_CHECKING: |
13 | | - from altair import Chart |
14 | | - |
15 | | -# Style guide colors |
16 | | -PYTHON_BLUE = "#306998" |
17 | | - |
18 | | - |
19 | | -def create_plot( |
20 | | - data: pd.DataFrame, |
21 | | - x: str, |
22 | | - y: str, |
23 | | - title: str | None = None, |
24 | | - xlabel: str | None = None, |
25 | | - ylabel: str | None = None, |
26 | | - color: str = PYTHON_BLUE, |
27 | | - linewidth: float = 2, |
28 | | - marker: str | None = None, |
29 | | - marker_size: int = 60, |
30 | | - alpha: float = 1.0, |
31 | | - linestyle: str = "solid", |
32 | | - **kwargs, |
33 | | -) -> "Chart": |
34 | | - """ |
35 | | - Create a basic line chart showing trends over a continuous axis. |
36 | | -
|
37 | | - Args: |
38 | | - data: Input DataFrame with required columns |
39 | | - x: Column name for x-axis values (typically time or sequence) |
40 | | - y: Column name for y-axis values |
41 | | - title: Plot title (default: None) |
42 | | - xlabel: Custom x-axis label (default: uses column name) |
43 | | - ylabel: Custom y-axis label (default: uses column name) |
44 | | - color: Line color (default: Python Blue #306998) |
45 | | - linewidth: Width of the line (default: 2) |
46 | | - marker: Marker style - 'circle', 'square', 'diamond', etc. (default: None) |
47 | | - marker_size: Size of markers if enabled (default: 60) |
48 | | - alpha: Transparency level for the line (default: 1.0) |
49 | | - linestyle: Line style - 'solid', 'dashed', 'dotted' (default: 'solid') |
50 | | - **kwargs: Additional parameters for altair chart configuration |
51 | | -
|
52 | | - Returns: |
53 | | - Altair Chart object |
54 | | -
|
55 | | - Raises: |
56 | | - ValueError: If data is empty |
57 | | - KeyError: If required columns not found |
58 | | -
|
59 | | - Example: |
60 | | - >>> data = pd.DataFrame({ |
61 | | - ... 'month': [1, 2, 3, 4, 5, 6], |
62 | | - ... 'sales': [100, 150, 130, 180, 200, 190] |
63 | | - ... }) |
64 | | - >>> chart = create_plot(data, x='month', y='sales') |
65 | | - """ |
66 | | - # Input validation |
67 | | - if data.empty: |
68 | | - raise ValueError("Data cannot be empty") |
69 | | - |
70 | | - for col in [x, y]: |
71 | | - if col not in data.columns: |
72 | | - available = ", ".join(data.columns) |
73 | | - raise KeyError(f"Column '{col}' not found. Available columns: {available}") |
74 | | - |
75 | | - # Sort data by x-axis to ensure proper line connections |
76 | | - plot_data = data.sort_values(by=x).copy() |
| 10 | +# Data |
| 11 | +data = pd.DataFrame({"time": [1, 2, 3, 4, 5, 6, 7], "value": [10, 15, 13, 18, 22, 19, 25]}) |
77 | 12 |
|
78 | | - # Determine x encoding type based on data |
79 | | - x_dtype = plot_data[x].dtype |
80 | | - if pd.api.types.is_datetime64_any_dtype(x_dtype): |
81 | | - x_encoding = f"{x}:T" |
82 | | - else: |
83 | | - x_encoding = f"{x}:Q" |
84 | | - |
85 | | - # Map linestyle to altair strokeDash |
86 | | - stroke_dash_map = {"solid": [], "dashed": [8, 4], "dotted": [2, 2]} |
87 | | - stroke_dash = stroke_dash_map.get(linestyle, []) |
88 | | - |
89 | | - # Create the line chart |
90 | | - line = ( |
91 | | - alt.Chart(plot_data) |
92 | | - .mark_line(color=color, strokeWidth=linewidth, opacity=alpha, strokeDash=stroke_dash) |
93 | | - .encode( |
94 | | - x=alt.X( |
95 | | - x_encoding, |
96 | | - title=xlabel or x, |
97 | | - axis=alt.Axis(labelAngle=0, labelLimit=200, labelFontSize=16, titleFontSize=20), |
98 | | - ), |
99 | | - y=alt.Y( |
100 | | - f"{y}:Q", |
101 | | - title=ylabel or y, |
102 | | - scale=alt.Scale(zero=False), |
103 | | - axis=alt.Axis(labelFontSize=16, titleFontSize=20), |
104 | | - ), |
105 | | - tooltip=[ |
106 | | - alt.Tooltip(x_encoding, title=xlabel or x), |
107 | | - alt.Tooltip(f"{y}:Q", title=ylabel or y, format=".2f"), |
108 | | - ], |
109 | | - ) |
110 | | - ) |
111 | | - |
112 | | - # Add markers if specified |
113 | | - if marker: |
114 | | - points = ( |
115 | | - alt.Chart(plot_data) |
116 | | - .mark_point(color=color, size=marker_size, filled=True, shape=marker, opacity=alpha) |
117 | | - .encode( |
118 | | - x=alt.X(x_encoding), |
119 | | - y=alt.Y(f"{y}:Q"), |
120 | | - tooltip=[ |
121 | | - alt.Tooltip(x_encoding, title=xlabel or x), |
122 | | - alt.Tooltip(f"{y}:Q", title=ylabel or y, format=".2f"), |
123 | | - ], |
124 | | - ) |
125 | | - ) |
126 | | - chart_base = line + points |
127 | | - else: |
128 | | - chart_base = line |
129 | | - |
130 | | - # Apply properties and configuration |
131 | | - # Target: 4800 × 2700 px with scale_factor=3.0 -> 1600 × 900 base |
132 | | - title_config = alt.TitleParams(text=title, fontSize=20, anchor="middle") if title else None |
133 | | - chart = ( |
134 | | - chart_base.properties(width=1600, height=900, title=title_config) |
135 | | - .configure_view(strokeWidth=0) |
136 | | - .configure_axis(grid=True, gridOpacity=0.3, gridDash=[3, 3], domainWidth=1, tickWidth=1) |
| 13 | +# Create line chart |
| 14 | +line = ( |
| 15 | + alt.Chart(data) |
| 16 | + .mark_line(strokeWidth=2, color="#306998") |
| 17 | + .encode( |
| 18 | + x=alt.X("time:Q", title="Time", axis=alt.Axis(labelFontSize=16, titleFontSize=20)), |
| 19 | + y=alt.Y("value:Q", title="Value", axis=alt.Axis(labelFontSize=16, titleFontSize=20)), |
137 | 20 | ) |
| 21 | +) |
138 | 22 |
|
139 | | - return chart |
| 23 | +# Add points on the line for clarity |
| 24 | +points = alt.Chart(data).mark_point(size=100, color="#306998", filled=True).encode(x="time:Q", y="value:Q") |
140 | 25 |
|
| 26 | +# Combine and configure chart |
| 27 | +chart = ( |
| 28 | + (line + points) |
| 29 | + .properties(width=1600, height=900, title=alt.Title("Basic Line Plot", fontSize=20)) |
| 30 | + .configure_view(strokeWidth=0) |
| 31 | + .configure_axis(grid=True, gridOpacity=0.3) |
| 32 | +) |
141 | 33 |
|
142 | | -if __name__ == "__main__": |
143 | | - # Sample data for testing - monthly sales trend |
144 | | - sample_data = pd.DataFrame( |
145 | | - { |
146 | | - "Month": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], |
147 | | - "Sales": [120, 150, 170, 165, 180, 220, 250, 240, 210, 190, 180, 200], |
148 | | - } |
149 | | - ) |
150 | | - |
151 | | - # Create plot with markers |
152 | | - chart = create_plot( |
153 | | - sample_data, |
154 | | - x="Month", |
155 | | - y="Sales", |
156 | | - title="Monthly Sales Trend (2024)", |
157 | | - xlabel="Month", |
158 | | - ylabel="Sales (thousands)", |
159 | | - linewidth=2.5, |
160 | | - marker="circle", |
161 | | - marker_size=80, |
162 | | - ) |
163 | | - |
164 | | - # Save as PNG - scale_factor=3.0 gives 4800 × 2700 px |
165 | | - chart.save("plot.png", scale_factor=3.0) |
166 | | - print("Plot saved to plot.png") |
| 34 | +# Save as PNG (1600 × 900 at scale 3 = 4800 × 2700 px) |
| 35 | +chart.save("plot.png", scale_factor=3.0) |
0 commit comments