panelbox 0.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. panelbox/__init__.py +67 -0
  2. panelbox/__version__.py +14 -0
  3. panelbox/cli/__init__.py +0 -0
  4. panelbox/cli/{commands}/__init__.py +0 -0
  5. panelbox/core/__init__.py +0 -0
  6. panelbox/core/base_model.py +164 -0
  7. panelbox/core/formula_parser.py +318 -0
  8. panelbox/core/panel_data.py +387 -0
  9. panelbox/core/results.py +366 -0
  10. panelbox/datasets/__init__.py +0 -0
  11. panelbox/datasets/{data}/__init__.py +0 -0
  12. panelbox/gmm/__init__.py +65 -0
  13. panelbox/gmm/difference_gmm.py +645 -0
  14. panelbox/gmm/estimator.py +562 -0
  15. panelbox/gmm/instruments.py +580 -0
  16. panelbox/gmm/results.py +550 -0
  17. panelbox/gmm/system_gmm.py +621 -0
  18. panelbox/gmm/tests.py +535 -0
  19. panelbox/models/__init__.py +11 -0
  20. panelbox/models/dynamic/__init__.py +0 -0
  21. panelbox/models/iv/__init__.py +0 -0
  22. panelbox/models/static/__init__.py +13 -0
  23. panelbox/models/static/fixed_effects.py +516 -0
  24. panelbox/models/static/pooled_ols.py +298 -0
  25. panelbox/models/static/random_effects.py +512 -0
  26. panelbox/report/__init__.py +61 -0
  27. panelbox/report/asset_manager.py +410 -0
  28. panelbox/report/css_manager.py +472 -0
  29. panelbox/report/exporters/__init__.py +15 -0
  30. panelbox/report/exporters/html_exporter.py +440 -0
  31. panelbox/report/exporters/latex_exporter.py +510 -0
  32. panelbox/report/exporters/markdown_exporter.py +446 -0
  33. panelbox/report/renderers/__init__.py +11 -0
  34. panelbox/report/renderers/static/__init__.py +0 -0
  35. panelbox/report/renderers/static_validation_renderer.py +341 -0
  36. panelbox/report/report_manager.py +502 -0
  37. panelbox/report/template_manager.py +337 -0
  38. panelbox/report/transformers/__init__.py +0 -0
  39. panelbox/report/transformers/static/__init__.py +0 -0
  40. panelbox/report/validation_transformer.py +449 -0
  41. panelbox/standard_errors/__init__.py +0 -0
  42. panelbox/templates/__init__.py +0 -0
  43. panelbox/templates/assets/css/base_styles.css +382 -0
  44. panelbox/templates/assets/css/report_components.css +747 -0
  45. panelbox/templates/assets/js/tab-navigation.js +161 -0
  46. panelbox/templates/assets/js/utils.js +276 -0
  47. panelbox/templates/common/footer.html +24 -0
  48. panelbox/templates/common/header.html +44 -0
  49. panelbox/templates/common/meta.html +5 -0
  50. panelbox/templates/validation/interactive/index.html +272 -0
  51. panelbox/templates/validation/interactive/partials/charts.html +58 -0
  52. panelbox/templates/validation/interactive/partials/methodology.html +201 -0
  53. panelbox/templates/validation/interactive/partials/overview.html +146 -0
  54. panelbox/templates/validation/interactive/partials/recommendations.html +101 -0
  55. panelbox/templates/validation/interactive/partials/test_results.html +231 -0
  56. panelbox/utils/__init__.py +0 -0
  57. panelbox/utils/formatting.py +172 -0
  58. panelbox/utils/matrix_ops.py +233 -0
  59. panelbox/utils/statistical.py +173 -0
  60. panelbox/validation/__init__.py +58 -0
  61. panelbox/validation/base.py +175 -0
  62. panelbox/validation/cointegration/__init__.py +0 -0
  63. panelbox/validation/cross_sectional_dependence/__init__.py +13 -0
  64. panelbox/validation/cross_sectional_dependence/breusch_pagan_lm.py +222 -0
  65. panelbox/validation/cross_sectional_dependence/frees.py +297 -0
  66. panelbox/validation/cross_sectional_dependence/pesaran_cd.py +188 -0
  67. panelbox/validation/heteroskedasticity/__init__.py +13 -0
  68. panelbox/validation/heteroskedasticity/breusch_pagan.py +222 -0
  69. panelbox/validation/heteroskedasticity/modified_wald.py +172 -0
  70. panelbox/validation/heteroskedasticity/white.py +208 -0
  71. panelbox/validation/instruments/__init__.py +0 -0
  72. panelbox/validation/robustness/__init__.py +0 -0
  73. panelbox/validation/serial_correlation/__init__.py +13 -0
  74. panelbox/validation/serial_correlation/baltagi_wu.py +220 -0
  75. panelbox/validation/serial_correlation/breusch_godfrey.py +260 -0
  76. panelbox/validation/serial_correlation/wooldridge_ar.py +200 -0
  77. panelbox/validation/specification/__init__.py +16 -0
  78. panelbox/validation/specification/chow.py +273 -0
  79. panelbox/validation/specification/hausman.py +264 -0
  80. panelbox/validation/specification/mundlak.py +331 -0
  81. panelbox/validation/specification/reset.py +273 -0
  82. panelbox/validation/unit_root/__init__.py +0 -0
  83. panelbox/validation/validation_report.py +257 -0
  84. panelbox/validation/validation_suite.py +401 -0
  85. panelbox-0.2.0.dist-info/METADATA +337 -0
  86. panelbox-0.2.0.dist-info/RECORD +90 -0
  87. panelbox-0.2.0.dist-info/WHEEL +5 -0
  88. panelbox-0.2.0.dist-info/entry_points.txt +2 -0
  89. panelbox-0.2.0.dist-info/licenses/LICENSE +21 -0
  90. panelbox-0.2.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,446 @@
1
+ """
2
+ Markdown Exporter for PanelBox Reports.
3
+
4
+ Exports validation and regression results to Markdown format.
5
+ """
6
+
7
+ from pathlib import Path
8
+ from typing import Dict, Any, List, Optional, Union
9
+ import datetime
10
+
11
+
12
+ class MarkdownExporter:
13
+ """
14
+ Exports PanelBox reports to Markdown format.
15
+
16
+ Creates GitHub-flavored Markdown reports suitable for documentation,
17
+ README files, and issue tracking.
18
+
19
+ Parameters
20
+ ----------
21
+ include_toc : bool, default=True
22
+ Include table of contents
23
+ github_flavor : bool, default=True
24
+ Use GitHub-flavored Markdown extensions
25
+
26
+ Examples
27
+ --------
28
+ >>> from panelbox.report.exporters import MarkdownExporter
29
+ >>>
30
+ >>> exporter = MarkdownExporter()
31
+ >>> md = exporter.export_validation_report(validation_data)
32
+ >>> exporter.save(md, 'validation_report.md')
33
+ """
34
+
35
+ def __init__(
36
+ self,
37
+ include_toc: bool = True,
38
+ github_flavor: bool = True
39
+ ):
40
+ """Initialize Markdown Exporter."""
41
+ self.include_toc = include_toc
42
+ self.github_flavor = github_flavor
43
+
44
+ def export_validation_report(
45
+ self,
46
+ validation_data: Dict[str, Any],
47
+ title: str = "Validation Report"
48
+ ) -> str:
49
+ """
50
+ Export complete validation report to Markdown.
51
+
52
+ Parameters
53
+ ----------
54
+ validation_data : dict
55
+ Validation data from ValidationTransformer
56
+ title : str, default="Validation Report"
57
+ Report title
58
+
59
+ Returns
60
+ -------
61
+ str
62
+ Markdown content
63
+
64
+ Examples
65
+ --------
66
+ >>> md = exporter.export_validation_report(
67
+ ... validation_data,
68
+ ... title="Panel Data Validation"
69
+ ... )
70
+ """
71
+ lines = []
72
+
73
+ # Title
74
+ lines.append(f"# {title}")
75
+ lines.append("")
76
+
77
+ # Metadata
78
+ timestamp = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
79
+ lines.append(f"**Generated:** {timestamp}")
80
+ lines.append("")
81
+
82
+ # Summary
83
+ summary = validation_data.get('summary', {})
84
+ lines.append("## Summary")
85
+ lines.append("")
86
+ lines.append(f"- **Total Tests:** {summary.get('total_tests', 0)}")
87
+ lines.append(f"- **Passed:** {summary.get('total_passed', 0)} ✅")
88
+ lines.append(f"- **Failed:** {summary.get('total_failed', 0)} ❌")
89
+ lines.append(f"- **Pass Rate:** {summary.get('pass_rate_formatted', '0%')}")
90
+ lines.append("")
91
+
92
+ # Status indicator
93
+ if summary.get('has_issues', False):
94
+ lines.append(f"> ⚠️ **{summary.get('status_message', 'Issues detected')}**")
95
+ else:
96
+ lines.append(f"> ✅ **{summary.get('status_message', 'All tests passed')}**")
97
+ lines.append("")
98
+
99
+ # TOC
100
+ if self.include_toc:
101
+ lines.append("## Table of Contents")
102
+ lines.append("")
103
+ lines.append("- [Model Information](#model-information)")
104
+ lines.append("- [Test Results](#test-results)")
105
+ if validation_data.get('recommendations'):
106
+ lines.append("- [Recommendations](#recommendations)")
107
+ lines.append("")
108
+
109
+ # Model Information
110
+ model_info = validation_data.get('model_info', {})
111
+ lines.append("## Model Information")
112
+ lines.append("")
113
+ lines.append(f"- **Model Type:** {model_info.get('model_type', 'Unknown')}")
114
+ if 'formula' in model_info:
115
+ lines.append(f"- **Formula:** `{model_info['formula']}`")
116
+ lines.append(f"- **Observations:** {model_info.get('nobs_formatted', model_info.get('nobs', 'N/A'))}")
117
+ if 'n_entities' in model_info:
118
+ lines.append(f"- **Entities:** {model_info.get('n_entities_formatted', model_info.get('n_entities'))}")
119
+ if 'n_periods' in model_info:
120
+ lines.append(f"- **Time Periods:** {model_info.get('n_periods_formatted', model_info.get('n_periods'))}")
121
+ lines.append("")
122
+
123
+ # Test Results
124
+ tests = validation_data.get('tests', [])
125
+ if tests:
126
+ lines.append("## Test Results")
127
+ lines.append("")
128
+
129
+ # Group by category
130
+ categories = {}
131
+ for test in tests:
132
+ cat = test['category']
133
+ if cat not in categories:
134
+ categories[cat] = []
135
+ categories[cat].append(test)
136
+
137
+ # Export each category
138
+ for category, cat_tests in categories.items():
139
+ lines.append(f"### {category}")
140
+ lines.append("")
141
+
142
+ # Table header
143
+ lines.append("| Test | Statistic | P-value | Result |")
144
+ lines.append("|------|-----------|---------|--------|")
145
+
146
+ # Table rows
147
+ for test in cat_tests:
148
+ name = test['name']
149
+ stat = test['statistic_formatted']
150
+ pval = test['pvalue_formatted']
151
+ sig = test.get('significance', '')
152
+ result = test['result']
153
+
154
+ # Emoji indicator
155
+ if result == 'REJECT':
156
+ result_emoji = "❌ REJECT"
157
+ else:
158
+ result_emoji = "✅ ACCEPT"
159
+
160
+ lines.append(f"| {name} | {stat} | {pval}{sig} | {result_emoji} |")
161
+
162
+ lines.append("")
163
+
164
+ # Recommendations
165
+ recommendations = validation_data.get('recommendations', [])
166
+ if recommendations:
167
+ lines.append("## Recommendations")
168
+ lines.append("")
169
+
170
+ for i, rec in enumerate(recommendations, 1):
171
+ severity = rec['severity'].upper()
172
+ category = rec['category']
173
+ issue = rec['issue']
174
+
175
+ # Severity emoji
176
+ if severity == 'CRITICAL':
177
+ emoji = "🔴"
178
+ elif severity == 'HIGH':
179
+ emoji = "🟠"
180
+ elif severity == 'MEDIUM':
181
+ emoji = "🟡"
182
+ else:
183
+ emoji = "🔵"
184
+
185
+ lines.append(f"### {i}. {emoji} {category} ({severity})")
186
+ lines.append("")
187
+ lines.append(f"**Issue:** {issue}")
188
+ lines.append("")
189
+
190
+ # Failed tests
191
+ if rec.get('tests'):
192
+ lines.append("**Failed Tests:**")
193
+ for test in rec['tests']:
194
+ lines.append(f"- {test}")
195
+ lines.append("")
196
+
197
+ # Suggestions
198
+ if rec.get('suggestions'):
199
+ lines.append("**Suggested Actions:**")
200
+ for suggestion in rec['suggestions']:
201
+ lines.append(f"1. {suggestion}")
202
+ lines.append("")
203
+
204
+ # Footer
205
+ lines.append("---")
206
+ lines.append("")
207
+ lines.append("*Generated with [PanelBox](https://github.com/panelbox/panelbox)*")
208
+ lines.append("")
209
+
210
+ return "\n".join(lines)
211
+
212
+ def export_validation_tests(
213
+ self,
214
+ tests: List[Dict[str, Any]]
215
+ ) -> str:
216
+ """
217
+ Export validation tests as Markdown table.
218
+
219
+ Parameters
220
+ ----------
221
+ tests : list of dict
222
+ List of test results
223
+
224
+ Returns
225
+ -------
226
+ str
227
+ Markdown table
228
+
229
+ Examples
230
+ --------
231
+ >>> md_table = exporter.export_validation_tests(tests)
232
+ """
233
+ lines = []
234
+
235
+ # Table header
236
+ lines.append("| Category | Test | Statistic | P-value | DF | Result |")
237
+ lines.append("|----------|------|-----------|---------|----|----|")
238
+
239
+ # Group by category
240
+ categories = {}
241
+ for test in tests:
242
+ cat = test['category']
243
+ if cat not in categories:
244
+ categories[cat] = []
245
+ categories[cat].append(test)
246
+
247
+ # Table rows
248
+ for category, cat_tests in categories.items():
249
+ for i, test in enumerate(cat_tests):
250
+ # Show category only for first test in group
251
+ cat_display = category if i == 0 else ""
252
+
253
+ name = test['name']
254
+ stat = test['statistic_formatted']
255
+ pval = test['pvalue_formatted']
256
+ sig = test.get('significance', '')
257
+ df = test.get('df', 'N/A')
258
+ result = test['result']
259
+
260
+ # Result emoji
261
+ result_emoji = "❌" if result == 'REJECT' else "✅"
262
+
263
+ lines.append(
264
+ f"| {cat_display} | {name} | {stat} | {pval}{sig} | {df} | {result_emoji} {result} |"
265
+ )
266
+
267
+ return "\n".join(lines)
268
+
269
+ def export_regression_table(
270
+ self,
271
+ coefficients: List[Dict[str, Any]],
272
+ model_info: Dict[str, Any],
273
+ title: str = "Regression Results"
274
+ ) -> str:
275
+ """
276
+ Export regression results as Markdown.
277
+
278
+ Parameters
279
+ ----------
280
+ coefficients : list of dict
281
+ Coefficient results
282
+ model_info : dict
283
+ Model information
284
+ title : str, default="Regression Results"
285
+ Table title
286
+
287
+ Returns
288
+ -------
289
+ str
290
+ Markdown table
291
+
292
+ Examples
293
+ --------
294
+ >>> md = exporter.export_regression_table(coefs, info)
295
+ """
296
+ lines = []
297
+
298
+ lines.append(f"## {title}")
299
+ lines.append("")
300
+
301
+ # Table header
302
+ lines.append("| Variable | Coefficient | Std. Error | t-statistic | P-value |")
303
+ lines.append("|----------|-------------|------------|-------------|---------|")
304
+
305
+ # Coefficient rows
306
+ for coef in coefficients:
307
+ var = coef['variable']
308
+ beta = f"{coef['coefficient']:.4f}"
309
+ se = f"{coef['std_error']:.4f}"
310
+ tstat = f"{coef['t_statistic']:.3f}"
311
+ pval = f"{coef['pvalue']:.4f}"
312
+
313
+ # Significance stars
314
+ if coef['pvalue'] < 0.001:
315
+ stars = "***"
316
+ elif coef['pvalue'] < 0.01:
317
+ stars = "**"
318
+ elif coef['pvalue'] < 0.05:
319
+ stars = "*"
320
+ else:
321
+ stars = ""
322
+
323
+ lines.append(
324
+ f"| {var} | {beta}{stars} | ({se}) | {tstat} | {pval} |"
325
+ )
326
+
327
+ lines.append("")
328
+
329
+ # Model statistics
330
+ lines.append("**Model Statistics:**")
331
+ lines.append("")
332
+ if 'r_squared' in model_info:
333
+ lines.append(f"- R²: {model_info['r_squared']:.4f}")
334
+ if 'nobs' in model_info:
335
+ lines.append(f"- Observations: {model_info['nobs']}")
336
+ if 'n_entities' in model_info:
337
+ lines.append(f"- Entities: {model_info['n_entities']}")
338
+ lines.append("")
339
+
340
+ # Note
341
+ lines.append("*Note:* Standard errors in parentheses. Significance: *** p<0.001, ** p<0.01, * p<0.05")
342
+ lines.append("")
343
+
344
+ return "\n".join(lines)
345
+
346
+ def export_summary_stats(
347
+ self,
348
+ stats: List[Dict[str, Any]],
349
+ title: str = "Summary Statistics"
350
+ ) -> str:
351
+ """
352
+ Export summary statistics as Markdown.
353
+
354
+ Parameters
355
+ ----------
356
+ stats : list of dict
357
+ Variable statistics
358
+ title : str, default="Summary Statistics"
359
+ Table title
360
+
361
+ Returns
362
+ -------
363
+ str
364
+ Markdown table
365
+
366
+ Examples
367
+ --------
368
+ >>> md = exporter.export_summary_stats(stats)
369
+ """
370
+ lines = []
371
+
372
+ lines.append(f"## {title}")
373
+ lines.append("")
374
+
375
+ # Table header
376
+ lines.append("| Variable | N | Mean | Std. Dev. | Min | Max |")
377
+ lines.append("|----------|---|------|-----------|-----|-----|")
378
+
379
+ # Data rows
380
+ for stat in stats:
381
+ var = stat['variable']
382
+ n = stat['count']
383
+ mean = f"{stat['mean']:.3f}"
384
+ std = f"{stat['std']:.3f}"
385
+ min_val = f"{stat['min']:.3f}"
386
+ max_val = f"{stat['max']:.3f}"
387
+
388
+ lines.append(
389
+ f"| {var} | {n} | {mean} | {std} | {min_val} | {max_val} |"
390
+ )
391
+
392
+ lines.append("")
393
+
394
+ return "\n".join(lines)
395
+
396
+ def save(
397
+ self,
398
+ markdown_content: str,
399
+ output_path: Union[str, Path],
400
+ overwrite: bool = False
401
+ ) -> Path:
402
+ """
403
+ Save Markdown content to file.
404
+
405
+ Parameters
406
+ ----------
407
+ markdown_content : str
408
+ Markdown content
409
+ output_path : str or Path
410
+ Output file path
411
+ overwrite : bool, default=False
412
+ Overwrite existing file
413
+
414
+ Returns
415
+ -------
416
+ Path
417
+ Path to saved file
418
+
419
+ Examples
420
+ --------
421
+ >>> exporter.save(md, 'report.md')
422
+ """
423
+ output_path = Path(output_path)
424
+
425
+ # Check if file exists
426
+ if output_path.exists() and not overwrite:
427
+ raise FileExistsError(
428
+ f"File already exists: {output_path}. "
429
+ "Use overwrite=True to replace."
430
+ )
431
+
432
+ # Create parent directories
433
+ output_path.parent.mkdir(parents=True, exist_ok=True)
434
+
435
+ # Write file
436
+ output_path.write_text(markdown_content, encoding='utf-8')
437
+
438
+ return output_path
439
+
440
+ def __repr__(self) -> str:
441
+ """String representation."""
442
+ return (
443
+ f"MarkdownExporter("
444
+ f"include_toc={self.include_toc}, "
445
+ f"github_flavor={self.github_flavor})"
446
+ )
@@ -0,0 +1,11 @@
1
+ """
2
+ PanelBox Report Renderers.
3
+
4
+ Provides chart rendering for static and interactive reports.
5
+ """
6
+
7
+ from .static_validation_renderer import StaticValidationRenderer
8
+
9
+ __all__ = [
10
+ 'StaticValidationRenderer',
11
+ ]
File without changes