Skip to content

Commit

Permalink
Merge pull request #1056 from MichaelDecent/standalone_pkg1
Browse files Browse the repository at this point in the history
Standalone_pkg1
  • Loading branch information
cobycloud authored Jan 9, 2025
2 parents ee743c1 + 2bc16ee commit a51d05f
Show file tree
Hide file tree
Showing 17 changed files with 445 additions and 9 deletions.
2 changes: 1 addition & 1 deletion pkgs/standards/swarmauri_standard/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ full = [
#"transformers",
#"torch",
#"keras", "tf-keras",
"matplotlib"
#"matplotlib"
]

[tool.poetry.group.dev.dependencies]
Expand Down
55 changes: 55 additions & 0 deletions pkgs/standards/swarmauri_tool_matplotlib/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
[tool.poetry]
name = "swarmauri_tool_matplotlib"
version = "0.6.0.dev1"
description = "This repository includes an example of a First Class Swarmauri Example."
authors = ["Jacob Stewart <[email protected]>"]
license = "Apache-2.0"
readme = "README.md"
repository = "http://github.com/swarmauri/swarmauri-sdk"
classifiers = [
"License :: OSI Approved :: Apache Software License",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12"
]

[tool.poetry.dependencies]
python = ">=3.10,<3.13"

# Swarmauri
swarmauri_core = { path = "../../core" }
swarmauri_base = { path = "../../base" }

[tool.poetry.group.dev.dependencies]
flake8 = "^7.0"
pytest = "^8.0"
pytest-asyncio = ">=0.24.0"
pytest-xdist = "^3.6.1"
pytest-json-report = "^1.5.0"
python-dotenv = "*"
requests = "^2.32.3"

[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"

[tool.pytest.ini_options]
norecursedirs = ["combined", "scripts"]

markers = [
"test: standard test",
"unit: Unit tests",
"integration: Integration tests",
"acceptance: Acceptance tests",
"experimental: Experimental tests"
]
log_cli = true
log_cli_level = "INFO"
log_cli_format = "%(asctime)s [%(levelname)s] %(message)s"
log_cli_date_format = "%Y-%m-%d %H:%M:%S"
asyncio_default_fixture_loop_scope = "function"

[tool.poetry.plugins."swarmauri.tools"]
MatplotlibTool = "swarmauri_tool_matplotlib:MatplotlibTool"
MatplotlibCsvTool = "swarmauri_tool_matplotlib:MatplotlibCsvTool"

Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import pandas as pd
import matplotlib.pyplot as plt
import base64
from typing import List, Literal, Dict
from pydantic import Field
from swarmauri_standard.tools.Parameter import Parameter
from swarmauri_base.tools.ToolBase import ToolBase
from swarmauri_core.ComponentBase import ComponentBase


@ComponentBase.register_type(ToolBase, "MatplotlibCsvTool")
class MatplotlibCsvTool(ToolBase):
type: Literal["MatplotlibCsvTool"] = "MatplotlibCsvTool"
name: str = Field(
"MatplotlibCsvTool",
description="Tool to generate plots from CSV data using Matplotlib.",
)
description: str = Field(
"This tool reads data from a CSV file and generates a plot using Matplotlib.",
description="Description of the MatplotlibCsvTool",
)

parameters: List[Parameter] = Field(
default_factory=lambda: [
Parameter(
name="csv_file",
type="string",
description="The path to the CSV file containing the data.",
required=True,
),
Parameter(
name="x_column",
type="string",
description="The name of the column to use for the x-axis.",
required=True,
),
Parameter(
name="y_column",
type="string",
description="The name of the column to use for the y-axis.",
required=True,
),
Parameter(
name="output_file",
type="string",
description="The filename where the plot will be saved.",
required=True,
),
]
)

def __call__(
self, csv_file: str, x_column: str, y_column: str, output_file: str
) -> Dict[str, str]:
# Read data from CSV
data = pd.read_csv(csv_file)

# Check if columns exist in the DataFrame
if x_column not in data.columns or y_column not in data.columns:
raise ValueError(
f"Columns {x_column} and/or {y_column} not found in the CSV file."
)

# Generate plot
plt.figure(figsize=(10, 6))
plt.plot(data[x_column], data[y_column], marker="o")
plt.xlabel(x_column)
plt.ylabel(y_column)
plt.title(f"{y_column} vs {x_column}")
plt.grid(True)
plt.savefig(output_file)
plt.close()
print(f"Plot generated and saved to {output_file}")
# Encode the plot image as base64
with open(output_file, "rb") as image_file:
encoded_image = base64.b64encode(image_file.read()).decode("utf-8")

return {"img_path": output_file, "img_base64": encoded_image, "data": []}
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import base64
import matplotlib.pyplot as plt
from typing import List, Literal
from pydantic import Field
from swarmauri_base.tools.ToolBase import ToolBase
from swarmauri_standard.tools.Parameter import Parameter
from swarmauri_core.ComponentBase import ComponentBase


@ComponentBase.register_type(ToolBase, "MatplotlibTool")
class MatplotlibTool(ToolBase):
version: str = "1.0.0"
name: str = "MatplotlibTool"
description: str = (
"Generates a plot using Matplotlib library based on provided configuration."
)
type: Literal["MatplotlibTool"] = "MatplotlibTool"

parameters: List[Parameter] = Field(
default_factory=lambda: [
Parameter(
name="plot_type",
type="string",
description="Type of plot to generate (e.g., 'line', 'bar', 'scatter').",
required=True,
enum=["line", "bar", "scatter"],
),
Parameter(
name="x_data",
type="list<float>",
description="X-axis data for the plot.",
required=True,
),
Parameter(
name="y_data",
type="list<float>",
description="Y-axis data for the plot.",
required=True,
),
Parameter(
name="title",
type="string",
description="Title of the plot.",
required=False,
default="",
),
Parameter(
name="x_label",
type="string",
description="Label for the X-axis.",
required=False,
default="",
),
Parameter(
name="y_label",
type="string",
description="Label for the Y-axis.",
required=False,
default="",
),
Parameter(
name="save_path",
type="string",
description="Path to save the generated plot image.",
required=False,
default="plot.png",
),
]
)

def __call__(
self,
plot_type: str,
x_data: List[float],
y_data: List[float],
title: str = "",
x_label: str = "",
y_label: str = "",
save_path: str = "plot.png",
):
"""
Generates a plot using Matplotlib based on provided configuration.
Parameters:
plot_type (str): The type of the plot ('line', 'bar', 'scatter').
x_data (List[float]): X-axis data for the plot.
y_data (List[float]): Y-axis data for the plot.
title (str): Title of the plot.
x_label (str): Label for the X-axis.
y_label (str): Label for the Y-axis.
save_path (str): Path to save the generated plot image.
Returns:
str: Path where the plot image is saved.
"""
plt.figure()

if plot_type == "line":
plt.plot(x_data, y_data)
elif plot_type == "bar":
plt.bar(x_data, y_data)
elif plot_type == "scatter":
plt.scatter(x_data, y_data)
else:
raise ValueError(f"Unsupported plot type: {plot_type}")

if title:
plt.title(title)
if x_label:
plt.xlabel(x_label)
if y_label:
plt.ylabel(y_label)

plt.savefig(save_path)
plt.close()

with open(save_path, "rb") as image_file:
encoded_image = base64.b64encode(image_file.read()).decode("utf-8")

return {"img_path": save_path, "img_base64": encoded_image, "data": []}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from .MatplotlibCsvTool import MatplotlibCsvTool
from .MatplotlibTool import MatplotlibTool
__version__ = "0.6.0.dev26"
__long_desc__ = """
# Swarmauri Matplotlib Based Components
Components Included:
- MatplotlibTool
- MatplotlibCsvTool
Visit us at: https://swarmauri.com
Follow us at: https://github.com/swarmauri
Star us at: https://github.com/swarmauri/swarmauri-sdk
"""

Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import os
from tempfile import NamedTemporaryFile

import pytest
from swarmauri_tool_matplotlib.MatplotlibCsvTool import MatplotlibCsvTool as Tool


@pytest.mark.unit
def test_ubc_resource():
tool = Tool()
assert tool.resource == "Tool"


@pytest.mark.unit
def test_ubc_type():
assert Tool().type == "MatplotlibCsvTool"


@pytest.mark.unit
def test_initialization():
tool = Tool()
assert type(tool.id) == str


@pytest.mark.unit
def test_serialization():
tool = Tool()
assert tool.id == Tool.model_validate_json(tool.model_dump_json()).id


@pytest.mark.parametrize(
"csv_content, x_column, y_column, expected_error",
[
(
"x,y\n1,2\n3,4\n5,6", # CSV content
"x", # x_column
"y", # y_column
None, # No error expected
),
(
"a,b\n1,2\n3,4\n5,6", # CSV content
"x", # x_column
"y", # y_column
ValueError, # Error expected due to missing columns
),
(
"x,z\n1,2\n3,4\n5,6", # CSV content
"x", # x_column
"y", # y_column
ValueError, # Error expected due to missing y_column
),
],
)
@pytest.mark.unit
def test_call(csv_content, x_column, y_column, expected_error):
with NamedTemporaryFile(delete=False, suffix=".csv") as csv_file:
csv_file.write(csv_content.encode())
csv_file_path = csv_file.name

with NamedTemporaryFile(delete=False, suffix=".png") as output_file:
output_file_path = output_file.name

tool = Tool()
expected_keys = {"img_path", "img_base64", "data"}

if expected_error:
with pytest.raises(expected_error):
tool(csv_file_path, x_column, y_column, output_file_path)
else:
result = tool(csv_file_path, x_column, y_column, output_file_path)
assert isinstance(
result, dict
), f"Expected dict, but got {type(result).__name__}"
assert expected_keys.issubset(
result.keys()
), f"Expected keys {expected_keys} but got {result.keys()}"
assert isinstance(
result.get("data"), list
), f"Expected list, but got {type(result).__name__}"
assert os.path.exists(output_file_path)

os.remove(csv_file_path)
if os.path.exists(output_file_path):
os.remove(output_file_path)
Loading

0 comments on commit a51d05f

Please sign in to comment.