plot-agent 0.1.2__tar.gz → 0.2.1__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plot-agent
3
- Version: 0.1.2
3
+ Version: 0.2.1
4
4
  Summary: An AI-powered data visualization assistant using Plotly
5
5
  Author-email: andrewm4894 <andrewm4894@gmail.com>
6
6
  Project-URL: Homepage, https://github.com/andrewm4894/plot-agent
@@ -14,6 +14,9 @@ Dynamic: license-file
14
14
 
15
15
  # Plot Agent
16
16
 
17
+ [![Tests](https://github.com/andrewm4894/plot-agent/actions/workflows/test.yml/badge.svg)](https://github.com/andrewm4894/plot-agent/actions/workflows/test.yml)
18
+ [![PyPI version](https://badge.fury.io/py/plot-agent.svg)](https://badge.fury.io/py/plot-agent)
19
+
17
20
  An AI-powered data visualization assistant that helps users create Plotly visualizations in Python.
18
21
 
19
22
  ## Installation
@@ -26,12 +29,15 @@ pip install plot-agent
26
29
 
27
30
  ## Usage
28
31
 
29
- Here's a simple example of how to use Plot Agent:
32
+ See more examples in [/examples/](https://nbviewer.org/github/andrewm4894/plot-agent/tree/main/examples/) (via nbviewer so that can see the charts easily).
33
+
34
+ Here's a simple minimal example of how to use Plot Agent:
30
35
 
31
36
  ```python
32
37
  import pandas as pd
33
- from plot_agent.plotly_agent import PlotlyAgent
38
+ from plot_agent.agent import PlotlyAgent
34
39
 
40
+ # ensure OPENAI_API_KEY is set and available for langchain
35
41
 
36
42
  # Create a sample dataframe
37
43
  df = pd.DataFrame({
@@ -47,10 +53,45 @@ agent.set_df(df)
47
53
 
48
54
  # Process a visualization request
49
55
  response = agent.process_message("Create a line plot of x vs y")
56
+
57
+ # Print generated code
58
+ print(agent.generated_code)
59
+
60
+ # Get fig
50
61
  fig = agent.get_figure()
51
62
  fig.show()
52
63
  ```
53
64
 
65
+ `agent.generated_code`:
66
+
67
+ ```python
68
+ import pandas as pd
69
+ import plotly.graph_objects as go
70
+
71
+ # Creating a line plot of x vs y
72
+ # Create a figure object
73
+ fig = go.Figure()
74
+
75
+ # Add a line trace to the figure
76
+ fig.add_trace(
77
+ go.Scatter(
78
+ x=df['x'], # The x values
79
+ y=df['y'], # The y values
80
+ mode='lines+markers', # Display both lines and markers
81
+ name='Line Plot', # Name of the trace
82
+ line=dict(color='blue', width=2) # Specify line color and width
83
+ )
84
+ )
85
+
86
+ # Adding titles and labels
87
+ fig.update_layout(
88
+ title='Line Plot of x vs y', # Plot title
89
+ xaxis_title='x', # x-axis label
90
+ yaxis_title='y', # y-axis label
91
+ template='plotly_white' # A clean layout
92
+ )
93
+ ```
94
+
54
95
  ## Features
55
96
 
56
97
  - AI-powered visualization generation
@@ -0,0 +1,96 @@
1
+ # Plot Agent
2
+
3
+ [![Tests](https://github.com/andrewm4894/plot-agent/actions/workflows/test.yml/badge.svg)](https://github.com/andrewm4894/plot-agent/actions/workflows/test.yml)
4
+ [![PyPI version](https://badge.fury.io/py/plot-agent.svg)](https://badge.fury.io/py/plot-agent)
5
+
6
+ An AI-powered data visualization assistant that helps users create Plotly visualizations in Python.
7
+
8
+ ## Installation
9
+
10
+ You can install the package using pip:
11
+
12
+ ```bash
13
+ pip install plot-agent
14
+ ```
15
+
16
+ ## Usage
17
+
18
+ See more examples in [/examples/](https://nbviewer.org/github/andrewm4894/plot-agent/tree/main/examples/) (via nbviewer so that can see the charts easily).
19
+
20
+ Here's a simple minimal example of how to use Plot Agent:
21
+
22
+ ```python
23
+ import pandas as pd
24
+ from plot_agent.agent import PlotlyAgent
25
+
26
+ # ensure OPENAI_API_KEY is set and available for langchain
27
+
28
+ # Create a sample dataframe
29
+ df = pd.DataFrame({
30
+ 'x': [1, 2, 3, 4, 5],
31
+ 'y': [10, 20, 30, 40, 50]
32
+ })
33
+
34
+ # Initialize the agent
35
+ agent = PlotlyAgent()
36
+
37
+ # Set the dataframe
38
+ agent.set_df(df)
39
+
40
+ # Process a visualization request
41
+ response = agent.process_message("Create a line plot of x vs y")
42
+
43
+ # Print generated code
44
+ print(agent.generated_code)
45
+
46
+ # Get fig
47
+ fig = agent.get_figure()
48
+ fig.show()
49
+ ```
50
+
51
+ `agent.generated_code`:
52
+
53
+ ```python
54
+ import pandas as pd
55
+ import plotly.graph_objects as go
56
+
57
+ # Creating a line plot of x vs y
58
+ # Create a figure object
59
+ fig = go.Figure()
60
+
61
+ # Add a line trace to the figure
62
+ fig.add_trace(
63
+ go.Scatter(
64
+ x=df['x'], # The x values
65
+ y=df['y'], # The y values
66
+ mode='lines+markers', # Display both lines and markers
67
+ name='Line Plot', # Name of the trace
68
+ line=dict(color='blue', width=2) # Specify line color and width
69
+ )
70
+ )
71
+
72
+ # Adding titles and labels
73
+ fig.update_layout(
74
+ title='Line Plot of x vs y', # Plot title
75
+ xaxis_title='x', # x-axis label
76
+ yaxis_title='y', # y-axis label
77
+ template='plotly_white' # A clean layout
78
+ )
79
+ ```
80
+
81
+ ## Features
82
+
83
+ - AI-powered visualization generation
84
+ - Support for various Plotly chart types
85
+ - Automatic data preprocessing
86
+ - Interactive visualization capabilities
87
+ - Integration with LangChain for advanced AI capabilities
88
+
89
+ ## Requirements
90
+
91
+ - Python 3.8 or higher
92
+ - Dependencies are automatically installed with the package
93
+
94
+ ## License
95
+
96
+ This project is licensed under the MIT License - see the LICENSE file for details.
@@ -7,168 +7,21 @@ from plotly.subplots import make_subplots
7
7
  from io import StringIO
8
8
  import traceback
9
9
  import sys
10
- import re
11
- from typing import Dict, List, Optional, Any
10
+ from typing import Dict, Optional, Any
12
11
 
13
12
  from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
14
13
  from langchain_core.messages import AIMessage, HumanMessage
15
14
  from langchain_core.tools import Tool, StructuredTool
16
- from pydantic import BaseModel, Field
17
15
  from langchain.agents import AgentExecutor, create_openai_tools_agent
18
16
  from langchain_openai import ChatOpenAI
19
17
 
20
-
21
- DEFAULT_SYSTEM_PROMPT = """
22
- You are an expert data visualization assistant that helps users create Plotly visualizations in Python.
23
- Your job is to generate Python and Plotly code based on the user's request that will create the desired visualization
24
- of their pandas DataFrame (df).
25
-
26
- You have access to a pandas df with the following information:
27
-
28
- df.info():
29
- ```plaintext
30
- {df_info}
31
- ```
32
-
33
- df.head():
34
- ```plaintext
35
- {df_head}
36
- ```
37
-
38
- {sql_context}
39
-
40
- NOTES:
41
- - You must use the execute_plotly_code(generated_code) tool run your code and use the does_fig_exist() tool to check that a fig object is available for display.
42
- - You must paste the full code, not just a reference to the code.
43
- - You must not use fig.show() in your code as it will ultimately be executed elsewhere in a headless environment.
44
- - If you need to do any data cleaning or wrangling, do it in the code before generating the plotly code as preprocessing steps assume the data is in the pandas 'df' object.
45
-
46
- TOOLS:
47
- - execute_plotly_code(generated_code) to execute the generated code.
48
- - does_fig_exist() to check that a fig object is available for display. This tool takes no arguments.
49
- - view_generated_code() to view the generated code if need to fix it. This tool takes no arguments.
50
-
51
- IMPORTANT CODE FORMATTING INSTRUCTIONS:
52
- 1. Include thorough, detailed comments in your code to explain what each section does.
53
- 2. Use descriptive variable names.
54
- 3. DO NOT include fig.show() in your code - the visualization will be rendered externally.
55
- 4. Ensure your code creates a variable named 'fig' that contains the Plotly figure object.
56
-
57
- When a user asks for a visualization:
58
- 1. YOU MUST ALWAYS use the execute_plotly_code(generated_code) tool to test and run your code.
59
- 2. If there are errors, view the generated code using view_generated_code() and fix the code.
60
- 3. Check that a figure object is available using does_fig_exist(). does_fig_exist() takes no arguments.
61
- 4. If the figure object is not available, repeat the process until it is available.
62
-
63
- IMPORTANT: The code you generate MUST be executed using the execute_plotly_code tool or no figure will be created!
64
- YOU MUST CALL execute_plotly_code WITH THE FULL CODE, NOT JUST A REFERENCE TO THE CODE.
65
-
66
- YOUR WORKFLOW MUST BE:
67
- 1. execute_plotly_code(generated_code) to make sure the code is ran and a figure object is created.
68
- 2. check that a figure object is available using does_fig_exist() to make sure the figure object was created.
69
- 3. if there are errors, view the generated code using view_generated_code() to see what went wrong.
70
- 4. fix the code and execute it again with execute_plotly_code(generated_code) to make sure the figure object is created.
71
- 5. repeat until the figure object is available.
72
-
73
- Always return the final working code (with all the comments) to the user along with an explanation of what the visualization shows.
74
- Make sure to follow best practices for data visualization, such as appropriate chart types, labels, and colors.
75
-
76
- Remember that users may want to iterate on their visualizations, so be responsive to requests for changes.
77
- """
78
-
79
-
80
- # Define input schemas for the tools
81
- class PlotDescriptionInput(BaseModel):
82
- plot_description: str = Field(
83
- ..., description="Description of the plot the user wants to create"
84
- )
85
-
86
-
87
- class GeneratedCodeInput(BaseModel):
88
- generated_code: str = Field(
89
- ..., description="Python code that creates a Plotly figure"
90
- )
91
-
92
-
93
- class DoesFigExistInput(BaseModel):
94
- """Model indicating that the does_fig_exist function takes no arguments."""
95
-
96
- pass
97
-
98
-
99
- class ViewGeneratedCodeInput(BaseModel):
100
- """Model indicating that the view_generated_code function takes no arguments."""
101
-
102
- pass
103
-
104
-
105
- class PlotlyAgentExecutionEnvironment:
106
- """Environment to safely execute plotly code and capture the fig object."""
107
-
108
- def __init__(self, df: pd.DataFrame):
109
- self.df = df
110
- self.locals_dict = {
111
- "df": df,
112
- "px": px,
113
- "go": go,
114
- "pd": pd,
115
- "np": np,
116
- "plt": plt,
117
- "make_subplots": make_subplots,
118
- }
119
- self.output = None
120
- self.error = None
121
- self.fig = None
122
-
123
- def execute_code(self, generated_code: str) -> Dict[str, Any]:
124
- """
125
- Execute the provided code and capture the fig object if created.
126
-
127
- Args:
128
- generated_code (str): The code to execute.
129
-
130
- Returns:
131
- Dict[str, Any]: A dictionary containing the fig object, output, error, and success status.
132
- """
133
- self.output = None
134
- self.error = None
135
-
136
- # Capture stdout
137
- old_stdout = sys.stdout
138
- sys.stdout = mystdout = StringIO()
139
-
140
- try:
141
- # Execute the code
142
- exec(generated_code, globals(), self.locals_dict)
143
-
144
- # Check if a fig object was created
145
- if "fig" in self.locals_dict:
146
- self.fig = self.locals_dict["fig"]
147
- self.output = "Code executed successfully. 'fig' object was created."
148
- else:
149
- print(f"no fig object created: {generated_code}")
150
- self.error = "Code executed without errors, but no 'fig' object was created. Make sure your code creates a variable named 'fig'."
151
-
152
- except Exception as e:
153
- self.error = f"Error executing code: {str(e)}\n{traceback.format_exc()}"
154
-
155
- finally:
156
- # Restore stdout
157
- sys.stdout = old_stdout
158
- captured_output = mystdout.getvalue()
159
-
160
- if captured_output.strip():
161
- if self.output:
162
- self.output += f"\nOutput:\n{captured_output}"
163
- else:
164
- self.output = f"Output:\n{captured_output}"
165
-
166
- return {
167
- "fig": self.fig,
168
- "output": self.output,
169
- "error": self.error,
170
- "success": self.error is None and self.fig is not None,
171
- }
18
+ from plot_agent.prompt import DEFAULT_SYSTEM_PROMPT
19
+ from plot_agent.models import (
20
+ GeneratedCodeInput,
21
+ DoesFigExistInput,
22
+ ViewGeneratedCodeInput,
23
+ )
24
+ from plot_agent.execution import PlotlyAgentExecutionEnvironment
172
25
 
173
26
 
174
27
  class PlotlyAgent:
@@ -176,13 +29,25 @@ class PlotlyAgent:
176
29
  A class that uses an LLM to generate Plotly code based on a user's plot description.
177
30
  """
178
31
 
179
- def __init__(self, model="gpt-4o-mini", system_prompt: Optional[str] = None):
32
+ def __init__(
33
+ self,
34
+ model="gpt-4o-mini",
35
+ system_prompt: Optional[str] = None,
36
+ verbose: bool = True,
37
+ max_iterations: int = 10,
38
+ early_stopping_method: str = "force",
39
+ handle_parsing_errors: bool = True,
40
+ ):
180
41
  """
181
42
  Initialize the PlotlyAgent.
182
43
 
183
44
  Args:
184
45
  model (str): The model to use for the LLM.
185
46
  system_prompt (Optional[str]): The system prompt to use for the LLM.
47
+ verbose (bool): Whether to print verbose output from the agent.
48
+ max_iterations (int): Maximum number of iterations for the agent to take.
49
+ early_stopping_method (str): Method to use for early stopping.
50
+ handle_parsing_errors (bool): Whether to handle parsing errors gracefully.
186
51
  """
187
52
  self.llm = ChatOpenAI(model=model)
188
53
  self.df = None
@@ -194,6 +59,10 @@ class PlotlyAgent:
194
59
  self.agent_executor = None
195
60
  self.generated_code = None
196
61
  self.system_prompt = system_prompt or DEFAULT_SYSTEM_PROMPT
62
+ self.verbose = verbose
63
+ self.max_iterations = max_iterations
64
+ self.early_stopping_method = early_stopping_method
65
+ self.handle_parsing_errors = handle_parsing_errors
197
66
 
198
67
  def set_df(self, df: pd.DataFrame, sql_query: Optional[str] = None):
199
68
  """
@@ -321,10 +190,10 @@ class PlotlyAgent:
321
190
  self.agent_executor = AgentExecutor(
322
191
  agent=agent,
323
192
  tools=tools,
324
- verbose=True,
325
- max_iterations=10,
326
- early_stopping_method="force",
327
- handle_parsing_errors=True,
193
+ verbose=self.verbose,
194
+ max_iterations=self.max_iterations,
195
+ early_stopping_method=self.early_stopping_method,
196
+ handle_parsing_errors=self.handle_parsing_errors,
328
197
  )
329
198
 
330
199
  def process_message(self, user_message: str) -> str:
@@ -0,0 +1,79 @@
1
+ import sys
2
+ from io import StringIO
3
+ import traceback
4
+ import pandas as pd
5
+ import plotly.express as px
6
+ import plotly.graph_objects as go
7
+ import numpy as np
8
+ import matplotlib.pyplot as plt
9
+ from plotly.subplots import make_subplots
10
+ from typing import Dict, Any
11
+
12
+
13
+ class PlotlyAgentExecutionEnvironment:
14
+ """Environment to safely execute plotly code and capture the fig object."""
15
+
16
+ def __init__(self, df: pd.DataFrame):
17
+ self.df = df
18
+ self.locals_dict = {
19
+ "df": df,
20
+ "px": px,
21
+ "go": go,
22
+ "pd": pd,
23
+ "np": np,
24
+ "plt": plt,
25
+ "make_subplots": make_subplots,
26
+ }
27
+ self.output = None
28
+ self.error = None
29
+ self.fig = None
30
+
31
+ def execute_code(self, generated_code: str) -> Dict[str, Any]:
32
+ """
33
+ Execute the provided code and capture the fig object if created.
34
+
35
+ Args:
36
+ generated_code (str): The code to execute.
37
+
38
+ Returns:
39
+ Dict[str, Any]: A dictionary containing the fig object, output, error, and success status.
40
+ """
41
+ self.output = None
42
+ self.error = None
43
+
44
+ # Capture stdout
45
+ old_stdout = sys.stdout
46
+ sys.stdout = mystdout = StringIO()
47
+
48
+ try:
49
+ # Execute the code
50
+ exec(generated_code, globals(), self.locals_dict)
51
+
52
+ # Check if a fig object was created
53
+ if "fig" in self.locals_dict:
54
+ self.fig = self.locals_dict["fig"]
55
+ self.output = "Code executed successfully. 'fig' object was created."
56
+ else:
57
+ print(f"no fig object created: {generated_code}")
58
+ self.error = "Code executed without errors, but no 'fig' object was created. Make sure your code creates a variable named 'fig'."
59
+
60
+ except Exception as e:
61
+ self.error = f"Error executing code: {str(e)}\n{traceback.format_exc()}"
62
+
63
+ finally:
64
+ # Restore stdout
65
+ sys.stdout = old_stdout
66
+ captured_output = mystdout.getvalue()
67
+
68
+ if captured_output.strip():
69
+ if self.output:
70
+ self.output += f"\nOutput:\n{captured_output}"
71
+ else:
72
+ self.output = f"Output:\n{captured_output}"
73
+
74
+ return {
75
+ "fig": self.fig,
76
+ "output": self.output,
77
+ "error": self.error,
78
+ "success": self.error is None and self.fig is not None,
79
+ }
@@ -0,0 +1,26 @@
1
+ from pydantic import BaseModel, Field
2
+
3
+
4
+ # Define input schemas for the tools
5
+ class PlotDescriptionInput(BaseModel):
6
+ plot_description: str = Field(
7
+ ..., description="Description of the plot the user wants to create"
8
+ )
9
+
10
+
11
+ class GeneratedCodeInput(BaseModel):
12
+ generated_code: str = Field(
13
+ ..., description="Python code that creates a Plotly figure"
14
+ )
15
+
16
+
17
+ class DoesFigExistInput(BaseModel):
18
+ """Model indicating that the does_fig_exist function takes no arguments."""
19
+
20
+ pass
21
+
22
+
23
+ class ViewGeneratedCodeInput(BaseModel):
24
+ """Model indicating that the view_generated_code function takes no arguments."""
25
+
26
+ pass
@@ -0,0 +1,57 @@
1
+ DEFAULT_SYSTEM_PROMPT = """
2
+ You are an expert data visualization assistant that helps users create Plotly visualizations in Python.
3
+ Your job is to generate Python and Plotly code based on the user's request that will create the desired visualization
4
+ of their pandas DataFrame (df).
5
+
6
+ You have access to a pandas df with the following information:
7
+
8
+ df.info():
9
+ ```plaintext
10
+ {df_info}
11
+ ```
12
+
13
+ df.head():
14
+ ```plaintext
15
+ {df_head}
16
+ ```
17
+
18
+ {sql_context}
19
+
20
+ NOTES:
21
+ - You must use the execute_plotly_code(generated_code) tool run your code and use the does_fig_exist() tool to check that a fig object is available for display.
22
+ - You must paste the full code, not just a reference to the code.
23
+ - You must not use fig.show() in your code as it will ultimately be executed elsewhere in a headless environment.
24
+ - If you need to do any data cleaning or wrangling, do it in the code before generating the plotly code as preprocessing steps assume the data is in the pandas 'df' object.
25
+
26
+ TOOLS:
27
+ - execute_plotly_code(generated_code) to execute the generated code.
28
+ - does_fig_exist() to check that a fig object is available for display. This tool takes no arguments.
29
+ - view_generated_code() to view the generated code if need to fix it. This tool takes no arguments.
30
+
31
+ IMPORTANT CODE FORMATTING INSTRUCTIONS:
32
+ 1. Include thorough, detailed comments in your code to explain what each section does.
33
+ 2. Use descriptive variable names.
34
+ 3. DO NOT include fig.show() in your code - the visualization will be rendered externally.
35
+ 4. Ensure your code creates a variable named 'fig' that contains the Plotly figure object.
36
+
37
+ When a user asks for a visualization:
38
+ 1. YOU MUST ALWAYS use the execute_plotly_code(generated_code) tool to test and run your code.
39
+ 2. If there are errors, view the generated code using view_generated_code() and fix the code.
40
+ 3. Check that a figure object is available using does_fig_exist(). does_fig_exist() takes no arguments.
41
+ 4. If the figure object is not available, repeat the process until it is available.
42
+
43
+ IMPORTANT: The code you generate MUST be executed using the execute_plotly_code tool or no figure will be created!
44
+ YOU MUST CALL execute_plotly_code WITH THE FULL CODE, NOT JUST A REFERENCE TO THE CODE.
45
+
46
+ YOUR WORKFLOW MUST BE:
47
+ 1. execute_plotly_code(generated_code) to make sure the code is ran and a figure object is created.
48
+ 2. check that a figure object is available using does_fig_exist() to make sure the figure object was created.
49
+ 3. if there are errors, view the generated code using view_generated_code() to see what went wrong.
50
+ 4. fix the code and execute it again with execute_plotly_code(generated_code) to make sure the figure object is created.
51
+ 5. repeat until the figure object is available.
52
+
53
+ Always return the final working code (with all the comments) to the user along with an explanation of what the visualization shows.
54
+ Make sure to follow best practices for data visualization, such as appropriate chart types, labels, and colors.
55
+
56
+ Remember that users may want to iterate on their visualizations, so be responsive to requests for changes.
57
+ """
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: plot-agent
3
- Version: 0.1.2
3
+ Version: 0.2.1
4
4
  Summary: An AI-powered data visualization assistant using Plotly
5
5
  Author-email: andrewm4894 <andrewm4894@gmail.com>
6
6
  Project-URL: Homepage, https://github.com/andrewm4894/plot-agent
@@ -14,6 +14,9 @@ Dynamic: license-file
14
14
 
15
15
  # Plot Agent
16
16
 
17
+ [![Tests](https://github.com/andrewm4894/plot-agent/actions/workflows/test.yml/badge.svg)](https://github.com/andrewm4894/plot-agent/actions/workflows/test.yml)
18
+ [![PyPI version](https://badge.fury.io/py/plot-agent.svg)](https://badge.fury.io/py/plot-agent)
19
+
17
20
  An AI-powered data visualization assistant that helps users create Plotly visualizations in Python.
18
21
 
19
22
  ## Installation
@@ -26,12 +29,15 @@ pip install plot-agent
26
29
 
27
30
  ## Usage
28
31
 
29
- Here's a simple example of how to use Plot Agent:
32
+ See more examples in [/examples/](https://nbviewer.org/github/andrewm4894/plot-agent/tree/main/examples/) (via nbviewer so that can see the charts easily).
33
+
34
+ Here's a simple minimal example of how to use Plot Agent:
30
35
 
31
36
  ```python
32
37
  import pandas as pd
33
- from plot_agent.plotly_agent import PlotlyAgent
38
+ from plot_agent.agent import PlotlyAgent
34
39
 
40
+ # ensure OPENAI_API_KEY is set and available for langchain
35
41
 
36
42
  # Create a sample dataframe
37
43
  df = pd.DataFrame({
@@ -47,10 +53,45 @@ agent.set_df(df)
47
53
 
48
54
  # Process a visualization request
49
55
  response = agent.process_message("Create a line plot of x vs y")
56
+
57
+ # Print generated code
58
+ print(agent.generated_code)
59
+
60
+ # Get fig
50
61
  fig = agent.get_figure()
51
62
  fig.show()
52
63
  ```
53
64
 
65
+ `agent.generated_code`:
66
+
67
+ ```python
68
+ import pandas as pd
69
+ import plotly.graph_objects as go
70
+
71
+ # Creating a line plot of x vs y
72
+ # Create a figure object
73
+ fig = go.Figure()
74
+
75
+ # Add a line trace to the figure
76
+ fig.add_trace(
77
+ go.Scatter(
78
+ x=df['x'], # The x values
79
+ y=df['y'], # The y values
80
+ mode='lines+markers', # Display both lines and markers
81
+ name='Line Plot', # Name of the trace
82
+ line=dict(color='blue', width=2) # Specify line color and width
83
+ )
84
+ )
85
+
86
+ # Adding titles and labels
87
+ fig.update_layout(
88
+ title='Line Plot of x vs y', # Plot title
89
+ xaxis_title='x', # x-axis label
90
+ yaxis_title='y', # y-axis label
91
+ template='plotly_white' # A clean layout
92
+ )
93
+ ```
94
+
54
95
  ## Features
55
96
 
56
97
  - AI-powered visualization generation
@@ -2,8 +2,12 @@ LICENSE
2
2
  README.md
3
3
  pyproject.toml
4
4
  plot_agent/__init__.py
5
- plot_agent/plotly_agent.py
5
+ plot_agent/agent.py
6
+ plot_agent/execution.py
7
+ plot_agent/models.py
8
+ plot_agent/prompt.py
6
9
  plot_agent.egg-info/PKG-INFO
7
10
  plot_agent.egg-info/SOURCES.txt
8
11
  plot_agent.egg-info/dependency_links.txt
9
- plot_agent.egg-info/top_level.txt
12
+ plot_agent.egg-info/top_level.txt
13
+ tests/test_plotly_agent.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "plot-agent"
7
- version = "0.1.2"
7
+ version = "0.2.1"
8
8
  authors = [
9
9
  { name="andrewm4894", email="andrewm4894@gmail.com" },
10
10
  ]
@@ -0,0 +1,152 @@
1
+ import pytest
2
+ import pandas as pd
3
+ import numpy as np
4
+ from plot_agent.agent import PlotlyAgent
5
+ from langchain_core.messages import HumanMessage, AIMessage
6
+
7
+ def test_plotly_agent_initialization():
8
+ """Test that PlotlyAgent initializes correctly."""
9
+ agent = PlotlyAgent()
10
+ assert agent.llm is not None
11
+ assert agent.df is None
12
+ assert agent.df_info is None
13
+ assert agent.df_head is None
14
+ assert agent.sql_query is None
15
+ assert agent.execution_env is None
16
+ assert agent.chat_history == []
17
+ assert agent.agent_executor is None
18
+ assert agent.generated_code is None
19
+
20
+ def test_set_df():
21
+ """Test that set_df properly sets up the dataframe and environment."""
22
+ # Create a sample dataframe
23
+ df = pd.DataFrame({
24
+ 'x': [1, 2, 3, 4, 5],
25
+ 'y': [10, 20, 30, 40, 50]
26
+ })
27
+
28
+ agent = PlotlyAgent()
29
+ agent.set_df(df)
30
+
31
+ assert agent.df is not None
32
+ assert agent.df_info is not None
33
+ assert agent.df_head is not None
34
+ assert agent.execution_env is not None
35
+ assert agent.agent_executor is not None
36
+
37
+ def test_execute_plotly_code():
38
+ """Test that execute_plotly_code works with valid code."""
39
+ df = pd.DataFrame({
40
+ 'x': [1, 2, 3, 4, 5],
41
+ 'y': [10, 20, 30, 40, 50]
42
+ })
43
+
44
+ agent = PlotlyAgent()
45
+ agent.set_df(df)
46
+
47
+ # Test with valid plotly code
48
+ valid_code = """import plotly.express as px
49
+ fig = px.scatter(df, x='x', y='y')"""
50
+
51
+ result = agent.execute_plotly_code(valid_code)
52
+ assert "Code executed successfully" in result
53
+ assert agent.execution_env.fig is not None
54
+
55
+ def test_execute_plotly_code_with_error():
56
+ """Test that execute_plotly_code handles errors properly."""
57
+ df = pd.DataFrame({
58
+ 'x': [1, 2, 3, 4, 5],
59
+ 'y': [10, 20, 30, 40, 50]
60
+ })
61
+
62
+ agent = PlotlyAgent()
63
+ agent.set_df(df)
64
+
65
+ # Test with invalid code
66
+ invalid_code = """import plotly.express as px
67
+ fig = px.scatter(df, x='non_existent_column', y='y')"""
68
+
69
+ result = agent.execute_plotly_code(invalid_code)
70
+ assert "Error" in result
71
+ assert agent.execution_env.fig is None
72
+
73
+ def test_does_fig_exist():
74
+ """Test that does_fig_exist correctly reports figure existence."""
75
+ df = pd.DataFrame({
76
+ 'x': [1, 2, 3, 4, 5],
77
+ 'y': [10, 20, 30, 40, 50]
78
+ })
79
+
80
+ agent = PlotlyAgent()
81
+ agent.set_df(df)
82
+
83
+ # Initially no figure should exist
84
+ assert "No figure has been created yet" in agent.does_fig_exist()
85
+
86
+ # Create a figure
87
+ valid_code = """import plotly.express as px
88
+ fig = px.scatter(df, x='x', y='y')"""
89
+ agent.execute_plotly_code(valid_code)
90
+
91
+ # Now a figure should exist
92
+ assert "A figure is available for display" in agent.does_fig_exist()
93
+
94
+ def test_reset_conversation():
95
+ """Test that reset_conversation clears the chat history."""
96
+ agent = PlotlyAgent()
97
+ agent.chat_history = ["message1", "message2"]
98
+ agent.reset_conversation()
99
+ assert agent.chat_history == []
100
+
101
+ def test_view_generated_code():
102
+ """Test that view_generated_code returns the last generated code."""
103
+ agent = PlotlyAgent()
104
+ test_code = "test code"
105
+ agent.generated_code = test_code
106
+ assert agent.view_generated_code() == test_code
107
+
108
+ def test_get_figure():
109
+ """Test that get_figure returns the current figure if it exists."""
110
+ df = pd.DataFrame({
111
+ 'x': [1, 2, 3, 4, 5],
112
+ 'y': [10, 20, 30, 40, 50]
113
+ })
114
+
115
+ agent = PlotlyAgent()
116
+ agent.set_df(df)
117
+
118
+ # Initially no figure should exist
119
+ assert agent.get_figure() is None
120
+
121
+ # Create a figure
122
+ valid_code = """import plotly.express as px
123
+ fig = px.scatter(df, x='x', y='y')"""
124
+ agent.execute_plotly_code(valid_code)
125
+
126
+ # Now a figure should exist
127
+ assert agent.get_figure() is not None
128
+
129
+ def test_process_message():
130
+ """Test that process_message updates chat history and handles responses."""
131
+ df = pd.DataFrame({
132
+ 'x': [1, 2, 3, 4, 5],
133
+ 'y': [10, 20, 30, 40, 50]
134
+ })
135
+
136
+ agent = PlotlyAgent()
137
+ agent.set_df(df)
138
+
139
+ # Test processing a message
140
+ response = agent.process_message("Create a scatter plot")
141
+
142
+ # Check that chat history was updated
143
+ assert len(agent.chat_history) == 2 # One human message and one AI message
144
+ assert isinstance(agent.chat_history[0], HumanMessage)
145
+ assert isinstance(agent.chat_history[1], AIMessage)
146
+ assert agent.chat_history[0].content == "Create a scatter plot"
147
+
148
+ def test_execute_plotly_code_without_df():
149
+ """Test that execute_plotly_code handles the case when no dataframe is set."""
150
+ agent = PlotlyAgent()
151
+ result = agent.execute_plotly_code("some code")
152
+ assert "Error" in result and "No dataframe has been set" in result
@@ -1,55 +0,0 @@
1
- # Plot Agent
2
-
3
- An AI-powered data visualization assistant that helps users create Plotly visualizations in Python.
4
-
5
- ## Installation
6
-
7
- You can install the package using pip:
8
-
9
- ```bash
10
- pip install plot-agent
11
- ```
12
-
13
- ## Usage
14
-
15
- Here's a simple example of how to use Plot Agent:
16
-
17
- ```python
18
- import pandas as pd
19
- from plot_agent.plotly_agent import PlotlyAgent
20
-
21
-
22
- # Create a sample dataframe
23
- df = pd.DataFrame({
24
- 'x': [1, 2, 3, 4, 5],
25
- 'y': [10, 20, 30, 40, 50]
26
- })
27
-
28
- # Initialize the agent
29
- agent = PlotlyAgent()
30
-
31
- # Set the dataframe
32
- agent.set_df(df)
33
-
34
- # Process a visualization request
35
- response = agent.process_message("Create a line plot of x vs y")
36
- fig = agent.get_figure()
37
- fig.show()
38
- ```
39
-
40
- ## Features
41
-
42
- - AI-powered visualization generation
43
- - Support for various Plotly chart types
44
- - Automatic data preprocessing
45
- - Interactive visualization capabilities
46
- - Integration with LangChain for advanced AI capabilities
47
-
48
- ## Requirements
49
-
50
- - Python 3.8 or higher
51
- - Dependencies are automatically installed with the package
52
-
53
- ## License
54
-
55
- This project is licensed under the MIT License - see the LICENSE file for details.
File without changes
File without changes