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.
- multifunctionplotter/mfp.py +989 -0
- multifunctionplotter/mfp_data_manipulator.py +192 -0
- multifunctionplotter/mfp_dmanp.py +931 -0
- multifunctionplotter/mfp_dmanp_help.py +741 -0
- multifunctionplotter/mfp_help.py +396 -0
- multifunctionplotter/mfp_server.py +603 -0
- multifunctionplotter/prophet_pred.py +214 -0
- multifunctionplotter-1.0.3.dist-info/METADATA +881 -0
- multifunctionplotter-1.0.3.dist-info/RECORD +13 -0
- multifunctionplotter-1.0.3.dist-info/WHEEL +5 -0
- multifunctionplotter-1.0.3.dist-info/entry_points.txt +3 -0
- multifunctionplotter-1.0.3.dist-info/licenses/LICENSE +201 -0
- multifunctionplotter-1.0.3.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,192 @@
|
|
|
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.")
|