MatplotLibAPI 2.0.2__py3-none-any.whl → 3.0.0__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/Bubble.py CHANGED
@@ -1,108 +1,127 @@
1
+ # Hint for Visual Code Python Interactive window
2
+ # %%
1
3
 
2
-
3
- from typing import List, Optional, Union
4
-
5
- import numpy as np
6
4
  import pandas as pd
7
- import seaborn as sns
8
- from sklearn.preprocessing import StandardScaler
9
-
5
+ import matplotlib.pyplot as plt
10
6
  from matplotlib.axes import Axes
11
-
12
- from .Utils import (BUBBLE_STYLE_TEMPLATE, DynamicFuncFormatter,
13
- StyleTemplate, generate_ticks)
14
-
15
- # region Bubble
16
-
17
-
18
- def plot_bubble(ax: Axes,
19
- data: pd.DataFrame,
20
- x_col: str,
21
- y_col: Union[str, List[str]],
22
- fig_title: Optional[str] = None,
23
- style: Optional[StyleTemplate] = None,
24
- legend: bool = False,
25
- z_col: str = "uniques",
26
- hue_col: str = "uniques_quintile",
27
- l_col: str = "dimension",
28
- normalize_x: bool = True,
29
- sizes: tuple = (20, 2000), **kwargs) -> Axes:
30
-
31
- # Clear the axis before plotting
32
- ax.clear()
33
-
34
- # Start formatting
35
- if fig_title is not None:
36
- ax.set_title(fig_title)
37
- if style is None:
38
- style = BUBBLE_STYLE_TEMPLATE
39
- ax.figure.set_facecolor(style.fig_background_color)
40
- ax.figure.set_edgecolor(style.fig_border)
41
- if normalize_x:
42
- # Step 1: Standardize the data to have mean=0 and variance=1
43
- scaler = StandardScaler()
44
- scaled_data = scaler.fit_transform(data[[x_col]])
45
-
46
- # Step 2: Find a scaling factor to confine data within [-100, 100]
47
- scale_factor = 100 / np.max(np.abs(scaled_data))
48
-
49
- # Apply scaling factor
50
- scaled_data *= scale_factor
51
-
52
- # Round to the nearest integer
53
- data[f"{x_col}"] = np.round(scaled_data).astype(int)
54
-
55
- if type(y_col) == list:
56
- y_col = y_col[0]
57
-
58
- g = sns.scatterplot(data=data,
59
- x=x_col,
60
- y=y_col,
61
- size=z_col,
62
- hue=hue_col,
63
- palette=style.palette,
64
- legend=legend,
65
- sizes=sizes,
66
- ax=ax)
67
-
68
- g.set(yscale="log")
69
-
70
- g.axes.xaxis.grid(True, "minor", linewidth=.25)
71
- g.axes.yaxis.grid(True, "minor", linewidth=.25)
72
-
73
- g.axes.axvline(x=0, linestyle='--')
74
-
75
- y_min = data[y_col].min()
76
- y_max = data[y_col].max()
77
- if style.y_formatter is not None:
78
- g.axes.yaxis.set_major_formatter(
79
- DynamicFuncFormatter(style.y_formatter))
80
- g.set_yticks(generate_ticks(y_min, y_max, num_ticks=style.y_ticks))
81
- else:
82
- ylabels = ['{:,.0f}%'.format(y) for y in g.get_yticks()*100]
83
- g.set_yticklabels(ylabels)
84
-
85
- y_mean = data[y_col].mean()
86
-
87
- if style.x_formatter is not None:
88
- x_min = data[x_col].min()
89
- x_max = data[x_col].max()
90
- g.xaxis.set_major_formatter(
91
- DynamicFuncFormatter(style.x_formatter))
92
- g.set_xticks(generate_ticks(x_min, x_max, num_ticks=style.x_ticks))
93
-
94
- g.axes.xaxis.grid(True, "minor", linewidth=.25)
95
- g.axes.yaxis.grid(True, "minor", linewidth=.25)
96
- g.hlines(y=y_mean, xmin=x_min, xmax=x_max,
97
- linestyle='--', colors=style.font_color)
98
-
99
- for index, row in data.iterrows():
100
- x = row[x_col]
101
- y = row[y_col[0] if type(y_col) == List else y_col]
102
- s = row[l_col]
103
- g.text(x, y, s, horizontalalignment='center',
104
- fontsize=style.font_size*row[hue_col], color=style.font_color)
105
-
7
+ import seaborn as sns
8
+ from typing import Optional
9
+ from .Style import DynamicFuncFormatter, StyleTemplate, generate_ticks, _validate_panda, string_formatter, bmk_formatter, percent_formatter, format_func
10
+
11
+
12
+ BUBBLE_STYLE_TEMPLATE = StyleTemplate(
13
+ format_funcs={"label": string_formatter,
14
+ "x": bmk_formatter,
15
+ "y": percent_formatter,
16
+ "label": string_formatter,
17
+ "z": bmk_formatter},
18
+ yscale="log",
19
+ y_ticks=8,
20
+ x_ticks=8
21
+ )
22
+
23
+
24
+ def plot_bubble(
25
+ pd_df: pd.DataFrame,
26
+ label: str,
27
+ x: str,
28
+ y: str,
29
+ z: str,
30
+ title: Optional[str] = "Test",
31
+ style: StyleTemplate = BUBBLE_STYLE_TEMPLATE,
32
+ max_values: int = BUBBLE_STYLE_TEMPLATE,
33
+ center_to_mean: bool = False,
34
+ sort_by: Optional[str] = None,
35
+ ascending: bool = False,
36
+ ax: Optional[Axes] = None):
37
+
38
+ _validate_panda(pd_df, cols=[label, x, y, z], sort_by=sort_by)
39
+ style.format_funcs = format_func(
40
+ style.format_funcs, label=label, x=x, y=y, z=z)
41
+ if not sort_by:
42
+ sort_by = z
43
+
44
+ plot_df = pd_df[[label, x, y, z]].sort_values(
45
+ by=sort_by, ascending=ascending).head(max_values)
46
+ if center_to_mean:
47
+ x_col_mean = plot_df[x].mean()
48
+ plot_df[x] = plot_df[x] - x_col_mean
49
+ plot_df['quintile'] = pd.qcut(
50
+ plot_df[z], 5, labels=False)
51
+
52
+ # styling
53
+
54
+ plot_df["fontsize"] = plot_df['quintile'].map(style.font_mapping)
55
+
56
+ if not ax:
57
+ ax = plt.gca()
58
+
59
+ ax = sns.scatterplot(
60
+ data=plot_df,
61
+ x=x,
62
+ y=y,
63
+ size=z,
64
+ hue='quintile',
65
+ sizes=(100, 2000),
66
+ legend=False,
67
+ palette=sns.color_palette(style.palette, as_cmap=True),
68
+ edgecolor=style.background_color,
69
+ ax=ax)
70
+ ax.set_facecolor(style.background_color)
71
+ if style.xscale:
72
+ ax.set(xscale=style.xscale)
73
+ if style.yscale:
74
+ ax.set(yscale=style.yscale)
75
+
76
+ x_min = pd_df[x].min()
77
+ x_max = pd_df[x].max()
78
+ x_mean = pd_df[x].mean()
79
+ ax.set_xticks(generate_ticks(x_min, x_max, num_ticks=style.x_ticks))
80
+ ax.xaxis.grid(True, "major", linewidth=.5, color=style.font_color)
81
+ if style.format_funcs.get("x"):
82
+ ax.xaxis.set_major_formatter(
83
+ DynamicFuncFormatter(style.format_funcs.get("x")))
84
+
85
+ y_min = pd_df[y].min()
86
+ y_max = pd_df[y].max()
87
+ y_mean = pd_df[y].mean()
88
+ ax.set_yticks(generate_ticks(y_min, y_max, num_ticks=style.y_ticks))
89
+ ax.yaxis.grid(True, "major", linewidth=.5, color=style.font_color)
90
+ if style.format_funcs.get("y"):
91
+ ax.yaxis.set_major_formatter(
92
+ DynamicFuncFormatter(style.format_funcs.get("y")))
93
+
94
+ ax.tick_params(axis='both',
95
+ which='major',
96
+ colors=style.font_color,
97
+ labelsize=style.font_size)
98
+
99
+ ax.vlines(x=x_mean,
100
+ ymin=y_min,
101
+ ymax=y_max,
102
+ linestyle='--',
103
+ colors=style.font_color)
104
+ ax.hlines(y=y_mean,
105
+ xmin=x_min,
106
+ xmax=x_max,
107
+ linestyle='--',
108
+ colors=style.font_color)
109
+
110
+ for index, row in plot_df.iterrows():
111
+ x_value = row[x]
112
+ y_value = row[y]
113
+ s_value = str(row[label])
114
+ if style.format_funcs.get("label"):
115
+ s_value = style.format_funcs.get("label")(s_value)
116
+ fs = row["fontsize"]
117
+ ax.text(x_value,
118
+ y_value,
119
+ s_value,
120
+ horizontalalignment='center',
121
+ fontdict={'color': style.font_color, 'fontsize': fs})
122
+ if title:
123
+ ax.set_title(title, color=style.font_color, fontsize=style.font_size*2)
106
124
  return ax
107
125
 
126
+
108
127
  # endregion
@@ -1,109 +1,78 @@
1
1
  # Hint for Visual Code Python Interactive window
2
2
  # %%
3
3
  import matplotlib.pyplot as plt
4
+ from matplotlib.figure import Figure
4
5
  import pandas as pd
5
- from .Bubble import plot_bubble
6
+ from .Bubble import plot_bubble, BUBBLE_STYLE_TEMPLATE
6
7
  from .Table import plot_table
7
- from typing import Callable, Dict, Optional, List
8
- from matplotlib.axes import Axes
9
-
10
-
11
- def plot_composite(data: pd.DataFrame,
12
- sort_column: str,
13
- mappings: Dict[str, Callable],
14
- num_rows: int = 10,
15
- font_size: int = 12,
16
- fig_title: str = 'Bubble Plot',
17
- fig_background_color: str = 'skyblue',
18
- fig_border: str = 'steelblue',
19
- font_name: str = 'Arial',
20
- font_color: str = 'black') -> None:
21
-
22
- data['uniques_quintile'] = pd.qcut(data['uniques'], 5, labels=False)
23
- text_size_mapping = {0: 8, 1: 9, 2: 10, 3: 12, 4: 14}
24
- data["font_size"] = data['uniques_quintile'].map(text_size_mapping)
25
-
26
- data['audience_quintile'] = pd.qcut(data['audience'], 5, labels=False)
27
- data['INDEX_quintile'] = pd.qcut(data['INDEX'], 5, labels=False)
28
- # Adjust font size for better readability
29
- plt.rc('font', size=font_size)
30
-
31
- fig = plt.figure("Graph", figsize=(10, 10))
32
-
33
- axgrid = fig.add_gridspec(5, 4)
34
-
35
- ax0 = fig.add_subplot(axgrid[0:3, :])
36
- plot_bubble(ax=ax0,
37
- data=data,
38
- font_size=font_size,
39
- fig_background_color=fig_background_color,
40
- fig_border=fig_border,
41
- font_name=font_name)
42
- ax0.set_title(fig_title) # Add title
43
- ax0.set_axis_off()
44
-
45
- ax1 = fig.add_subplot(axgrid[3:, :2])
46
- top_10 = data.sort_values(by="INDEX", ascending=False).head(10)
47
-
48
- plot_table(ax=ax1,
49
- data=top_10,
50
- mappings=mappings,
51
- sort_column=sort_column,
52
- num_rows=num_rows,
53
- fig_background_color=fig_background_color,
54
- fig_border=fig_border,
55
- font_name=font_name,
56
- font_size=font_size,
57
- font_color=font_color)
58
- ax1.set_title('Top Items') # Add title
59
- ax1.set_axis_off()
60
-
61
- ax2 = fig.add_subplot(axgrid[3:, 2:])
62
- worst_10 = data.sort_values(by="INDEX").head(10)
63
- plot_table(ax=ax2,
64
- data=worst_10,
65
- mappings=mappings,
66
- sort_column=sort_column,
67
- num_rows=num_rows,
68
- fig_background_color=fig_background_color,
69
- fig_border=fig_border,
70
- font_name=font_name,
71
- font_size=font_size,
72
- sort_ascending=True)
73
- ax2.set_title('Worst Items') # Add title
74
- ax2.set_axis_off()
75
-
76
- fig.tight_layout()
77
-
78
-
79
- def plot_composite_12(plot_func1, plot_func2, plot_func3,
80
- data1, data2, data3,
81
- metrics1, metrics2, metrics3,
82
- highlights: Optional[List[str]] = None,
83
- font_size: int = 12,
84
- fig_title: str = 'Bubble Plot',
85
- fig_background_color: str = 'skyblue',
86
- fig_border: str = 'steelblue',
87
- font_name: str = 'Arial',
88
- font_color: str = 'black') -> None:
89
-
90
- # Create a new figure and define the grid
91
- fig = plt.figure(fig_title, figsize=(10, 10))
92
- axgrid = fig.add_gridspec(5, 4)
93
-
94
- # Create individual axes based on the grid
95
- ax0 = fig.add_subplot(axgrid[0:3, :])
96
- ax1 = fig.add_subplot(axgrid[3:, :2])
97
- ax2 = fig.add_subplot(axgrid[3:, 2:])
98
-
99
- # Call the individual plot functions with the respective axes and data
100
- plot_func1(ax=ax0, data=data1, metrics=metrics1, highlights=highlights, font_size=font_size, fig_background_color=fig_background_color,
101
- fig_border=fig_border, font_name=font_name, font_color=font_color)
102
- plot_func2(ax=ax1, data=data2, metrics=metrics2, highlights=highlights, font_size=font_size, fig_background_color=fig_background_color,
103
- fig_border=fig_border, font_name=font_name, font_color=font_color)
104
- plot_func3(ax=ax2, data=data3, metrics=metrics3, highlights=highlights, font_size=font_size, fig_background_color=fig_background_color,
105
- fig_border=fig_border, font_name=font_name, font_color=font_color)
106
-
107
- fig.suptitle(fig_title, fontsize=16)
8
+ from typing import Optional, Tuple
9
+ from .Style import StyleTemplate, _validate_panda,format_func
10
+
11
+
12
+ def plot_composite_bubble(
13
+ pd_df: pd.DataFrame,
14
+ label: str,
15
+ x: str,
16
+ y: str,
17
+ z: str,
18
+ title: Optional[str] = "Test",
19
+ style: StyleTemplate = BUBBLE_STYLE_TEMPLATE,
20
+ max_values: int = 50,
21
+ center_to_mean: bool = False,
22
+ sort_by: Optional[str] = None,
23
+ ascending: bool = False,
24
+ table_rows: int = 10,
25
+ figsize: Tuple[float, float] = (19.2, 10.8)) -> Figure:
26
+
27
+ _validate_panda(pd_df, cols=[label, x, y, z], sort_by=sort_by)
28
+ style.format_funcs=format_func(style.format_funcs,label=label,x=x,y=y)
29
+ fig = plt.figure(figsize=figsize)
30
+ fig.patch.set_facecolor("black")
31
+ grid = plt.GridSpec(2, 2, height_ratios=[2, 1], width_ratios=[1, 1])
32
+ ax = fig.add_subplot(grid[0, 0:])
33
+ ax = plot_bubble(pd_df=pd_df,
34
+ label=label,
35
+ x=x,
36
+ y=y,
37
+ z=z,
38
+ title=title,
39
+ style=style,
40
+ max_values=max_values,
41
+ center_to_mean=center_to_mean,
42
+ sort_by=sort_by,
43
+ ascending=ascending,
44
+ ax=ax)
45
+
46
+ if "label" in style.format_funcs:
47
+ style.format_funcs[label] = style.format_funcs["label"]
48
+ if "x" in style.format_funcs:
49
+ style.format_funcs[x] = style.format_funcs["x"]
50
+ if "y" in style.format_funcs:
51
+ style.format_funcs[y] = style.format_funcs["y"]
52
+ if "z" in style.format_funcs:
53
+ style.format_funcs[z] = style.format_funcs["z"]
54
+
55
+ ax2 = fig.add_subplot(grid[1, 0])
56
+ ax2 = plot_table(
57
+ pd_df=pd_df,
58
+ cols=[label, z, y, x],
59
+ title=f"Top {table_rows}",
60
+ ax=ax2,
61
+ sort_by=sort_by,
62
+ ascending=False,
63
+ max_values=table_rows,
64
+ style=style
65
+ )
66
+ ax3 = fig.add_subplot(grid[1, 1])
67
+ ax3 = plot_table(
68
+ pd_df=pd_df,
69
+ cols=[label, z, y, x],
70
+ title=f"Worst {table_rows}",
71
+ ax=ax3,
72
+ sort_by=sort_by,
73
+ ascending=True,
74
+ max_values=table_rows,
75
+ style=style
76
+ )
108
77
  fig.tight_layout()
109
78
  return fig
MatplotLibAPI/Network.py CHANGED
@@ -4,19 +4,27 @@ from collections.abc import Iterable
4
4
  from typing import Any, Dict, List, Optional, Tuple
5
5
 
6
6
  import matplotlib.pyplot as plt
7
+ from matplotlib.axes import Axes
8
+ import seaborn as sns
7
9
  import networkx as nx
8
10
  import numpy as np
9
11
  import pandas as pd
10
12
  from networkx import Graph
11
13
  from networkx.classes.graph import Graph
12
14
 
15
+
16
+ from .Style import StyleTemplate, string_formatter, _validate_panda,format_func
17
+
18
+ NETWORK_STYLE_TEMPLATE = StyleTemplate(
19
+ )
20
+
13
21
  DEFAULT = {"MAX_EDGES": 100,
14
22
  "MAX_NODES": 30,
15
23
  "MIN_NODE_SIZE": 100,
16
24
  "MAX_NODE_SIZE": 2000,
17
25
  "MAX_EDGE_WIDTH": 10,
18
26
  "GRAPH_SCALE": 2,
19
- "MAX_FONT_SIZE": 12,
27
+ "MAX_FONT_SIZE": 20,
20
28
  "MIN_FONT_SIZE": 8
21
29
  }
22
30
 
@@ -25,7 +33,7 @@ def softmax(x):
25
33
  return (np.exp(x - np.max(x)) / np.exp(x - np.max(x)).sum())
26
34
 
27
35
 
28
- def scale_weights(weights, scale_min=0,scale_max=1):
36
+ def scale_weights(weights, scale_min=0, scale_max=1):
29
37
  deciles = np.percentile(weights, [10, 20, 30, 40, 50, 60, 70, 80, 90])
30
38
  outs = np.searchsorted(deciles, weights)
31
39
  return [out * (scale_max-scale_min)/len(deciles)+scale_min for out in outs]
@@ -160,8 +168,9 @@ class Graph(nx.Graph):
160
168
  def subgraphX(self, node_list=None, max_edges: int = DEFAULT["MAX_EDGES"]):
161
169
  if node_list is None:
162
170
  node_list = self.nodes.sort("weight")[:DEFAULT["MAX_NODES"]]
163
- connected_subgraph_nodes=list(self.find_connected_subgraph())
164
- node_list = [node for node in node_list if node in connected_subgraph_nodes]
171
+ connected_subgraph_nodes = list(self.find_connected_subgraph())
172
+ node_list = [
173
+ node for node in node_list if node in connected_subgraph_nodes]
165
174
 
166
175
  subgraph = nx.subgraph(
167
176
  self, nbunch=node_list)
@@ -169,30 +178,39 @@ class Graph(nx.Graph):
169
178
  subgraph = subgraph.edge_subgraph(list(edges)[:max_edges])
170
179
  return subgraph
171
180
 
172
- def plotX(self):
181
+ def plotX(self,
182
+ title: str = "Test",
183
+ style: StyleTemplate = NETWORK_STYLE_TEMPLATE,
184
+ ax: Optional[Axes] = None) -> Axes:
173
185
  """
174
186
  Plots the degree distribution of the graph, including a degree rank plot and a degree histogram.
175
187
  """
176
188
  degree_sequence = sorted([d for n, d in self.degree()], reverse=True)
177
189
  dmax = max(degree_sequence)
178
-
179
- fig, ax = plt.subplots()
190
+ sns.set_palette(style.palette)
191
+ if ax is None:
192
+ ax = plt.gca()
180
193
 
181
194
  node_sizes, edge_widths, font_sizes = self.layout(
182
- DEFAULT["MAX_NODE_SIZE"], DEFAULT["MAX_EDGE_WIDTH"], 14)
195
+ min_node_size=DEFAULT["MIN_NODE_SIZE"]/5,
196
+ max_node_size=DEFAULT["MAX_NODE_SIZE"],
197
+ max_edge_width=DEFAULT["MAX_EDGE_WIDTH"],
198
+ min_font_size=style.font_mapping.get(0),
199
+ max_font_size=style.font_mapping.get(4))
183
200
  pos = nx.spring_layout(self, k=1)
184
201
  # nodes
185
202
  nx.draw_networkx_nodes(self,
186
203
  pos,
187
204
  ax=ax,
188
205
  node_size=list(node_sizes),
189
- # node_color=list(node_sizes.values()),
190
- cmap=plt.cm.Blues)
206
+ node_color=node_sizes,
207
+ cmap=plt.cm.get_cmap(style.palette))
191
208
  # edges
192
209
  nx.draw_networkx_edges(self,
193
210
  pos,
194
211
  ax=ax,
195
- alpha=0.4,
212
+ edge_color=style.font_color,
213
+ edge_cmap=plt.cm.get_cmap(style.palette),
196
214
  width=edge_widths)
197
215
  # labels
198
216
  for font_size, nodes in font_sizes.items():
@@ -201,16 +219,13 @@ class Graph(nx.Graph):
201
219
  pos,
202
220
  ax=ax,
203
221
  font_size=font_size,
204
- labels={n: n for n in nodes},
205
- alpha=0.4)
206
-
207
- ax.set_title(self.name)
222
+ font_color=style.font_color,
223
+ labels={n: string_formatter(n) for n in nodes})
224
+ ax.set_facecolor(style.background_color)
225
+ ax.set_title(title, color=style.font_color, fontsize=style.font_size*2)
208
226
  ax.set_axis_off()
209
227
 
210
-
211
-
212
- fig.tight_layout()
213
- return fig
228
+ return ax
214
229
 
215
230
  def analysis(self, node_list: Optional[List] = None,
216
231
  scale: int = DEFAULT["GRAPH_SCALE"],
@@ -242,12 +257,14 @@ class Graph(nx.Graph):
242
257
  for node in list(H.nodes):
243
258
  if H.degree(node) < 2:
244
259
  # Remove the node and its incident edges
245
- logging.info(f'Removing the {node} node and its incident edges')
260
+ logging.info(
261
+ f'Removing the {node} node and its incident edges')
246
262
  H.remove_node(node)
247
263
  removed_node = True
248
264
  break
249
265
 
250
266
  return H
267
+
251
268
  def top_k_edges(self, attribute: str, reverse: bool = True, k: int = 5) -> Dict[Any, List[Tuple[Any, Dict]]]:
252
269
  """
253
270
  Returns the top k edges per node based on the given attribute.
@@ -275,10 +292,10 @@ class Graph(nx.Graph):
275
292
  return top_list
276
293
 
277
294
  @staticmethod
278
- def from_pandas_edgelist(df,
279
- source: Optional[str] = "source",
280
- target: Optional[str] = "target",
281
- weight: Optional[str] = "weight"):
295
+ def from_pandas_edgelist(df: pd.DataFrame,
296
+ source: str = "source",
297
+ target: str = "target",
298
+ weight: str = "weight"):
282
299
  """
283
300
  Initialize netX instance with a simple dataframe
284
301
 
@@ -291,7 +308,7 @@ class Graph(nx.Graph):
291
308
  G = Graph()
292
309
  G = nx.from_pandas_edgelist(
293
310
  df, source=source, target=target, edge_attr=weight, create_using=G)
294
- G=G.find_connected_subgraph()
311
+ G = G.find_connected_subgraph()
295
312
 
296
313
  edge_aggregates = G.top_k_edges(attribute=weight, k=10)
297
314
  node_aggregates = {}
@@ -308,11 +325,23 @@ class Graph(nx.Graph):
308
325
  G = G.edge_subgraph(edges=G.top_k_edges(attribute=weight))
309
326
  return G
310
327
 
311
- def plot_network(data:pd.DataFrame):
312
- graph = Graph.from_pandas_edgelist(data)
313
- graph = graph.subgraphX()
314
- return graph.analysis()
315
-
316
-
317
-
318
328
 
329
+ def plot_network(pd_df: pd.DataFrame,
330
+ source: str = "source",
331
+ target: str = "target",
332
+ weight: str = "weight",
333
+ title: str = "Test",
334
+ style: StyleTemplate = NETWORK_STYLE_TEMPLATE,
335
+ sort_by: Optional[str] = None,
336
+ ascending: bool = False,
337
+ ax: Optional[Axes] = None) -> Axes:
338
+
339
+ _validate_panda(pd_df, cols=[source, target, weight], sort_by=sort_by)
340
+
341
+ graph = Graph.from_pandas_edgelist(pd_df,
342
+ source=source,
343
+ target=target,
344
+ weight=weight)
345
+ return graph.plotX(title=title,
346
+ style=style,
347
+ ax=ax)