multifunctionplotter 1.0.3__tar.gz → 1.0.4__tar.gz

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 (18) hide show
  1. {multifunctionplotter-1.0.3/src/multifunctionplotter.egg-info → multifunctionplotter-1.0.4}/PKG-INFO +31 -8
  2. {multifunctionplotter-1.0.3 → multifunctionplotter-1.0.4}/README.md +30 -7
  3. {multifunctionplotter-1.0.3 → multifunctionplotter-1.0.4}/pyproject.toml +1 -1
  4. {multifunctionplotter-1.0.3 → multifunctionplotter-1.0.4}/src/multifunctionplotter/mfp_server.py +28 -10
  5. {multifunctionplotter-1.0.3 → multifunctionplotter-1.0.4/src/multifunctionplotter.egg-info}/PKG-INFO +31 -8
  6. {multifunctionplotter-1.0.3 → multifunctionplotter-1.0.4}/src/multifunctionplotter.egg-info/SOURCES.txt +0 -1
  7. multifunctionplotter-1.0.3/src/multifunctionplotter/mfp_data_manipulator.py +0 -192
  8. {multifunctionplotter-1.0.3 → multifunctionplotter-1.0.4}/LICENSE +0 -0
  9. {multifunctionplotter-1.0.3 → multifunctionplotter-1.0.4}/setup.cfg +0 -0
  10. {multifunctionplotter-1.0.3 → multifunctionplotter-1.0.4}/src/multifunctionplotter/mfp.py +0 -0
  11. {multifunctionplotter-1.0.3 → multifunctionplotter-1.0.4}/src/multifunctionplotter/mfp_dmanp.py +0 -0
  12. {multifunctionplotter-1.0.3 → multifunctionplotter-1.0.4}/src/multifunctionplotter/mfp_dmanp_help.py +0 -0
  13. {multifunctionplotter-1.0.3 → multifunctionplotter-1.0.4}/src/multifunctionplotter/mfp_help.py +0 -0
  14. {multifunctionplotter-1.0.3 → multifunctionplotter-1.0.4}/src/multifunctionplotter/prophet_pred.py +0 -0
  15. {multifunctionplotter-1.0.3 → multifunctionplotter-1.0.4}/src/multifunctionplotter.egg-info/dependency_links.txt +0 -0
  16. {multifunctionplotter-1.0.3 → multifunctionplotter-1.0.4}/src/multifunctionplotter.egg-info/entry_points.txt +0 -0
  17. {multifunctionplotter-1.0.3 → multifunctionplotter-1.0.4}/src/multifunctionplotter.egg-info/requires.txt +0 -0
  18. {multifunctionplotter-1.0.3 → multifunctionplotter-1.0.4}/src/multifunctionplotter.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: multifunctionplotter
3
- Version: 1.0.3
3
+ Version: 1.0.4
4
4
  Summary: Publication-quality plots from CSV/TXT/DAT files — CLI, Python API, and MCP agent tool
5
5
  Author: Swarnadeep Seth
6
6
  License: Apache License
@@ -244,6 +244,8 @@ A versatile Python-based tool for creating publication-quality plots from CSV, T
244
244
  - [Installation](#installation)
245
245
  - [Option 1: Install Dependencies](#option-1-install-dependencies)
246
246
  - [Option 2: Install as Command-Line Tool (Recommended)](#option-2-install-as-command-line-tool-recommended)
247
+ - [MCP Server Installation](#mcp-server-installation)
248
+ - [Usage with AI Assistants](#usage-with-ai-assistants)
247
249
  - [Quick Start](#quick-start)
248
250
  - [Command Line](#command-line)
249
251
  - [Python API](#python-api)
@@ -328,16 +330,12 @@ pip install -r requirements.txt
328
330
 
329
331
  ### Option 2: Install as Command-Line Tool (Recommended)
330
332
 
331
- Run the install script to make `mfp` available as a global command:
333
+ Install directly from PyPI:
332
334
 
333
335
  ```
334
- bash install.sh
336
+ pip3 install multifunctionplotter
335
337
  ```
336
338
 
337
- This will:
338
- 1. Make `src/mfp.py` executable
339
- 2. Create a symbolic link at `/usr/local/bin/mfp`
340
-
341
339
  After installation, you can run `mfp` from anywhere:
342
340
 
343
341
  ```
@@ -346,7 +344,32 @@ mfp --help
346
344
  mfp forecast
347
345
  ```
348
346
 
349
- **Note:** Requires sudo privileges to create the symbolic link in `/usr/local/bin`.
347
+ ### MCP Server Installation
348
+
349
+ For AI assistant integration (Claude Code, opencode, etc.):
350
+
351
+ ```
352
+ pip3 install multifunctionplotter
353
+ mfp-mcp
354
+ ```
355
+
356
+ ### Usage with AI Assistants
357
+
358
+ **Claude Code:**
359
+ ```
360
+ claude mcp add mfp -- mfp-mcp
361
+ ```
362
+
363
+ **opencode:** Add to `~/.config/opencode/opencode.json`:
364
+ ```json
365
+ {
366
+ "mfp": {
367
+ "type": "local",
368
+ "command": ["mfp-mcp"],
369
+ "enabled": true
370
+ }
371
+ }
372
+ ```
350
373
 
351
374
  ---
352
375
 
@@ -15,6 +15,8 @@ A versatile Python-based tool for creating publication-quality plots from CSV, T
15
15
  - [Installation](#installation)
16
16
  - [Option 1: Install Dependencies](#option-1-install-dependencies)
17
17
  - [Option 2: Install as Command-Line Tool (Recommended)](#option-2-install-as-command-line-tool-recommended)
18
+ - [MCP Server Installation](#mcp-server-installation)
19
+ - [Usage with AI Assistants](#usage-with-ai-assistants)
18
20
  - [Quick Start](#quick-start)
19
21
  - [Command Line](#command-line)
20
22
  - [Python API](#python-api)
@@ -99,16 +101,12 @@ pip install -r requirements.txt
99
101
 
100
102
  ### Option 2: Install as Command-Line Tool (Recommended)
101
103
 
102
- Run the install script to make `mfp` available as a global command:
104
+ Install directly from PyPI:
103
105
 
104
106
  ```
105
- bash install.sh
107
+ pip3 install multifunctionplotter
106
108
  ```
107
109
 
108
- This will:
109
- 1. Make `src/mfp.py` executable
110
- 2. Create a symbolic link at `/usr/local/bin/mfp`
111
-
112
110
  After installation, you can run `mfp` from anywhere:
113
111
 
114
112
  ```
@@ -117,7 +115,32 @@ mfp --help
117
115
  mfp forecast
118
116
  ```
119
117
 
120
- **Note:** Requires sudo privileges to create the symbolic link in `/usr/local/bin`.
118
+ ### MCP Server Installation
119
+
120
+ For AI assistant integration (Claude Code, opencode, etc.):
121
+
122
+ ```
123
+ pip3 install multifunctionplotter
124
+ mfp-mcp
125
+ ```
126
+
127
+ ### Usage with AI Assistants
128
+
129
+ **Claude Code:**
130
+ ```
131
+ claude mcp add mfp -- mfp-mcp
132
+ ```
133
+
134
+ **opencode:** Add to `~/.config/opencode/opencode.json`:
135
+ ```json
136
+ {
137
+ "mfp": {
138
+ "type": "local",
139
+ "command": ["mfp-mcp"],
140
+ "enabled": true
141
+ }
142
+ }
143
+ ```
121
144
 
122
145
  ---
123
146
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "multifunctionplotter"
7
- version = "1.0.3"
7
+ version = "1.0.4"
8
8
  description = "Publication-quality plots from CSV/TXT/DAT files — CLI, Python API, and MCP agent tool"
9
9
  readme = "README.md"
10
10
  license = { file = "LICENSE" }
@@ -86,6 +86,15 @@ def plot(
86
86
  """
87
87
  Plot a single data series from a CSV, TXT, or DAT file.
88
88
 
89
+ This tool translates structured parameters into the mfp CLI command:
90
+ mfp <file> u <x_col>:<y_col> [with <style>] [options] --save <save>
91
+
92
+ For example, "plot data.dat col1 vs col2 and save as plot.png" becomes:
93
+ plot("data.dat", x_col=1, y_col=2, save="plot.png")
94
+ → runs: mfp data.dat u 1:2 --save plot.png
95
+
96
+ Do NOT call this tool as "mfp_plot" — the correct tool name is "plot".
97
+
89
98
  Column indexing:
90
99
  - CSV files: 0-based (first col = 0)
91
100
  - TXT / DAT files: 1-based (first col = 1)
@@ -133,11 +142,15 @@ def plot(
133
142
  Success message with the output path, or error details.
134
143
 
135
144
  Examples:
136
- plot("data.csv", 0, 4, style="lines", title="Close Price", save="price.png")
137
- plot("results.dat", 1, 2, style="errorbars", yerr_col=3, linecolor="tab:red")
138
- plot("samples.csv", 0, 1, style="hist", bin=30, save="dist.pdf")
139
- plot("matrix.dat", 0, 0, style="heatmap", colormap="inferno", save="heat.png")
140
- plot("data.csv", 1, 2, style="scatter", cmap_col=3, colormap="plasma")
145
+ # "plot data.dat col1 vs col2, save as plot.png"
146
+ plot("data.dat", x_col=1, y_col=2, save="plot.png")
147
+ # → mfp data.dat u 1:2 --save plot.png
148
+
149
+ plot("data.csv", x_col=0, y_col=4, style="lines", title="Close Price", save="price.png")
150
+ plot("results.dat", x_col=1, y_col=2, style="errorbars", yerr_col=3, linecolor="tab:red")
151
+ plot("samples.csv", x_col=0, y_col=1, style="hist", bin=30, save="dist.pdf")
152
+ plot("matrix.dat", x_col=0, y_col=0, style="heatmap", colormap="inferno", save="heat.png")
153
+ plot("data.csv", x_col=1, y_col=2, style="scatter", cmap_col=3, colormap="plasma")
141
154
  """
142
155
  # Build the gnuplot-style command string that mfp parses
143
156
  cmd_parts = [file, "using", f"{x_col}:{y_col}", "with", style]
@@ -166,7 +179,9 @@ def plot(
166
179
  if xlog: args += ["--xlog"]
167
180
  if ylog: args += ["--ylog"]
168
181
 
169
- _run(args)
182
+ result = _run(args)
183
+ if result.startswith("Error"):
184
+ return result
170
185
  return f"Plot saved to: {save}"
171
186
 
172
187
 
@@ -236,7 +251,9 @@ def plot_function(
236
251
  args = cmd_parts + ["--save", save]
237
252
  if ylog: args += ["--ylog"]
238
253
 
239
- _run(args)
254
+ result = _run(args)
255
+ if result.startswith("Error"):
256
+ return result
240
257
  return f"Plot saved to: {save}"
241
258
 
242
259
 
@@ -326,7 +343,9 @@ def multi_plot(
326
343
  if xlog: args += ["--xlog"]
327
344
  if ylog: args += ["--ylog"]
328
345
 
329
- _run(args)
346
+ result = _run(args)
347
+ if result.startswith("Error"):
348
+ return result
330
349
  return f"Plot saved to: {save}"
331
350
 
332
351
 
@@ -599,5 +618,4 @@ def main():
599
618
  mcp.run()
600
619
 
601
620
  if __name__ == "__main__":
602
- main()
603
-
621
+ main()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: multifunctionplotter
3
- Version: 1.0.3
3
+ Version: 1.0.4
4
4
  Summary: Publication-quality plots from CSV/TXT/DAT files — CLI, Python API, and MCP agent tool
5
5
  Author: Swarnadeep Seth
6
6
  License: Apache License
@@ -244,6 +244,8 @@ A versatile Python-based tool for creating publication-quality plots from CSV, T
244
244
  - [Installation](#installation)
245
245
  - [Option 1: Install Dependencies](#option-1-install-dependencies)
246
246
  - [Option 2: Install as Command-Line Tool (Recommended)](#option-2-install-as-command-line-tool-recommended)
247
+ - [MCP Server Installation](#mcp-server-installation)
248
+ - [Usage with AI Assistants](#usage-with-ai-assistants)
247
249
  - [Quick Start](#quick-start)
248
250
  - [Command Line](#command-line)
249
251
  - [Python API](#python-api)
@@ -328,16 +330,12 @@ pip install -r requirements.txt
328
330
 
329
331
  ### Option 2: Install as Command-Line Tool (Recommended)
330
332
 
331
- Run the install script to make `mfp` available as a global command:
333
+ Install directly from PyPI:
332
334
 
333
335
  ```
334
- bash install.sh
336
+ pip3 install multifunctionplotter
335
337
  ```
336
338
 
337
- This will:
338
- 1. Make `src/mfp.py` executable
339
- 2. Create a symbolic link at `/usr/local/bin/mfp`
340
-
341
339
  After installation, you can run `mfp` from anywhere:
342
340
 
343
341
  ```
@@ -346,7 +344,32 @@ mfp --help
346
344
  mfp forecast
347
345
  ```
348
346
 
349
- **Note:** Requires sudo privileges to create the symbolic link in `/usr/local/bin`.
347
+ ### MCP Server Installation
348
+
349
+ For AI assistant integration (Claude Code, opencode, etc.):
350
+
351
+ ```
352
+ pip3 install multifunctionplotter
353
+ mfp-mcp
354
+ ```
355
+
356
+ ### Usage with AI Assistants
357
+
358
+ **Claude Code:**
359
+ ```
360
+ claude mcp add mfp -- mfp-mcp
361
+ ```
362
+
363
+ **opencode:** Add to `~/.config/opencode/opencode.json`:
364
+ ```json
365
+ {
366
+ "mfp": {
367
+ "type": "local",
368
+ "command": ["mfp-mcp"],
369
+ "enabled": true
370
+ }
371
+ }
372
+ ```
350
373
 
351
374
  ---
352
375
 
@@ -2,7 +2,6 @@ LICENSE
2
2
  README.md
3
3
  pyproject.toml
4
4
  src/multifunctionplotter/mfp.py
5
- src/multifunctionplotter/mfp_data_manipulator.py
6
5
  src/multifunctionplotter/mfp_dmanp.py
7
6
  src/multifunctionplotter/mfp_dmanp_help.py
8
7
  src/multifunctionplotter/mfp_help.py
@@ -1,192 +0,0 @@
1
- import pandas as pd
2
- import numpy as np
3
- import os, sys, re, warnings
4
-
5
- warnings.filterwarnings("ignore")
6
-
7
- print("Data Manipulator")
8
- print("=" * 70)
9
- print("Program to slice, sort, merge, generate, append, delete, and show properties/props, data in a CSV file.")
10
- print("=" * 70)
11
-
12
- class MFPDataManipulator:
13
- def __init__(self, datafile=None):
14
- if datafile:
15
- self.datafile = os.path.abspath(datafile) # Get absolute path
16
- self.df = pd.read_csv(self.datafile).replace(np.nan, '', regex=True)
17
- print ("Datafile loaded successfully.")
18
- print(self.df)
19
- else:
20
- self.datafile = None
21
- self.df = pd.DataFrame() # Initialize an empty DataFrame
22
-
23
- def merge(self, other_file, on_column, how="inner"):
24
- """
25
- Merge the current DataFrame with another CSV file.
26
- Args:
27
- other_file (str): The file to merge with.
28
- on_column (str): The column name to compare and merge on.
29
- how (str): Merge strategy - 'inner', 'outer', 'left', or 'right'. Defaults to 'inner'.
30
- Returns:
31
- pd.DataFrame: The merged DataFrame.
32
- """
33
- try:
34
- df_to_merge = pd.read_csv(other_file).replace(np.nan, '', regex=True)
35
- self.df = pd.merge(self.df, df_to_merge, on=on_column, how=how)
36
- return self.df
37
- except FileNotFoundError:
38
- print(f"File '{other_file}' not found.")
39
- return self.df
40
- except KeyError:
41
- print(f"Column '{on_column}' not found in one of the files.")
42
- return self.df
43
-
44
- def slice(self, start, end):
45
- start = int(start)
46
- end = int(end)
47
- self.df = self.df.iloc[start:end] # Update self.df
48
- return self.df
49
-
50
- def sort(self, col, order):
51
- if order in ["ascending", "asc"]:
52
- self.df = self.df.sort_values(by=[col], ascending=True) # Update self.df
53
- elif order in ["descending", "desc"]:
54
- self.df = self.df.sort_values(by=[col], ascending=False) # Update self.df
55
- else:
56
- raise ValueError("Invalid order. Use 'asc' or 'desc'.")
57
- return self.df
58
-
59
- def generate(self, xr, expr):
60
- xr = xr.split(":")
61
- x = np.linspace(int(xr[0]), int(xr[1]), int(xr[1]) - int(xr[0]) + 1)
62
- y = eval(expr)
63
- new_df = pd.DataFrame({"x": x, "y": y})
64
- self.df = new_df # Replace any previous data frame with the new one
65
- return self.df
66
-
67
- def append(self, datafile):
68
- df2 = pd.read_csv(datafile)
69
- df2 = df2.replace(np.nan, '', regex=True)
70
- self.df = pd.concat([self.df, df2]) # Update self.df
71
- return self.df
72
-
73
- def properties(self):
74
- # Display the columns in a nice table with index
75
- column_table = pd.DataFrame({
76
- 'Index': range(len(self.df.columns)),
77
- 'Column Name': self.df.columns
78
- })
79
- print("Column Index Table:")
80
- print(column_table)
81
-
82
- # Show NaN counts for each column
83
- nan_counts = self.df.isnull().sum()
84
- print("\nNaN Counts:")
85
- print(nan_counts)
86
-
87
- # Return the summary statistics
88
- return self.df.describe()
89
-
90
- def delete(self, targets):
91
- # Check if the input targets are columns (strings) or rows (integers)
92
- if all(target.strip().isnumeric() for target in targets.split(',')):
93
- # If all targets are numeric, treat them as row indices
94
- row_indices = [int(target.strip()) for target in targets.split(',')]
95
- self.df = self.df.drop(index=row_indices) # Drop specified rows
96
- else:
97
- # Otherwise, treat them as column names
98
- col_names = [target.strip() for target in targets.split(',')]
99
- self.df = self.df.drop(columns=col_names) # Drop specified columns
100
- return self.df
101
-
102
- def modify(self, col, old_val, new_val):
103
- self.df[col] = self.df[col].replace(old_val, new_val) # Update self.df
104
- return self.df
105
-
106
- def save(self, datafile):
107
- directory = os.path.dirname(self.datafile)
108
- save_path = os.path.join(directory, datafile)
109
- self.df.to_csv(save_path, index=False) # Save the updated DataFrame
110
- print(f"Data saved to {save_path}")
111
-
112
- if __name__ == "__main__":
113
- while True:
114
- datafile = input("Enter the CSV file name (or press Enter to skip): ")
115
- if datafile.strip():
116
- try:
117
- data_manipulator = MFPDataManipulator(datafile)
118
- print("Datafile loaded successfully.")
119
- except FileNotFoundError:
120
- print(f"File '{datafile}' not found. Please try again.")
121
- continue
122
- else:
123
- data_manipulator = MFPDataManipulator() # Create an instance with no file
124
- print("No datafile loaded. You can generate data from scratch.")
125
-
126
- while True:
127
- action = input("Enter an action (properties/props, slice, sort, merge, generate/gen, append, delete/del, modify, save, or exit/q): ").lower()
128
-
129
- if action == "generate" or action == "gen":
130
- xr = input("Enter the range for x (e.g., 0:10): ")
131
- expr = input("Enter the expression for y (e.g., 5*x**2/np.exp(x)): ")
132
- print(data_manipulator.generate(xr, expr))
133
-
134
- elif action == "merge":
135
- if data_manipulator.df.empty:
136
- print("No data available to merge.")
137
- continue
138
- other_file = input("Enter the file name to merge with: ")
139
- on_column = input("Enter the column name to merge on: ")
140
- how = input("Enter the merge type (inner, outer, left, right): ").lower()
141
- print(data_manipulator.merge(other_file, on_column, how))
142
-
143
- elif action == "slice":
144
- if data_manipulator.df.empty:
145
- print("No data available to slice.")
146
- continue
147
- start = input("Enter the start index: ")
148
- end = input("Enter the end index: ")
149
- print(data_manipulator.slice(start, end))
150
-
151
- elif action == "sort":
152
- if data_manipulator.df.empty:
153
- print("No data available to sort.")
154
- continue
155
- order = input("Enter the order (asc/desc): ")
156
- col = input("Enter the column name to sort by: ")
157
- print(data_manipulator.sort(col, order))
158
-
159
- elif action == "properties" or action == "props":
160
- print(data_manipulator.properties())
161
-
162
- elif action == "append":
163
- file_to_append = input("Enter the file name to append: ")
164
- print(data_manipulator.append(file_to_append))
165
-
166
- elif action == "delete" or action == "del":
167
- if data_manipulator.df.empty:
168
- print("No data available to delete.")
169
- continue
170
- targets = input("Enter the column names or row indices to delete (comma-separated): ")
171
- print(data_manipulator.delete(targets))
172
-
173
- elif action == "modify":
174
- if data_manipulator.df.empty:
175
- print("No data available to modify.")
176
- continue
177
- col = input("Enter the column name to modify: ")
178
- old_val = input("Enter the old value to replace: ")
179
- new_val = input("Enter the new value: ")
180
- print(data_manipulator.modify(col, old_val, new_val))
181
-
182
- elif action == "save":
183
- save_file = input("Enter the file name to save the data: ")
184
- data_manipulator.save(save_file)
185
- print(f"Data saved to {save_file}")
186
-
187
- elif action == "exit" or action == "q":
188
- print("Exiting the program.")
189
- exit(0)
190
-
191
- else:
192
- print("Invalid action. Please try again.")