MatplotLibAPI 3.3.0__py3-none-any.whl → 4.0.1__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.
- MatplotLibAPI/__init__.py +4 -86
- MatplotLibAPI/accessor.py +288 -191
- MatplotLibAPI/area.py +235 -0
- MatplotLibAPI/bar.py +193 -0
- MatplotLibAPI/base_plot.py +88 -0
- MatplotLibAPI/box_violin.py +186 -0
- MatplotLibAPI/bubble.py +569 -0
- MatplotLibAPI/{Composite.py → composite.py} +70 -83
- MatplotLibAPI/heatmap.py +246 -0
- MatplotLibAPI/histogram.py +172 -0
- MatplotLibAPI/mcp/__init__.py +17 -0
- MatplotLibAPI/mcp/metadata.py +90 -0
- MatplotLibAPI/mcp/renderers.py +45 -0
- MatplotLibAPI/mcp_server.py +626 -0
- MatplotLibAPI/network/__init__.py +28 -0
- MatplotLibAPI/network/constants.py +22 -0
- MatplotLibAPI/{Network.py → network/core.py} +347 -809
- MatplotLibAPI/network/plot.py +597 -0
- MatplotLibAPI/network/scaling.py +56 -0
- MatplotLibAPI/pie.py +155 -0
- MatplotLibAPI/pivot.py +282 -0
- MatplotLibAPI/sankey.py +99 -0
- MatplotLibAPI/{StyleTemplate.py → style_template.py} +8 -4
- MatplotLibAPI/sunburst.py +139 -0
- MatplotLibAPI/{Table.py → table.py} +109 -93
- MatplotLibAPI/{Timeserie.py → timeserie.py} +99 -42
- MatplotLibAPI/{Treemap.py → treemap.py} +43 -55
- MatplotLibAPI/typing.py +12 -0
- MatplotLibAPI/{_visualization_utils.py → utils.py} +30 -13
- MatplotLibAPI/waffle.py +174 -0
- MatplotLibAPI/{Wordcloud.py → word_cloud.py} +188 -88
- {matplotlibapi-3.3.0.dist-info → matplotlibapi-4.0.1.dist-info}/METADATA +98 -9
- matplotlibapi-4.0.1.dist-info/RECORD +36 -0
- {matplotlibapi-3.3.0.dist-info → matplotlibapi-4.0.1.dist-info}/WHEEL +1 -1
- matplotlibapi-4.0.1.dist-info/entry_points.txt +2 -0
- MatplotLibAPI/Area.py +0 -80
- MatplotLibAPI/Bar.py +0 -83
- MatplotLibAPI/BoxViolin.py +0 -75
- MatplotLibAPI/Bubble.py +0 -460
- MatplotLibAPI/Heatmap.py +0 -121
- MatplotLibAPI/Histogram.py +0 -73
- MatplotLibAPI/Pie.py +0 -70
- MatplotLibAPI/Pivot.py +0 -134
- MatplotLibAPI/Sankey.py +0 -46
- MatplotLibAPI/Sunburst.py +0 -89
- MatplotLibAPI/Waffle.py +0 -86
- MatplotLibAPI/_typing.py +0 -17
- matplotlibapi-3.3.0.dist-info/RECORD +0 -26
- {matplotlibapi-3.3.0.dist-info → matplotlibapi-4.0.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,626 @@
|
|
|
1
|
+
"""MCP server helpers for exposing MatplotLibAPI plotting tools."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from io import BytesIO
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Any, Dict, List, Optional
|
|
8
|
+
|
|
9
|
+
import matplotlib.pyplot as plt
|
|
10
|
+
import pandas as pd
|
|
11
|
+
from matplotlib.figure import Figure
|
|
12
|
+
|
|
13
|
+
from .style_template import BUBBLE_STYLE_TEMPLATE, StyleTemplate
|
|
14
|
+
|
|
15
|
+
from .bubble import Bubble
|
|
16
|
+
from .network import fplot_network
|
|
17
|
+
from .mcp.metadata import (
|
|
18
|
+
DEDICATED_PLOT_TOOLS,
|
|
19
|
+
PLOT_MODULE_PARAMETER_HINTS,
|
|
20
|
+
SHARED_INPUT_CONTRACT,
|
|
21
|
+
)
|
|
22
|
+
from .mcp.renderers import (
|
|
23
|
+
MATPLOTLIB_RENDERERS,
|
|
24
|
+
PLOTLY_RENDERERS,
|
|
25
|
+
SUPPORTED_PLOT_MODULES,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
TableRecords = List[Dict[str, Any]]
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _load_dataframe(
|
|
32
|
+
csv_path: Optional[str] = None,
|
|
33
|
+
table: Optional[TableRecords] = None,
|
|
34
|
+
) -> pd.DataFrame:
|
|
35
|
+
"""Load plotting data from either a CSV file or table records."""
|
|
36
|
+
if csv_path is None and table is None:
|
|
37
|
+
raise ValueError("Provide either `csv_path` or `table`.")
|
|
38
|
+
|
|
39
|
+
if table is not None:
|
|
40
|
+
return pd.DataFrame(table)
|
|
41
|
+
|
|
42
|
+
data_path = Path(str(csv_path)).expanduser().resolve()
|
|
43
|
+
return pd.read_csv(data_path)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _figure_to_png_bytes(fig: Figure) -> bytes:
|
|
47
|
+
"""Serialize a Matplotlib figure to PNG bytes and close it."""
|
|
48
|
+
buffer = BytesIO()
|
|
49
|
+
fig.savefig(buffer, format="png", dpi=300, bbox_inches="tight")
|
|
50
|
+
plt.close(fig)
|
|
51
|
+
return buffer.getvalue()
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _build_bubble_chart_figure(
|
|
55
|
+
label: str,
|
|
56
|
+
x: str,
|
|
57
|
+
y: str,
|
|
58
|
+
z: str,
|
|
59
|
+
csv_path: Optional[str] = None,
|
|
60
|
+
table: Optional[TableRecords] = None,
|
|
61
|
+
title: Optional[str] = None,
|
|
62
|
+
max_values: int = 50,
|
|
63
|
+
center_to_mean: bool = False,
|
|
64
|
+
sort_by: Optional[str] = None,
|
|
65
|
+
ascending: bool = False,
|
|
66
|
+
style: StyleTemplate = BUBBLE_STYLE_TEMPLATE,
|
|
67
|
+
hline: bool = False,
|
|
68
|
+
vline: bool = False,
|
|
69
|
+
) -> Figure:
|
|
70
|
+
"""Create a bubble chart figure from tabular input."""
|
|
71
|
+
pd_df = _load_dataframe(csv_path=csv_path, table=table)
|
|
72
|
+
fig = Bubble(
|
|
73
|
+
pd_df=pd_df,
|
|
74
|
+
label=label,
|
|
75
|
+
x=x,
|
|
76
|
+
y=y,
|
|
77
|
+
z=z,
|
|
78
|
+
max_values=max_values,
|
|
79
|
+
center_to_mean=center_to_mean,
|
|
80
|
+
sort_by=sort_by,
|
|
81
|
+
ascending=ascending,
|
|
82
|
+
).fplot(
|
|
83
|
+
title=title,
|
|
84
|
+
hline=hline,
|
|
85
|
+
vline=vline,
|
|
86
|
+
style=style,
|
|
87
|
+
)
|
|
88
|
+
return fig
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def _build_network_chart_figure(
|
|
92
|
+
csv_path: Optional[str] = None,
|
|
93
|
+
table: Optional[TableRecords] = None,
|
|
94
|
+
edge_source_col: str = "source",
|
|
95
|
+
edge_target_col: str = "target",
|
|
96
|
+
edge_weight_col: str = "weight",
|
|
97
|
+
title: Optional[str] = None,
|
|
98
|
+
) -> Figure:
|
|
99
|
+
"""Create a network chart figure from tabular input."""
|
|
100
|
+
pd_df = _load_dataframe(csv_path=csv_path, table=table)
|
|
101
|
+
return fplot_network(
|
|
102
|
+
pd_df=pd_df,
|
|
103
|
+
edge_source_col=edge_source_col,
|
|
104
|
+
edge_target_col=edge_target_col,
|
|
105
|
+
edge_weight_col=edge_weight_col,
|
|
106
|
+
title=title,
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def render_bubble_chart(
|
|
111
|
+
output_path: str,
|
|
112
|
+
label: str,
|
|
113
|
+
x: str,
|
|
114
|
+
y: str,
|
|
115
|
+
z: str,
|
|
116
|
+
csv_path: Optional[str] = None,
|
|
117
|
+
table: Optional[TableRecords] = None,
|
|
118
|
+
title: Optional[str] = None,
|
|
119
|
+
max_values: int = 50,
|
|
120
|
+
center_to_mean: bool = False,
|
|
121
|
+
sort_by: Optional[str] = None,
|
|
122
|
+
ascending: bool = False,
|
|
123
|
+
hline: bool = False,
|
|
124
|
+
vline: bool = False,
|
|
125
|
+
) -> str:
|
|
126
|
+
"""Render a bubble chart from table data and write it to disk.
|
|
127
|
+
|
|
128
|
+
Parameters
|
|
129
|
+
----------
|
|
130
|
+
output_path : str
|
|
131
|
+
Path where the generated chart image is saved.
|
|
132
|
+
label : str
|
|
133
|
+
Column name used for bubble labels.
|
|
134
|
+
x : str
|
|
135
|
+
Column name for the x-axis values.
|
|
136
|
+
y : str
|
|
137
|
+
Column name for the y-axis values.
|
|
138
|
+
z : str
|
|
139
|
+
Column name used for bubble size.
|
|
140
|
+
csv_path : str, optional
|
|
141
|
+
Path to a CSV file containing plotting data. The default is None.
|
|
142
|
+
table : list[dict[str, Any]], optional
|
|
143
|
+
In-memory row records with column names as keys. The default is None.
|
|
144
|
+
title : str, optional
|
|
145
|
+
Chart title. The default is None.
|
|
146
|
+
max_values : int, optional
|
|
147
|
+
Maximum number of rows to include in the plot. The default is 50.
|
|
148
|
+
center_to_mean : bool, optional
|
|
149
|
+
Whether to center x-axis values around their mean. The default is False.
|
|
150
|
+
sort_by : str, optional
|
|
151
|
+
Column used to sort before selecting rows. The default is None.
|
|
152
|
+
ascending : bool, optional
|
|
153
|
+
Sort order used with ``sort_by``. The default is False.
|
|
154
|
+
hline : bool, optional
|
|
155
|
+
Whether to draw a horizontal mean line for y values. The default is False.
|
|
156
|
+
vline : bool, optional
|
|
157
|
+
Whether to draw a vertical mean line for x values. The default is False.
|
|
158
|
+
|
|
159
|
+
Returns
|
|
160
|
+
-------
|
|
161
|
+
str
|
|
162
|
+
The resolved output path for the generated image.
|
|
163
|
+
"""
|
|
164
|
+
out_path = Path(output_path).expanduser().resolve()
|
|
165
|
+
if out_path.suffix.lower() != ".png":
|
|
166
|
+
out_path = out_path.with_suffix(".png")
|
|
167
|
+
out_path.parent.mkdir(parents=True, exist_ok=True)
|
|
168
|
+
|
|
169
|
+
out_path.write_bytes(
|
|
170
|
+
render_bubble_chart_octet(
|
|
171
|
+
label=label,
|
|
172
|
+
x=x,
|
|
173
|
+
y=y,
|
|
174
|
+
z=z,
|
|
175
|
+
csv_path=csv_path,
|
|
176
|
+
table=table,
|
|
177
|
+
title=title,
|
|
178
|
+
max_values=max_values,
|
|
179
|
+
center_to_mean=center_to_mean,
|
|
180
|
+
sort_by=sort_by,
|
|
181
|
+
ascending=ascending,
|
|
182
|
+
hline=hline,
|
|
183
|
+
vline=vline,
|
|
184
|
+
)
|
|
185
|
+
)
|
|
186
|
+
return str(out_path)
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def render_bubble_chart_octet(
|
|
190
|
+
label: str,
|
|
191
|
+
x: str,
|
|
192
|
+
y: str,
|
|
193
|
+
z: str,
|
|
194
|
+
csv_path: Optional[str] = None,
|
|
195
|
+
table: Optional[TableRecords] = None,
|
|
196
|
+
title: Optional[str] = None,
|
|
197
|
+
max_values: int = 50,
|
|
198
|
+
center_to_mean: bool = False,
|
|
199
|
+
sort_by: Optional[str] = None,
|
|
200
|
+
ascending: bool = False,
|
|
201
|
+
hline: bool = False,
|
|
202
|
+
vline: bool = False,
|
|
203
|
+
) -> bytes:
|
|
204
|
+
"""Render a bubble chart and return PNG bytes as an octet payload.
|
|
205
|
+
|
|
206
|
+
Parameters
|
|
207
|
+
----------
|
|
208
|
+
label : str
|
|
209
|
+
Column name used for bubble labels.
|
|
210
|
+
x : str
|
|
211
|
+
Column name for the x-axis values.
|
|
212
|
+
y : str
|
|
213
|
+
Column name for the y-axis values.
|
|
214
|
+
z : str
|
|
215
|
+
Column name used for bubble size.
|
|
216
|
+
csv_path : str, optional
|
|
217
|
+
Path to a CSV file containing plotting data. The default is None.
|
|
218
|
+
table : list[dict[str, Any]], optional
|
|
219
|
+
In-memory row records with column names as keys. The default is None.
|
|
220
|
+
title : str, optional
|
|
221
|
+
Chart title. The default is None.
|
|
222
|
+
max_values : int, optional
|
|
223
|
+
Maximum number of rows to include in the plot. The default is 50.
|
|
224
|
+
center_to_mean : bool, optional
|
|
225
|
+
Whether to center x-axis values around their mean. The default is False.
|
|
226
|
+
sort_by : str, optional
|
|
227
|
+
Column used to sort before selecting rows. The default is None.
|
|
228
|
+
ascending : bool, optional
|
|
229
|
+
Sort order used with ``sort_by``. The default is False.
|
|
230
|
+
hline : bool, optional
|
|
231
|
+
Whether to draw a horizontal mean line for y values. The default is False.
|
|
232
|
+
vline : bool, optional
|
|
233
|
+
Whether to draw a vertical mean line for x values. The default is False.
|
|
234
|
+
|
|
235
|
+
Returns
|
|
236
|
+
-------
|
|
237
|
+
bytes
|
|
238
|
+
PNG payload bytes suitable for ``application/octet-stream`` responses.
|
|
239
|
+
"""
|
|
240
|
+
fig = _build_bubble_chart_figure(
|
|
241
|
+
label=label,
|
|
242
|
+
x=x,
|
|
243
|
+
y=y,
|
|
244
|
+
z=z,
|
|
245
|
+
csv_path=csv_path,
|
|
246
|
+
table=table,
|
|
247
|
+
title=title,
|
|
248
|
+
max_values=max_values,
|
|
249
|
+
center_to_mean=center_to_mean,
|
|
250
|
+
sort_by=sort_by,
|
|
251
|
+
ascending=ascending,
|
|
252
|
+
hline=hline,
|
|
253
|
+
vline=vline,
|
|
254
|
+
)
|
|
255
|
+
return _figure_to_png_bytes(fig)
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
def render_network_chart_octet(
|
|
259
|
+
csv_path: Optional[str] = None,
|
|
260
|
+
table: Optional[TableRecords] = None,
|
|
261
|
+
edge_source_col: str = "source",
|
|
262
|
+
edge_target_col: str = "target",
|
|
263
|
+
edge_weight_col: str = "weight",
|
|
264
|
+
title: Optional[str] = None,
|
|
265
|
+
) -> bytes:
|
|
266
|
+
"""Render a network chart and return PNG bytes as an octet payload.
|
|
267
|
+
|
|
268
|
+
Parameters
|
|
269
|
+
----------
|
|
270
|
+
csv_path : str, optional
|
|
271
|
+
Path to a CSV file containing edge data. The default is None.
|
|
272
|
+
table : list[dict[str, Any]], optional
|
|
273
|
+
In-memory row records with edge columns as keys. The default is None.
|
|
274
|
+
edge_source_col : str, optional
|
|
275
|
+
Column name for source nodes. The default is ``"source"``.
|
|
276
|
+
edge_target_col : str, optional
|
|
277
|
+
Column name for target nodes. The default is ``"target"``.
|
|
278
|
+
edge_weight_col : str, optional
|
|
279
|
+
Column name for edge weights. The default is ``"weight"``.
|
|
280
|
+
title : str, optional
|
|
281
|
+
Chart title. The default is None.
|
|
282
|
+
|
|
283
|
+
Returns
|
|
284
|
+
-------
|
|
285
|
+
bytes
|
|
286
|
+
PNG payload bytes suitable for ``application/octet-stream`` responses.
|
|
287
|
+
"""
|
|
288
|
+
fig = _build_network_chart_figure(
|
|
289
|
+
csv_path=csv_path,
|
|
290
|
+
table=table,
|
|
291
|
+
edge_source_col=edge_source_col,
|
|
292
|
+
edge_target_col=edge_target_col,
|
|
293
|
+
edge_weight_col=edge_weight_col,
|
|
294
|
+
title=title,
|
|
295
|
+
)
|
|
296
|
+
return _figure_to_png_bytes(fig)
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
def get_plot_module_metadata() -> Dict[str, Any]:
|
|
300
|
+
"""Return MCP metadata for module discoverability and exploration.
|
|
301
|
+
|
|
302
|
+
Returns
|
|
303
|
+
-------
|
|
304
|
+
dict[str, Any]
|
|
305
|
+
Discoverability metadata containing supported modules, shared input
|
|
306
|
+
contract, and parameter hints per module.
|
|
307
|
+
"""
|
|
308
|
+
return {
|
|
309
|
+
"supported_plot_modules": SUPPORTED_PLOT_MODULES,
|
|
310
|
+
"shared_input_contract": SHARED_INPUT_CONTRACT,
|
|
311
|
+
"parameter_hints": PLOT_MODULE_PARAMETER_HINTS,
|
|
312
|
+
"dedicated_tools": DEDICATED_PLOT_TOOLS,
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
def render_plot_module_octet(
|
|
317
|
+
plot_module: str,
|
|
318
|
+
params: Dict[str, Any],
|
|
319
|
+
csv_path: Optional[str] = None,
|
|
320
|
+
table: Optional[TableRecords] = None,
|
|
321
|
+
) -> bytes:
|
|
322
|
+
"""Render a supported plot module and return PNG bytes.
|
|
323
|
+
|
|
324
|
+
Parameters
|
|
325
|
+
----------
|
|
326
|
+
plot_module : str
|
|
327
|
+
Plot module key.
|
|
328
|
+
params : dict[str, Any]
|
|
329
|
+
Module-specific plotting parameters excluding the DataFrame argument.
|
|
330
|
+
csv_path : str, optional
|
|
331
|
+
Path to a CSV file containing source data. The default is None.
|
|
332
|
+
table : list[dict[str, Any]], optional
|
|
333
|
+
In-memory row records with source columns as keys. The default is None.
|
|
334
|
+
|
|
335
|
+
Returns
|
|
336
|
+
-------
|
|
337
|
+
bytes
|
|
338
|
+
PNG payload bytes suitable for ``application/octet-stream`` responses.
|
|
339
|
+
|
|
340
|
+
Raises
|
|
341
|
+
------
|
|
342
|
+
ValueError
|
|
343
|
+
If ``plot_module`` is not supported.
|
|
344
|
+
"""
|
|
345
|
+
if plot_module == "bubble":
|
|
346
|
+
return render_bubble_chart_octet(csv_path=csv_path, table=table, **params)
|
|
347
|
+
if plot_module == "network":
|
|
348
|
+
return render_network_chart_octet(csv_path=csv_path, table=table, **params)
|
|
349
|
+
|
|
350
|
+
pd_df = _load_dataframe(csv_path=csv_path, table=table)
|
|
351
|
+
|
|
352
|
+
if plot_module in MATPLOTLIB_RENDERERS:
|
|
353
|
+
fig = MATPLOTLIB_RENDERERS[plot_module](pd_df=pd_df, **params)
|
|
354
|
+
return _figure_to_png_bytes(fig)
|
|
355
|
+
|
|
356
|
+
if plot_module in PLOTLY_RENDERERS:
|
|
357
|
+
fig = PLOTLY_RENDERERS[plot_module](pd_df=pd_df, **params)
|
|
358
|
+
return bytes(fig.to_image(format="png"))
|
|
359
|
+
|
|
360
|
+
raise ValueError(
|
|
361
|
+
f"Unsupported plot_module '{plot_module}'. Supported: {SUPPORTED_PLOT_MODULES}"
|
|
362
|
+
)
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
def create_mcp_server() -> Any:
|
|
366
|
+
"""Create an MCP server exposing MatplotLibAPI plotting tools.
|
|
367
|
+
|
|
368
|
+
Returns
|
|
369
|
+
-------
|
|
370
|
+
FastMCP
|
|
371
|
+
A configured FastMCP server instance.
|
|
372
|
+
|
|
373
|
+
Raises
|
|
374
|
+
------
|
|
375
|
+
ImportError
|
|
376
|
+
If the optional ``mcp`` package is not installed.
|
|
377
|
+
"""
|
|
378
|
+
try:
|
|
379
|
+
from mcp.server.fastmcp import FastMCP # pyright: ignore[reportMissingImports]
|
|
380
|
+
except ImportError as exc: # pragma: no cover
|
|
381
|
+
raise ImportError(
|
|
382
|
+
"Install MatplotLibAPI with MCP support: `pip install MatplotLibAPI[mcp]`."
|
|
383
|
+
) from exc
|
|
384
|
+
|
|
385
|
+
mcp = FastMCP("MatplotLibAPI")
|
|
386
|
+
|
|
387
|
+
@mcp.tool()
|
|
388
|
+
def plot_bubble(
|
|
389
|
+
label: str,
|
|
390
|
+
x: str,
|
|
391
|
+
y: str,
|
|
392
|
+
z: str,
|
|
393
|
+
csv_path: Optional[str] = None,
|
|
394
|
+
table: Optional[TableRecords] = None,
|
|
395
|
+
title: Optional[str] = None,
|
|
396
|
+
max_values: int = 50,
|
|
397
|
+
center_to_mean: bool = False,
|
|
398
|
+
sort_by: Optional[str] = None,
|
|
399
|
+
ascending: bool = False,
|
|
400
|
+
hline: bool = False,
|
|
401
|
+
vline: bool = False,
|
|
402
|
+
) -> bytes:
|
|
403
|
+
"""Generate a bubble chart and return PNG octets."""
|
|
404
|
+
return render_bubble_chart_octet(
|
|
405
|
+
label=label,
|
|
406
|
+
x=x,
|
|
407
|
+
y=y,
|
|
408
|
+
z=z,
|
|
409
|
+
csv_path=csv_path,
|
|
410
|
+
table=table,
|
|
411
|
+
title=title,
|
|
412
|
+
max_values=max_values,
|
|
413
|
+
center_to_mean=center_to_mean,
|
|
414
|
+
sort_by=sort_by,
|
|
415
|
+
ascending=ascending,
|
|
416
|
+
hline=hline,
|
|
417
|
+
vline=vline,
|
|
418
|
+
)
|
|
419
|
+
|
|
420
|
+
@mcp.tool()
|
|
421
|
+
def plot_network(
|
|
422
|
+
csv_path: Optional[str] = None,
|
|
423
|
+
table: Optional[TableRecords] = None,
|
|
424
|
+
edge_source_col: str = "source",
|
|
425
|
+
edge_target_col: str = "target",
|
|
426
|
+
edge_weight_col: str = "weight",
|
|
427
|
+
title: Optional[str] = None,
|
|
428
|
+
) -> bytes:
|
|
429
|
+
"""Generate a network chart and return PNG octets."""
|
|
430
|
+
return render_network_chart_octet(
|
|
431
|
+
csv_path=csv_path,
|
|
432
|
+
table=table,
|
|
433
|
+
edge_source_col=edge_source_col,
|
|
434
|
+
edge_target_col=edge_target_col,
|
|
435
|
+
edge_weight_col=edge_weight_col,
|
|
436
|
+
title=title,
|
|
437
|
+
)
|
|
438
|
+
|
|
439
|
+
@mcp.tool()
|
|
440
|
+
def plot_module(
|
|
441
|
+
plot_module: str,
|
|
442
|
+
params: Dict[str, Any],
|
|
443
|
+
csv_path: Optional[str] = None,
|
|
444
|
+
table: Optional[TableRecords] = None,
|
|
445
|
+
) -> bytes:
|
|
446
|
+
"""Generate a chart for any supported plot module and return octets."""
|
|
447
|
+
return render_plot_module_octet(
|
|
448
|
+
plot_module=plot_module,
|
|
449
|
+
params=params,
|
|
450
|
+
csv_path=csv_path,
|
|
451
|
+
table=table,
|
|
452
|
+
)
|
|
453
|
+
|
|
454
|
+
def _render_module(
|
|
455
|
+
module_name: str,
|
|
456
|
+
params: Dict[str, Any],
|
|
457
|
+
csv_path: Optional[str] = None,
|
|
458
|
+
table: Optional[TableRecords] = None,
|
|
459
|
+
) -> bytes:
|
|
460
|
+
"""Render a module-specific chart as PNG octets."""
|
|
461
|
+
return render_plot_module_octet(
|
|
462
|
+
plot_module=module_name,
|
|
463
|
+
params=params,
|
|
464
|
+
csv_path=csv_path,
|
|
465
|
+
table=table,
|
|
466
|
+
)
|
|
467
|
+
|
|
468
|
+
@mcp.tool()
|
|
469
|
+
def plot_bar(
|
|
470
|
+
params: Dict[str, Any],
|
|
471
|
+
csv_path: Optional[str] = None,
|
|
472
|
+
table: Optional[TableRecords] = None,
|
|
473
|
+
) -> bytes:
|
|
474
|
+
"""Generate a bar chart and return PNG octets."""
|
|
475
|
+
return _render_module("bar", params=params, csv_path=csv_path, table=table)
|
|
476
|
+
|
|
477
|
+
@mcp.tool()
|
|
478
|
+
def plot_histogram(
|
|
479
|
+
params: Dict[str, Any],
|
|
480
|
+
csv_path: Optional[str] = None,
|
|
481
|
+
table: Optional[TableRecords] = None,
|
|
482
|
+
) -> bytes:
|
|
483
|
+
"""Generate a histogram chart and return PNG octets."""
|
|
484
|
+
return _render_module(
|
|
485
|
+
"histogram", params=params, csv_path=csv_path, table=table
|
|
486
|
+
)
|
|
487
|
+
|
|
488
|
+
@mcp.tool()
|
|
489
|
+
def plot_box_violin(
|
|
490
|
+
params: Dict[str, Any],
|
|
491
|
+
csv_path: Optional[str] = None,
|
|
492
|
+
table: Optional[TableRecords] = None,
|
|
493
|
+
) -> bytes:
|
|
494
|
+
"""Generate a box/violin chart and return PNG octets."""
|
|
495
|
+
return _render_module(
|
|
496
|
+
"box_violin", params=params, csv_path=csv_path, table=table
|
|
497
|
+
)
|
|
498
|
+
|
|
499
|
+
@mcp.tool()
|
|
500
|
+
def plot_heatmap(
|
|
501
|
+
params: Dict[str, Any],
|
|
502
|
+
csv_path: Optional[str] = None,
|
|
503
|
+
table: Optional[TableRecords] = None,
|
|
504
|
+
) -> bytes:
|
|
505
|
+
"""Generate a heatmap chart and return PNG octets."""
|
|
506
|
+
return _render_module("heatmap", params=params, csv_path=csv_path, table=table)
|
|
507
|
+
|
|
508
|
+
@mcp.tool()
|
|
509
|
+
def plot_correlation_matrix(
|
|
510
|
+
params: Dict[str, Any],
|
|
511
|
+
csv_path: Optional[str] = None,
|
|
512
|
+
table: Optional[TableRecords] = None,
|
|
513
|
+
) -> bytes:
|
|
514
|
+
"""Generate a correlation matrix chart and return PNG octets."""
|
|
515
|
+
return _render_module(
|
|
516
|
+
"correlation_matrix", params=params, csv_path=csv_path, table=table
|
|
517
|
+
)
|
|
518
|
+
|
|
519
|
+
@mcp.tool()
|
|
520
|
+
def plot_area(
|
|
521
|
+
params: Dict[str, Any],
|
|
522
|
+
csv_path: Optional[str] = None,
|
|
523
|
+
table: Optional[TableRecords] = None,
|
|
524
|
+
) -> bytes:
|
|
525
|
+
"""Generate an area chart and return PNG octets."""
|
|
526
|
+
return _render_module("area", params=params, csv_path=csv_path, table=table)
|
|
527
|
+
|
|
528
|
+
@mcp.tool()
|
|
529
|
+
def plot_pie(
|
|
530
|
+
params: Dict[str, Any],
|
|
531
|
+
csv_path: Optional[str] = None,
|
|
532
|
+
table: Optional[TableRecords] = None,
|
|
533
|
+
) -> bytes:
|
|
534
|
+
"""Generate a pie chart and return PNG octets."""
|
|
535
|
+
return _render_module("pie", params=params, csv_path=csv_path, table=table)
|
|
536
|
+
|
|
537
|
+
@mcp.tool()
|
|
538
|
+
def plot_waffle(
|
|
539
|
+
params: Dict[str, Any],
|
|
540
|
+
csv_path: Optional[str] = None,
|
|
541
|
+
table: Optional[TableRecords] = None,
|
|
542
|
+
) -> bytes:
|
|
543
|
+
"""Generate a waffle chart and return PNG octets."""
|
|
544
|
+
return _render_module("waffle", params=params, csv_path=csv_path, table=table)
|
|
545
|
+
|
|
546
|
+
@mcp.tool()
|
|
547
|
+
def plot_sankey(
|
|
548
|
+
params: Dict[str, Any],
|
|
549
|
+
csv_path: Optional[str] = None,
|
|
550
|
+
table: Optional[TableRecords] = None,
|
|
551
|
+
) -> bytes:
|
|
552
|
+
"""Generate a sankey chart and return PNG octets."""
|
|
553
|
+
return _render_module("sankey", params=params, csv_path=csv_path, table=table)
|
|
554
|
+
|
|
555
|
+
@mcp.tool()
|
|
556
|
+
def plot_table(
|
|
557
|
+
params: Dict[str, Any],
|
|
558
|
+
csv_path: Optional[str] = None,
|
|
559
|
+
table: Optional[TableRecords] = None,
|
|
560
|
+
) -> bytes:
|
|
561
|
+
"""Generate a table chart and return PNG octets."""
|
|
562
|
+
return _render_module("table", params=params, csv_path=csv_path, table=table)
|
|
563
|
+
|
|
564
|
+
@mcp.tool()
|
|
565
|
+
def plot_timeserie(
|
|
566
|
+
params: Dict[str, Any],
|
|
567
|
+
csv_path: Optional[str] = None,
|
|
568
|
+
table: Optional[TableRecords] = None,
|
|
569
|
+
) -> bytes:
|
|
570
|
+
"""Generate a timeserie chart and return PNG octets."""
|
|
571
|
+
return _render_module(
|
|
572
|
+
"timeserie", params=params, csv_path=csv_path, table=table
|
|
573
|
+
)
|
|
574
|
+
|
|
575
|
+
@mcp.tool()
|
|
576
|
+
def plot_wordcloud(
|
|
577
|
+
params: Dict[str, Any],
|
|
578
|
+
csv_path: Optional[str] = None,
|
|
579
|
+
table: Optional[TableRecords] = None,
|
|
580
|
+
) -> bytes:
|
|
581
|
+
"""Generate a wordcloud chart and return PNG octets."""
|
|
582
|
+
return _render_module(
|
|
583
|
+
"wordcloud", params=params, csv_path=csv_path, table=table
|
|
584
|
+
)
|
|
585
|
+
|
|
586
|
+
@mcp.tool()
|
|
587
|
+
def plot_treemap(
|
|
588
|
+
params: Dict[str, Any],
|
|
589
|
+
csv_path: Optional[str] = None,
|
|
590
|
+
table: Optional[TableRecords] = None,
|
|
591
|
+
) -> bytes:
|
|
592
|
+
"""Generate a treemap chart and return PNG octets."""
|
|
593
|
+
return _render_module("treemap", params=params, csv_path=csv_path, table=table)
|
|
594
|
+
|
|
595
|
+
@mcp.tool()
|
|
596
|
+
def plot_sunburst(
|
|
597
|
+
params: Dict[str, Any],
|
|
598
|
+
csv_path: Optional[str] = None,
|
|
599
|
+
table: Optional[TableRecords] = None,
|
|
600
|
+
) -> bytes:
|
|
601
|
+
"""Generate a sunburst chart and return PNG octets."""
|
|
602
|
+
return _render_module("sunburst", params=params, csv_path=csv_path, table=table)
|
|
603
|
+
|
|
604
|
+
@mcp.tool()
|
|
605
|
+
def describe_plot_modules() -> Dict[str, Any]:
|
|
606
|
+
"""Describe MCP plot-module capabilities for tool exploration.
|
|
607
|
+
|
|
608
|
+
Returns
|
|
609
|
+
-------
|
|
610
|
+
dict[str, Any]
|
|
611
|
+
Metadata including supported module names, shared input contract,
|
|
612
|
+
and parameter-hint dictionaries.
|
|
613
|
+
"""
|
|
614
|
+
return get_plot_module_metadata()
|
|
615
|
+
|
|
616
|
+
return mcp
|
|
617
|
+
|
|
618
|
+
|
|
619
|
+
def main() -> None:
|
|
620
|
+
"""Run the MCP server over stdio transport."""
|
|
621
|
+
server = create_mcp_server()
|
|
622
|
+
server.run(transport="stdio")
|
|
623
|
+
|
|
624
|
+
|
|
625
|
+
if __name__ == "__main__": # pragma: no cover
|
|
626
|
+
main()
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""Network plotting tools for graph-based visualizations.
|
|
2
|
+
|
|
3
|
+
This package preserves the public ``MatplotLibAPI.network`` API while
|
|
4
|
+
organizing implementation details in submodules.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from .constants import _DEFAULT, _WEIGHT_PERCENTILES
|
|
8
|
+
from .core import NETWORK_STYLE_TEMPLATE, NetworkGraph
|
|
9
|
+
from .plot import (
|
|
10
|
+
aplot_network,
|
|
11
|
+
aplot_network_node,
|
|
12
|
+
aplot_network_components,
|
|
13
|
+
fplot_network,
|
|
14
|
+
fplot_network_node,
|
|
15
|
+
fplot_network_components,
|
|
16
|
+
)
|
|
17
|
+
from .scaling import _scale_weights, _softmax
|
|
18
|
+
|
|
19
|
+
__all__ = [
|
|
20
|
+
"aplot_network",
|
|
21
|
+
"aplot_network_node",
|
|
22
|
+
"aplot_network_components",
|
|
23
|
+
"fplot_network",
|
|
24
|
+
"fplot_network_node",
|
|
25
|
+
"fplot_network_components",
|
|
26
|
+
"NETWORK_STYLE_TEMPLATE",
|
|
27
|
+
"NetworkGraph",
|
|
28
|
+
]
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""Constants used by network plotting helpers."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
|
|
7
|
+
_DEFAULT = {
|
|
8
|
+
"MAX_EDGES": 100,
|
|
9
|
+
"MAX_NODES": 30,
|
|
10
|
+
"MIN_NODE_SIZE": 100,
|
|
11
|
+
"MAX_NODE_SIZE": 2000,
|
|
12
|
+
"MAX_EDGE_WIDTH": 10,
|
|
13
|
+
"GRAPH_SCALE": 2,
|
|
14
|
+
"MAX_FONT_SIZE": 20,
|
|
15
|
+
"MIN_FONT_SIZE": 8,
|
|
16
|
+
"SPRING_LAYOUT_K": 1.0,
|
|
17
|
+
"SPRING_LAYOUT_SEED": 42,
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
_WEIGHT_PERCENTILES = np.arange(10, 100, 10)
|
|
21
|
+
|
|
22
|
+
__all__ = ["_DEFAULT", "_WEIGHT_PERCENTILES"]
|