multifunctionplotter 1.0.3__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.
@@ -0,0 +1,396 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ mfp_help.py — MFP Manual Page
4
+ ==============================
5
+ Import and call ``show()`` to print the full manual, or call individual
6
+ section printers for targeted help.
7
+
8
+ Usage from CLI:
9
+ python mfp_help.py # full manual
10
+ python mfp_help.py styles # just the styles section
11
+ python mfp_help.py errorbars
12
+ python mfp_help.py colormap
13
+ python mfp_help.py 2d
14
+ python mfp_help.py logscale
15
+ python mfp_help.py subplots
16
+ python mfp_help.py save
17
+ """
18
+
19
+ # ── ANSI colours (gracefully disabled on Windows / dumb terminals) ────────────
20
+ import os, sys
21
+
22
+ _NO_COLOR = not sys.stdout.isatty() or os.name == "nt"
23
+
24
+ def _c(code: str, text: str) -> str:
25
+ return text if _NO_COLOR else f"\033[{code}m{text}\033[0m"
26
+
27
+ H1 = lambda t: _c("1;36", t) # bold cyan — top-level heading
28
+ H2 = lambda t: _c("1;33", t) # bold yellow — section heading
29
+ KW = lambda t: _c("1;32", t) # bold green — keyword / token
30
+ EX = lambda t: _c("90", t) # dark grey — example line
31
+ NOTE= lambda t: _c("35", t) # magenta — note / tip
32
+
33
+
34
+ # ══════════════════════════════════════════════════════════════════════════════
35
+ # Section printers
36
+ # ══════════════════════════════════════════════════════════════════════════════
37
+
38
+ def _header() -> None:
39
+ print(H1("""
40
+ ╔══════════════════════════════════════════════════════════════════════════╗
41
+ ║ MFP — MultiFunctionPlotter • Manual / Reference ║
42
+ ║ Developed by Swarnadeep Seth • v1.0 ║
43
+ ╚══════════════════════════════════════════════════════════════════════════╝
44
+ """))
45
+
46
+
47
+ def _synopsis() -> None:
48
+ print(H2("SYNOPSIS"))
49
+ print(f"""
50
+ {KW('python mfp.py')} <command> [, <command> ...] [--flags]
51
+
52
+ Commands are separated by commas. Each command describes one dataset
53
+ or function to overlay on the same axes (or one subplot panel).
54
+
55
+ Special subcommands:
56
+ {KW('plot.json')} Replay the last session from the saved JSON config.
57
+ {KW('forecast')} Run the Prophet time-series forecast helper.
58
+ {KW('DM')} Launch the interactive Data Manipulator.
59
+ {KW('--help')} Print this manual.
60
+ {KW('--list-styles')} List every recognised plot style keyword.
61
+ """)
62
+
63
+
64
+ def _basic_tokens() -> None:
65
+ print(H2("BASIC COMMAND TOKENS"))
66
+ rows = [
67
+ ("FILE", "<name>.csv / .txt / .dat",
68
+ "Data file to read."),
69
+ ("using / u", "X:Y",
70
+ "Column indices (1-based for text files, 0-based for CSV)."),
71
+ ("with / w", "<style>",
72
+ "Plot style — see STYLES section."),
73
+ ("title", '"My Title"',
74
+ "Plot / panel title."),
75
+ ("xlabel", '"X label"',
76
+ "Horizontal axis label."),
77
+ ("ylabel", '"Y label"',
78
+ "Vertical axis label."),
79
+ ("legend / lg", "<label>",
80
+ "Legend entry for this series (no spaces)."),
81
+ ("linewidth / lw", "<int>",
82
+ "Line width in points (default 2)."),
83
+ ("linecolor / lc", "<color>",
84
+ "Any matplotlib color string, e.g. tab:red, #3a7ab3."),
85
+ ("xrange", "min:max",
86
+ "Force x-axis limits."),
87
+ ("yrange", "min:max",
88
+ "Force y-axis limits."),
89
+ ("bin", "<int>",
90
+ "Histogram bin count (default 'auto')."),
91
+ ("func:", '"f(x,a=1) = a*np.sin(x)"',
92
+ "Plot a math expression. Requires xrange."),
93
+ ]
94
+ col_w = [16, 20, 42]
95
+ sep = " "
96
+ header = sep.join([
97
+ KW("Token".ljust(col_w[0])),
98
+ KW("Value".ljust(col_w[1])),
99
+ KW("Description"),
100
+ ])
101
+ print(" " + header)
102
+ print(" " + "─" * (sum(col_w) + len(sep) * 2))
103
+ for tok, val, desc in rows:
104
+ print(" " + sep.join([
105
+ tok.ljust(col_w[0]),
106
+ val.ljust(col_w[1]),
107
+ desc,
108
+ ]))
109
+ print()
110
+
111
+
112
+ def _styles() -> None:
113
+ print(H2("STYLES (with / w)"))
114
+ styles = [
115
+ # ── Line/scatter ──────────────────────────────────────────────────────
116
+ ("lines / l", "Solid line (matplotlib)"),
117
+ ("dashed", "Dashed line (matplotlib)"),
118
+ ("dotted", "Dotted line (matplotlib)"),
119
+ ("points / p", "Circle markers only (matplotlib)"),
120
+ ("linespoints / lp", "Line + circle markers (matplotlib)"),
121
+ ("stars", "Star markers (matplotlib)"),
122
+ ("d", "Diamond markers (matplotlib)"),
123
+ # ── Error bars ────────────────────────────────────────────────────────
124
+ ("errorbars / eb", "Discrete error bars — needs yerr <col>"),
125
+ ("errorshade / es", "Shaded ±σ band — needs yerr <col>"),
126
+ # ── Colormap scatter ──────────────────────────────────────────────────
127
+ ("scatter", "Scatter coloured by 3rd column — needs cmap <col> [colormap <name>]"),
128
+ # ── 2-D / matrix ─────────────────────────────────────────────────────
129
+ ("heatmap", "2-D heatmap (imshow) — needs 2D file"),
130
+ ("contour", "Contour lines — needs 2D file"),
131
+ ("contourf", "Filled contours — needs 2D file"),
132
+ # ── Seaborn distribution ──────────────────────────────────────────────
133
+ ("hist", "Histogram (seaborn histplot)"),
134
+ ("kde", "KDE density curve (seaborn kdeplot)"),
135
+ ("box", "Box-and-whisker plot (seaborn boxplot)"),
136
+ ("violin", "Violin plot (seaborn violinplot)"),
137
+ ]
138
+ for name, desc in styles:
139
+ print(f" {KW(name.ljust(22))} {desc}")
140
+ print()
141
+
142
+
143
+ def _errorbars() -> None:
144
+ print(H2("ERROR BARS"))
145
+ print(f"""
146
+ Two styles are available:
147
+
148
+ {KW('errorbars / eb')}
149
+ Plots discrete error bars using matplotlib errorbar().
150
+ The error column is a separate column in your data file.
151
+
152
+ Extra tokens:
153
+ {KW('yerr <col>')} 1-based column index holding the ±σ values.
154
+ {KW('capsize <int>')} Cap width in points (default 4).
155
+
156
+ Example:
157
+ {EX('python mfp.py data.csv using 1:2 with errorbars yerr 3 lc tab:red legend "my data"')}
158
+
159
+ {KW('errorshade / es')}
160
+ Fills a translucent band of ±σ around the mean line.
161
+ Same tokens as errorbars; capsize is ignored.
162
+
163
+ Example:
164
+ {EX('python mfp.py data.csv using 1:2 with errorshade yerr 3 lc steelblue legend "mean±σ"')}
165
+
166
+ {NOTE('Tip: combine errorshade with a lines series in the same command')}
167
+ {NOTE('to show the solid mean line on top of the shaded band:')}
168
+ {EX('python mfp.py "data.csv using 1:2 with errorshade yerr 3 lc steelblue, data.csv using 1:2 with lines lc steelblue"')}
169
+ """)
170
+
171
+
172
+ def _logscale() -> None:
173
+ print(H2("LOG SCALE"))
174
+ print(f"""
175
+ Append one or both flags to any plot command string:
176
+
177
+ {KW('--xlog')} Set the x-axis to logarithmic scale.
178
+ {KW('--ylog')} Set the y-axis to logarithmic scale.
179
+
180
+ These are global flags — they apply to the entire figure / all panels.
181
+
182
+ Example:
183
+ {EX('python mfp.py spectrum.csv using 1:2 with lines --ylog')}
184
+ {EX('python mfp.py spectrum.csv using 1:2 with lines --xlog --ylog')}
185
+
186
+ {NOTE('Tip: log scale is applied after all series are drawn,')}
187
+ {NOTE('so it works with subplots, errorbar, and function plots too.')}
188
+ """)
189
+
190
+
191
+ def _colormap() -> None:
192
+ print(H2("COLORMAP SCATTER"))
193
+ print(f"""
194
+ Style: {KW('scatter')}
195
+
196
+ Plots x vs y with each point coloured by the value in a third column.
197
+ A colorbar is added automatically.
198
+
199
+ Extra tokens:
200
+ {KW('cmap <col>')} 1-based column index for the colour values.
201
+ {KW('colormap <name>')} Matplotlib colormap name (default: viridis).
202
+ {KW('cbar_label "<text>"')} Label for the colorbar (optional).
203
+
204
+ Example:
205
+ {EX('python mfp.py results.csv using 1:2 with scatter cmap 3 colormap plasma cbar_label "Temperature (K)"')}
206
+
207
+ Useful colormaps:
208
+ viridis, plasma, inferno, magma, cividis (perceptually uniform)
209
+ coolwarm, RdBu, seismic (diverging)
210
+ Blues, Reds, YlOrRd (sequential)
211
+
212
+ {NOTE('Run python -c "import matplotlib; print(matplotlib.colormaps)"')}
213
+ {NOTE('for the full list.')}
214
+ """)
215
+
216
+
217
+ def _2d() -> None:
218
+ print(H2("2-D PLOT STYLES (heatmap / contour / contourf)"))
219
+ print(f"""
220
+ These styles read the entire file as a 2-D numeric matrix (no header).
221
+ Rows → y-axis, columns → x-axis.
222
+
223
+ Styles:
224
+ {KW('heatmap')} imshow with a colorbar — best for raster data.
225
+ {KW('contour')} Contour lines only.
226
+ {KW('contourf')} Filled contours.
227
+
228
+ Extra tokens:
229
+ {KW('colormap <name>')} Colormap for the fill / image (default: viridis).
230
+ {KW('levels <int>')} Number of contour levels (default 10, contour/f only).
231
+ {KW('cbar_label "<text>"')} Colorbar label.
232
+
233
+ The {KW('using')} / {KW('xrange')} / {KW('yrange')} tokens are ignored for 2-D plots
234
+ because the entire matrix is rendered.
235
+
236
+ Example:
237
+ {EX('python mfp.py matrix.dat with heatmap colormap inferno cbar_label "Intensity"')}
238
+ {EX('python mfp.py matrix.dat with contourf levels 20 colormap RdBu')}
239
+ """)
240
+
241
+
242
+ def _subplots() -> None:
243
+ print(H2("SUBPLOTS"))
244
+ print(f"""
245
+ Use the {KW('--subplot')} flag followed by a layout string.
246
+ The layout uses letters — each letter is a panel key.
247
+
248
+ Row separator: use {KW('-')} between rows (MFP converts it to a newline).
249
+
250
+ One command per panel, separated by commas (left-to-right, top-to-bottom).
251
+
252
+ Example — 2×2 grid:
253
+ {EX('python mfp.py --subplot AB-CD "data1.csv using 1:2 with lines, data2.csv using 1:2 with hist, data3.csv using 1:2 with kde, data4.csv using 1:2 with scatter cmap 3"')}
254
+
255
+ Example — asymmetric (A spans the top row, B and C share the bottom):
256
+ {EX('python mfp.py --subplot AA-BC ...')}
257
+ """)
258
+
259
+
260
+ def _save_section() -> None:
261
+ print(H2("SAVING FIGURES"))
262
+ print(f"""
263
+ Append {KW('--save <path>')} to write the figure to disk.
264
+ The format is inferred from the file extension.
265
+
266
+ Supported formats:
267
+ .png Raster — good for screen / web.
268
+ .pdf Vector — best for LaTeX / publications.
269
+ .svg Vector — good for Inkscape / web.
270
+ .eps Vector — legacy journals.
271
+
272
+ Example:
273
+ {EX('python mfp.py data.csv using 1:2 with lines --save figure.pdf')}
274
+
275
+ {NOTE('Tip: append --dpi 300 (future flag) for high-resolution raster output.')}
276
+ """)
277
+
278
+
279
+ def _axis_formatting() -> None:
280
+ print(H2("ADVANCED AXIS FORMATTING"))
281
+ print(f"""
282
+ Control axis appearance with precision for publication-quality plots.
283
+
284
+ Tokens:
285
+ {KW('sci_notation <axis>')} Enable scientific notation.
286
+ <axis> = x, y, or both (default: off).
287
+ {KW('xticks "x0,x1,x2,..."')} Set custom x-axis tick positions.
288
+ Use comma-separated numbers.
289
+ {KW('yticks "y0,y1,y2,..."')} Set custom y-axis tick positions.
290
+ {KW('xtick_rotation <angle>')} Rotate x-axis labels by angle in degrees.
291
+ Use negative angles for opposite rotation.
292
+ {KW('ytick_rotation <angle>')} Rotate y-axis labels by angle in degrees.
293
+ {KW('date_format "<fmt>"')} Parse and format x-axis as dates.
294
+ Format codes: %Y (year), %m (month), %d (day),
295
+ %H (hour), %M (min), %S (sec).
296
+ Example: "%Y-%m-%d" for 2024-01-15.
297
+
298
+ Examples:
299
+ {EX('python mfp.py data.csv using 1:2 with lines sci_notation both')}
300
+ {EX('python mfp.py spectrum.csv using 1:2 with lines sci_notation y')}
301
+ {EX('python mfp.py angles.csv using 1:2 with points xticks "0,90,180,270" xtick_rotation 45')}
302
+ {EX('python mfp.py timeseries.csv using 1:2 with lines date_format "%Y-%m-%d"')}
303
+ {EX('python mfp.py matrix.csv using 1:2 with scatter cmap 3 ytick_rotation 90')}
304
+
305
+ {NOTE('Tip: date_format auto-rotates x labels 45° for readability.')}
306
+ {NOTE('Combine xticks with xtick_rotation for precise control.')}
307
+ """)
308
+
309
+
310
+ def _examples() -> None:
311
+ print(H2("QUICK EXAMPLES"))
312
+ print(f"""
313
+ Basic line plot:
314
+ {EX('python mfp.py data.csv using 1:2 with lines lc tab:blue legend "Series A"')}
315
+
316
+ Two overlaid series:
317
+ {EX('python mfp.py "data.csv using 1:2 with lines, data.csv using 1:3 with dashed lc tab:red"')}
318
+
319
+ Function plot:
320
+ {EX('python mfp.py func: "f(x,a=1) = a*np.sin(x)" xrange 0:10 lc tab:green')}
321
+
322
+ Error bars (discrete):
323
+ {EX('python mfp.py data.csv using 1:2 with errorbars yerr 3')}
324
+
325
+ Shaded error band:
326
+ {EX('python mfp.py data.csv using 1:2 with errorshade yerr 3 lc steelblue')}
327
+
328
+ Colormap scatter:
329
+ {EX('python mfp.py results.csv using 1:2 with scatter cmap 3 colormap plasma')}
330
+
331
+ Heatmap from matrix file:
332
+ {EX('python mfp.py matrix.dat with heatmap colormap viridis cbar_label "Value"')}
333
+
334
+ Filled contour:
335
+ {EX('python mfp.py matrix.dat with contourf levels 15 colormap RdBu')}
336
+
337
+ Log-scale spectrum:
338
+ {EX('python mfp.py spectrum.csv using 1:2 with lines --xlog --ylog')}
339
+
340
+ Histogram:
341
+ {EX('python mfp.py samples.csv using 0:1 with hist bin 30 lc tab:orange')}
342
+
343
+ 2-panel subplot:
344
+ {EX('python mfp.py --subplot AB "data.csv using 1:2 with lines, data.csv using 1:2 with hist"')}
345
+
346
+ Save as PDF:
347
+ {EX('python mfp.py data.csv using 1:2 with lines --save output.pdf')}
348
+
349
+ Replay last session:
350
+ {EX('python mfp.py plot.json')}
351
+ """)
352
+
353
+
354
+ # ══════════════════════════════════════════════════════════════════════════════
355
+ # Public API
356
+ # ══════════════════════════════════════════════════════════════════════════════
357
+
358
+ _SECTIONS: dict[str, callable] = {
359
+ "synopsis": _synopsis,
360
+ "tokens": _basic_tokens,
361
+ "styles": _styles,
362
+ "errorbars": _errorbars,
363
+ "logscale": _logscale,
364
+ "colormap": _colormap,
365
+ "2d": _2d,
366
+ "subplots": _subplots,
367
+ "save": _save_section,
368
+ "formatting": _axis_formatting,
369
+ "examples": _examples,
370
+ }
371
+
372
+
373
+ def show(section: str = "all") -> None:
374
+ """Print the MFP manual.
375
+
376
+ Args:
377
+ section: One of the keys in ``_SECTIONS``, or ``"all"`` for the full
378
+ manual.
379
+ """
380
+ _header()
381
+ if section == "all":
382
+ for fn in _SECTIONS.values():
383
+ fn()
384
+ elif section in _SECTIONS:
385
+ _SECTIONS[section]()
386
+ else:
387
+ print(f"Unknown section '{section}'. Available: {', '.join(_SECTIONS)}")
388
+
389
+
390
+ # ══════════════════════════════════════════════════════════════════════════════
391
+ # CLI entry point
392
+ # ══════════════════════════════════════════════════════════════════════════════
393
+
394
+ if __name__ == "__main__":
395
+ section = sys.argv[1] if len(sys.argv) > 1 else "all"
396
+ show(section)