|
26 | 26 | ] |
27 | 27 | }, |
28 | 28 | { |
29 | | - "cell_type": "code", |
30 | | - "execution_count": null, |
| 29 | + "cell_type": "markdown", |
31 | 30 | "id": "2", |
32 | 31 | "metadata": {}, |
33 | | - "outputs": [], |
34 | 32 | "source": [ |
35 | | - "# Sample data\n", |
36 | | - "da = xr.DataArray(\n", |
37 | | - " np.random.rand(12, 3) * 100,\n", |
38 | | - " dims=[\"month\", \"category\"],\n", |
39 | | - " coords={\n", |
40 | | - " \"month\": [\n", |
41 | | - " \"Jan\",\n", |
42 | | - " \"Feb\",\n", |
43 | | - " \"Mar\",\n", |
44 | | - " \"Apr\",\n", |
45 | | - " \"May\",\n", |
46 | | - " \"Jun\",\n", |
47 | | - " \"Jul\",\n", |
48 | | - " \"Aug\",\n", |
49 | | - " \"Sep\",\n", |
50 | | - " \"Oct\",\n", |
51 | | - " \"Nov\",\n", |
52 | | - " \"Dec\",\n", |
53 | | - " ],\n", |
54 | | - " \"category\": [\"A\", \"B\", \"C\"],\n", |
55 | | - " },\n", |
56 | | - " name=\"sales\",\n", |
57 | | - ")" |
| 33 | + "## Basic Example" |
58 | 34 | ] |
59 | 35 | }, |
60 | 36 | { |
61 | | - "cell_type": "markdown", |
| 37 | + "cell_type": "code", |
| 38 | + "execution_count": null, |
62 | 39 | "id": "3", |
63 | 40 | "metadata": {}, |
| 41 | + "outputs": [], |
64 | 42 | "source": [ |
65 | | - "## Fast Bar Chart" |
| 43 | + "# Quarterly revenue data by product and region\n", |
| 44 | + "np.random.seed(42)\n", |
| 45 | + "da = xr.DataArray(\n", |
| 46 | + " np.random.rand(4, 3, 2) * 100 + 50,\n", |
| 47 | + " dims=[\"quarter\", \"product\", \"region\"],\n", |
| 48 | + " coords={\n", |
| 49 | + " \"quarter\": [\"Q1\", \"Q2\", \"Q3\", \"Q4\"],\n", |
| 50 | + " \"product\": [\"Widgets\", \"Gadgets\", \"Gizmos\"],\n", |
| 51 | + " \"region\": [\"North\", \"South\"],\n", |
| 52 | + " },\n", |
| 53 | + " name=\"revenue\",\n", |
| 54 | + ")\n", |
| 55 | + "\n", |
| 56 | + "xpx(da).fast_bar()" |
66 | 57 | ] |
67 | 58 | }, |
68 | 59 | { |
|
72 | 63 | "metadata": {}, |
73 | 64 | "outputs": [], |
74 | 65 | "source": [ |
75 | | - "xpx(da).fast_bar()" |
| 66 | + "# Comparison with regular bar()\n", |
| 67 | + "xpx(da).bar()" |
76 | 68 | ] |
77 | 69 | }, |
78 | 70 | { |
79 | 71 | "cell_type": "markdown", |
80 | 72 | "id": "5", |
81 | 73 | "metadata": {}, |
82 | 74 | "source": [ |
83 | | - "## Comparison with Regular Bar Chart" |
| 75 | + "## With Faceting" |
84 | 76 | ] |
85 | 77 | }, |
86 | 78 | { |
|
90 | 82 | "metadata": {}, |
91 | 83 | "outputs": [], |
92 | 84 | "source": [ |
93 | | - "xpx(da).bar()" |
| 85 | + "xpx(da).fast_bar(facet_col=\"region\")" |
94 | 86 | ] |
95 | 87 | }, |
96 | 88 | { |
97 | 89 | "cell_type": "markdown", |
98 | 90 | "id": "7", |
99 | 91 | "metadata": {}, |
100 | 92 | "source": [ |
101 | | - "## Comparison with Area Chart" |
| 93 | + "## With Animation" |
102 | 94 | ] |
103 | 95 | }, |
104 | 96 | { |
|
108 | 100 | "metadata": {}, |
109 | 101 | "outputs": [], |
110 | 102 | "source": [ |
111 | | - "xpx(da).area()" |
| 103 | + "# Multi-year data for animation\n", |
| 104 | + "np.random.seed(123)\n", |
| 105 | + "da_anim = xr.DataArray(\n", |
| 106 | + " np.random.rand(4, 3, 5) * 100 + 20,\n", |
| 107 | + " dims=[\"quarter\", \"product\", \"year\"],\n", |
| 108 | + " coords={\n", |
| 109 | + " \"quarter\": [\"Q1\", \"Q2\", \"Q3\", \"Q4\"],\n", |
| 110 | + " \"product\": [\"Widgets\", \"Gadgets\", \"Gizmos\"],\n", |
| 111 | + " \"year\": [2020, 2021, 2022, 2023, 2024],\n", |
| 112 | + " },\n", |
| 113 | + " name=\"revenue\",\n", |
| 114 | + ")\n", |
| 115 | + "\n", |
| 116 | + "xpx(da_anim).fast_bar(animation_frame=\"year\")" |
112 | 117 | ] |
113 | 118 | }, |
114 | 119 | { |
115 | 120 | "cell_type": "markdown", |
116 | 121 | "id": "9", |
117 | 122 | "metadata": {}, |
118 | 123 | "source": [ |
119 | | - "## With Animation\n", |
120 | | - "\n", |
121 | | - "The `fast_bar` styling also applies to animation frames:" |
| 124 | + "## Faceting + Animation" |
122 | 125 | ] |
123 | 126 | }, |
124 | 127 | { |
|
128 | 131 | "metadata": {}, |
129 | 132 | "outputs": [], |
130 | 133 | "source": [ |
131 | | - "# Data with animation dimension\n", |
132 | | - "da_anim = xr.DataArray(\n", |
133 | | - " np.random.rand(12, 3, 5) * 100,\n", |
134 | | - " dims=[\"month\", \"category\", \"year\"],\n", |
| 134 | + "# 4D data: quarter x product x region x year\n", |
| 135 | + "np.random.seed(456)\n", |
| 136 | + "da_4d = xr.DataArray(\n", |
| 137 | + " np.random.rand(4, 3, 2, 4) * 80 + 30,\n", |
| 138 | + " dims=[\"quarter\", \"product\", \"region\", \"year\"],\n", |
135 | 139 | " coords={\n", |
136 | | - " \"month\": [\n", |
137 | | - " \"Jan\",\n", |
138 | | - " \"Feb\",\n", |
139 | | - " \"Mar\",\n", |
140 | | - " \"Apr\",\n", |
141 | | - " \"May\",\n", |
142 | | - " \"Jun\",\n", |
143 | | - " \"Jul\",\n", |
144 | | - " \"Aug\",\n", |
145 | | - " \"Sep\",\n", |
146 | | - " \"Oct\",\n", |
147 | | - " \"Nov\",\n", |
148 | | - " \"Dec\",\n", |
149 | | - " ],\n", |
150 | | - " \"category\": [\"A\", \"B\", \"C\"],\n", |
151 | | - " \"year\": [2020, 2021, 2022, 2023, 2024],\n", |
| 140 | + " \"quarter\": [\"Q1\", \"Q2\", \"Q3\", \"Q4\"],\n", |
| 141 | + " \"product\": [\"Widgets\", \"Gadgets\", \"Gizmos\"],\n", |
| 142 | + " \"region\": [\"North\", \"South\"],\n", |
| 143 | + " \"year\": [2021, 2022, 2023, 2024],\n", |
152 | 144 | " },\n", |
153 | | - " name=\"sales\",\n", |
| 145 | + " name=\"revenue\",\n", |
154 | 146 | ")\n", |
155 | 147 | "\n", |
156 | | - "xpx(da_anim).fast_bar(animation_frame=\"year\")" |
| 148 | + "xpx(da_4d).fast_bar(facet_col=\"region\", animation_frame=\"year\")" |
157 | 149 | ] |
158 | 150 | }, |
159 | 151 | { |
160 | 152 | "cell_type": "markdown", |
161 | 153 | "id": "11", |
162 | 154 | "metadata": {}, |
163 | 155 | "source": [ |
164 | | - "## When to Use\n", |
165 | | - "\n", |
166 | | - "| Method | Use when... |\n", |
167 | | - "|--------|-------------|\n", |
168 | | - "| `fast_bar()` | Large datasets, animations with many frames, performance matters |\n", |
169 | | - "| `bar()` | Need precise bar positioning, grouped bars, pattern fills |\n", |
170 | | - "| `area()` | Want smooth continuous fills, standard area chart appearance |" |
171 | | - ] |
172 | | - }, |
173 | | - { |
174 | | - "cell_type": "markdown", |
175 | | - "id": "12", |
176 | | - "metadata": {}, |
177 | | - "source": [ |
178 | | - "## Negative Values\n", |
| 156 | + "## Positive and Negative Values\n", |
179 | 157 | "\n", |
180 | | - "Testing with all negative values:" |
| 158 | + "`fast_bar()` classifies each trace by its values:\n", |
| 159 | + "- **Purely positive** → stacks upward\n", |
| 160 | + "- **Purely negative** → stacks downward\n", |
| 161 | + "- **Mixed signs** → warning + dashed line (use `bar()` instead)" |
181 | 162 | ] |
182 | 163 | }, |
183 | 164 | { |
184 | 165 | "cell_type": "code", |
185 | 166 | "execution_count": null, |
186 | | - "id": "13", |
| 167 | + "id": "12", |
187 | 168 | "metadata": {}, |
188 | 169 | "outputs": [], |
189 | 170 | "source": [ |
190 | | - "# All negative values\n", |
191 | | - "da_negative = xr.DataArray(\n", |
192 | | - " -np.random.rand(6, 3) * 100,\n", |
| 171 | + "# Profit (positive) and Loss (negative) - stacks correctly\n", |
| 172 | + "np.random.seed(789)\n", |
| 173 | + "da_split = xr.DataArray(\n", |
| 174 | + " np.column_stack(\n", |
| 175 | + " [\n", |
| 176 | + " np.random.rand(6) * 80 + 20, # Revenue: positive\n", |
| 177 | + " -np.random.rand(6) * 50 - 10, # Costs: negative\n", |
| 178 | + " ]\n", |
| 179 | + " ),\n", |
193 | 180 | " dims=[\"month\", \"category\"],\n", |
194 | 181 | " coords={\n", |
195 | 182 | " \"month\": [\"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\"],\n", |
196 | | - " \"category\": [\"A\", \"B\", \"C\"],\n", |
| 183 | + " \"category\": [\"Revenue\", \"Costs\"],\n", |
197 | 184 | " },\n", |
198 | | - " name=\"loss\",\n", |
| 185 | + " name=\"financials\",\n", |
199 | 186 | ")\n", |
200 | 187 | "\n", |
201 | | - "xpx(da_negative).fast_bar()" |
202 | | - ] |
203 | | - }, |
204 | | - { |
205 | | - "cell_type": "code", |
206 | | - "execution_count": null, |
207 | | - "id": "14", |
208 | | - "metadata": {}, |
209 | | - "outputs": [], |
210 | | - "source": [ |
211 | | - "# Comparison: regular bar with negative values\n", |
212 | | - "xpx(da_negative).bar()" |
213 | | - ] |
214 | | - }, |
215 | | - { |
216 | | - "cell_type": "markdown", |
217 | | - "id": "15", |
218 | | - "metadata": {}, |
219 | | - "source": [ |
220 | | - "## Mixed Values (Positive and Negative)\n", |
221 | | - "\n", |
222 | | - "`fast_bar()` classifies each trace (color group) by its values:\n", |
223 | | - "- **Purely positive** → stacks upward (stackgroup='positive')\n", |
224 | | - "- **Purely negative** → stacks downward (stackgroup='negative') \n", |
225 | | - "- **Mixed signs** → shown as dashed line, no stacking\n", |
226 | | - "\n", |
227 | | - "When one column is all positive and another all negative, they stack correctly in separate groups:" |
| 188 | + "xpx(da_split).fast_bar()" |
228 | 189 | ] |
229 | 190 | }, |
230 | 191 | { |
231 | 192 | "cell_type": "code", |
232 | 193 | "execution_count": null, |
233 | | - "id": "16", |
| 194 | + "id": "13", |
234 | 195 | "metadata": {}, |
235 | 196 | "outputs": [], |
236 | 197 | "source": [ |
237 | | - "# Column A positive, Column B negative - stacks correctly\n", |
238 | | - "da_split = xr.DataArray(\n", |
239 | | - " np.array(\n", |
| 198 | + "# With animation - sign classification is consistent across frames\n", |
| 199 | + "np.random.seed(321)\n", |
| 200 | + "da_split_anim = xr.DataArray(\n", |
| 201 | + " np.stack(\n", |
240 | 202 | " [\n", |
241 | | - " [50, -20],\n", |
242 | | - " [60, -40],\n", |
243 | | - " [30, -30],\n", |
244 | | - " [70, -25],\n", |
245 | | - " [40, -35],\n", |
246 | | - " [55, -15],\n", |
247 | | - " ]\n", |
| 203 | + " np.column_stack([np.random.rand(6) * 80 + 20, -np.random.rand(6) * 50 - 10])\n", |
| 204 | + " for _ in range(4)\n", |
| 205 | + " ],\n", |
| 206 | + " axis=-1,\n", |
248 | 207 | " ),\n", |
249 | | - " dims=[\"month\", \"category\"],\n", |
| 208 | + " dims=[\"month\", \"category\", \"year\"],\n", |
250 | 209 | " coords={\n", |
251 | 210 | " \"month\": [\"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\"],\n", |
252 | | - " \"category\": [\"Profit\", \"Loss\"],\n", |
| 211 | + " \"category\": [\"Revenue\", \"Costs\"],\n", |
| 212 | + " \"year\": [2021, 2022, 2023, 2024],\n", |
253 | 213 | " },\n", |
254 | 214 | " name=\"financials\",\n", |
255 | 215 | ")\n", |
256 | 216 | "\n", |
257 | | - "xpx(da_split).fast_bar()" |
| 217 | + "xpx(da_split_anim).fast_bar(animation_frame=\"year\")" |
258 | 218 | ] |
259 | 219 | }, |
260 | 220 | { |
261 | 221 | "cell_type": "markdown", |
262 | | - "id": "17", |
| 222 | + "id": "14", |
263 | 223 | "metadata": {}, |
264 | 224 | "source": [ |
265 | | - "Truly mixed columns (each has both + and -) are shown as dashed lines:" |
| 225 | + "## Mixed Sign Warning\n", |
| 226 | + "\n", |
| 227 | + "When a trace has both positive and negative values, `fast_bar()` shows a warning and displays it as a dashed line:" |
266 | 228 | ] |
267 | 229 | }, |
268 | 230 | { |
269 | 231 | "cell_type": "code", |
270 | 232 | "execution_count": null, |
271 | | - "id": "18", |
| 233 | + "id": "15", |
272 | 234 | "metadata": {}, |
273 | 235 | "outputs": [], |
274 | 236 | "source": [ |
275 | | - "# Truly mixed columns - shown as dashed lines (use bar() for these)\n", |
| 237 | + "# Both columns have mixed signs - triggers warning\n", |
276 | 238 | "da_mixed = xr.DataArray(\n", |
277 | 239 | " np.array(\n", |
278 | 240 | " [\n", |
279 | 241 | " [50, -30],\n", |
280 | 242 | " [-40, 60],\n", |
281 | 243 | " [30, -50],\n", |
| 244 | + " [-20, 40],\n", |
282 | 245 | " ]\n", |
283 | 246 | " ),\n", |
284 | 247 | " dims=[\"month\", \"category\"],\n", |
285 | 248 | " coords={\n", |
286 | | - " \"month\": [\"Jan\", \"Feb\", \"Mar\"],\n", |
| 249 | + " \"month\": [\"Jan\", \"Feb\", \"Mar\", \"Apr\"],\n", |
287 | 250 | " \"category\": [\"A\", \"B\"],\n", |
288 | 251 | " },\n", |
289 | 252 | ")\n", |
290 | 253 | "\n", |
| 254 | + "# This will show a warning\n", |
291 | 255 | "xpx(da_mixed).fast_bar()" |
292 | 256 | ] |
293 | 257 | }, |
294 | 258 | { |
295 | 259 | "cell_type": "code", |
296 | 260 | "execution_count": null, |
297 | | - "id": "19", |
| 261 | + "id": "16", |
298 | 262 | "metadata": {}, |
299 | 263 | "outputs": [], |
300 | 264 | "source": [ |
301 | | - "# Comparison: regular bar with mixed values\n", |
| 265 | + "# For mixed data, use bar() instead\n", |
302 | 266 | "xpx(da_mixed).bar()" |
303 | 267 | ] |
| 268 | + }, |
| 269 | + { |
| 270 | + "cell_type": "markdown", |
| 271 | + "id": "17", |
| 272 | + "metadata": {}, |
| 273 | + "source": [ |
| 274 | + "## When to Use\n", |
| 275 | + "\n", |
| 276 | + "| Method | Use when... |\n", |
| 277 | + "|--------|-------------|\n", |
| 278 | + "| `fast_bar()` | Large datasets, animations, performance matters, data is same-sign per trace |\n", |
| 279 | + "| `bar()` | Need grouped bars, pattern fills, or have mixed +/- values per trace |\n", |
| 280 | + "| `area()` | Want smooth continuous fills |" |
| 281 | + ] |
304 | 282 | } |
305 | 283 | ], |
306 | 284 | "metadata": { |
|
0 commit comments