pyedb 0.39.1__py3-none-any.whl → 0.40.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.

Potentially problematic release.


This version of pyedb might be problematic. Click here for more details.

@@ -54,6 +54,7 @@ from pyedb.grpc.database.definition.component_pin import ComponentPin
54
54
  from pyedb.grpc.database.hierarchy.component import Component
55
55
  from pyedb.grpc.database.hierarchy.pin_pair_model import PinPairModel
56
56
  from pyedb.grpc.database.hierarchy.pingroup import PinGroup
57
+ from pyedb.grpc.database.padstacks import Padstacks
57
58
  from pyedb.grpc.database.utility.sources import SourceType
58
59
  from pyedb.modeler.geometry_operators import GeometryOperators
59
60
 
@@ -119,17 +120,10 @@ class Components(object):
119
120
 
120
121
  def __init__(self, p_edb):
121
122
  self._pedb = p_edb
122
- self._cmp = {}
123
- self._res = {}
124
- self._cap = {}
125
- self._ind = {}
126
- self._ios = {}
127
- self._ics = {}
128
- self._others = {}
123
+ self.refresh_components()
129
124
  self._pins = {}
130
125
  self._comps_by_part = {}
131
- self._init_parts()
132
- # self._padstack = Padstacks(self._pedb)
126
+ self._padstack = Padstacks(self._pedb)
133
127
  # self._excitations = self._pedb.excitations
134
128
 
135
129
  @property
@@ -137,16 +131,6 @@ class Components(object):
137
131
  """Logger."""
138
132
  return self._pedb.logger
139
133
 
140
- def _init_parts(self):
141
- a = self.instances
142
- a = self.resistors
143
- a = self.ICs
144
- a = self.Others
145
- a = self.inductors
146
- a = self.IOs
147
- a = self.components_by_partname
148
- return True
149
-
150
134
  @property
151
135
  def _active_layout(self):
152
136
  return self._pedb.active_layout
@@ -180,8 +164,6 @@ class Components(object):
180
164
  >>> edbapp.components.instances
181
165
 
182
166
  """
183
- if not self._cmp:
184
- self.refresh_components()
185
167
  return self._cmp
186
168
 
187
169
  @property
@@ -287,10 +269,28 @@ class Components(object):
287
269
  """Refresh the component dictionary."""
288
270
  self._logger.info("Refreshing the Components dictionary.")
289
271
  self._cmp = {}
272
+ self._res = {}
273
+ self._ind = {}
274
+ self._cap = {}
275
+ self._ics = {}
276
+ self._ios = {}
277
+ self._others = {}
290
278
  for i in self._pedb.layout.groups:
291
- if isinstance(i, Component):
292
- if not i.is_null:
293
- self._cmp[i.name] = i
279
+ self._cmp[i.name] = i
280
+ if i.type == "resistor":
281
+ self._res[i.name] = i
282
+ elif i.type == "capacitor":
283
+ self._cap[i.name] = i
284
+ elif i.type == "inductor":
285
+ self._ind[i.name] = i
286
+ elif i.type == "ic":
287
+ self._ics[i.name] = i
288
+ elif i.type == "io":
289
+ self._ios[i.name] = i
290
+ elif i.type == "other":
291
+ self._others[i.name] = i
292
+ else:
293
+ self._logger.warning(f"Unknown component type {i.name} found while refreshing components, will ignore")
294
294
  return True
295
295
 
296
296
  @property
@@ -309,14 +309,6 @@ class Components(object):
309
309
  >>> edbapp = Edb("myaedbfolder")
310
310
  >>> edbapp.components.resistors
311
311
  """
312
- self._res = {}
313
- for el, val in self.instances.items():
314
- if not val.is_null:
315
- try:
316
- if val.type == "resistor":
317
- self._res[el] = val
318
- except:
319
- pass
320
312
  return self._res
321
313
 
322
314
  @property
@@ -335,14 +327,6 @@ class Components(object):
335
327
  >>> edbapp = Edb("myaedbfolder")
336
328
  >>> edbapp.components.capacitors
337
329
  """
338
- self._cap = {}
339
- for el, val in self.instances.items():
340
- if not val.is_null:
341
- try:
342
- if val.type == "capacitor":
343
- self._cap[el] = val
344
- except:
345
- pass
346
330
  return self._cap
347
331
 
348
332
  @property
@@ -362,14 +346,6 @@ class Components(object):
362
346
  >>> edbapp.components.inductors
363
347
 
364
348
  """
365
- self._ind = {}
366
- for el, val in self.instances.items():
367
- if not val.is_null:
368
- try:
369
- if val.type == "inductor":
370
- self._ind[el] = val
371
- except:
372
- pass
373
349
  return self._ind
374
350
 
375
351
  @property
@@ -389,14 +365,6 @@ class Components(object):
389
365
  >>> edbapp.components.ICs
390
366
 
391
367
  """
392
- self._ics = {}
393
- for el, val in self.instances.items():
394
- if not val.is_null:
395
- try:
396
- if val.type == "ic":
397
- self._ics[el] = val
398
- except:
399
- pass
400
368
  return self._ics
401
369
 
402
370
  @property
@@ -416,14 +384,6 @@ class Components(object):
416
384
  >>> edbapp.components.IOs
417
385
 
418
386
  """
419
- self._ios = {}
420
- for el, val in self.instances.items():
421
- if not val.is_null:
422
- try:
423
- if val.type == "io":
424
- self._ios[el] = val
425
- except:
426
- pass
427
387
  return self._ios
428
388
 
429
389
  @property
@@ -443,14 +403,6 @@ class Components(object):
443
403
  >>> edbapp.components.others
444
404
 
445
405
  """
446
- self._others = {}
447
- for el, val in self.instances.items():
448
- if not val.is_null:
449
- try:
450
- if val.type == "other":
451
- self._others[el] = val
452
- except:
453
- pass
454
406
  return self._others
455
407
 
456
408
  @property
@@ -26,7 +26,7 @@ import difflib
26
26
  import logging
27
27
  import os
28
28
  import re
29
- from typing import Optional
29
+ from typing import Optional, Union
30
30
  import warnings
31
31
 
32
32
  from ansys.edb.core.definition.debye_model import DebyeModel as GrpcDebyeModel
@@ -1205,3 +1205,18 @@ class Materials(object):
1205
1205
 
1206
1206
  self.__edb.logger.error(f"Material {material_name} does not exist in syslib AMAT file.")
1207
1207
  return res
1208
+
1209
+ def update_materials_from_sys_library(self, update_all: bool = True, material_name: Union[str, list] = None):
1210
+ """Update material properties from syslib AMAT file."""
1211
+ amat_file = os.path.join(self.__edb.base_path, "syslib", "Materials.amat")
1212
+ materials_dict = self.read_materials(amat_file)
1213
+ if update_all:
1214
+ for name, obj in self.materials.items():
1215
+ if name in materials_dict:
1216
+ obj.update(materials_dict[name])
1217
+ self.__edb.logger.info(f"Material {name} is updated from syslibrary.")
1218
+ else:
1219
+ material_names = material_name if isinstance(material_name, list) else [material_name]
1220
+ for name in material_names:
1221
+ self.materials[name].update(materials_dict[name])
1222
+ self.__edb.logger.info(f"Material {name} is updated from syslibrary.")
@@ -26,6 +26,7 @@ This module contains these classes: `EdbLayout` and `Shape`.
26
26
  from typing import Union
27
27
 
28
28
  from ansys.edb.core.layout.layout import Layout as GrpcLayout
29
+ import ansys.edb.core.primitive.primitive
29
30
 
30
31
  from pyedb.grpc.database.hierarchy.component import Component
31
32
  from pyedb.grpc.database.hierarchy.pingroup import PinGroup
@@ -34,7 +35,12 @@ from pyedb.grpc.database.net.differential_pair import DifferentialPair
34
35
  from pyedb.grpc.database.net.extended_net import ExtendedNet
35
36
  from pyedb.grpc.database.net.net import Net
36
37
  from pyedb.grpc.database.net.net_class import NetClass
38
+ from pyedb.grpc.database.primitive.bondwire import Bondwire
39
+ from pyedb.grpc.database.primitive.circle import Circle
37
40
  from pyedb.grpc.database.primitive.padstack_instance import PadstackInstance
41
+ from pyedb.grpc.database.primitive.path import Path
42
+ from pyedb.grpc.database.primitive.polygon import Polygon
43
+ from pyedb.grpc.database.primitive.rectangle import Rectangle
38
44
  from pyedb.grpc.database.terminal.bundle_terminal import BundleTerminal
39
45
  from pyedb.grpc.database.terminal.edge_terminal import EdgeTerminal
40
46
  from pyedb.grpc.database.terminal.padstack_instance_terminal import (
@@ -59,6 +65,24 @@ class Layout(GrpcLayout):
59
65
  """
60
66
  return self._pedb._active_cell
61
67
 
68
+ @property
69
+ def primitives(self):
70
+ prims = []
71
+ for prim in super().primitives:
72
+ if isinstance(prim, ansys.edb.core.primitive.primitive.Path):
73
+ prims.append(Path(self._pedb, prim))
74
+ elif isinstance(prim, ansys.edb.core.primitive.primitive.Polygon):
75
+ prims.append(Polygon(self._pedb, prim))
76
+ elif isinstance(prim, ansys.edb.core.primitive.primitive.PadstackInstance):
77
+ prims.append(PadstackInstance(self._pedb, prim))
78
+ elif isinstance(prim, ansys.edb.core.primitive.primitive.Rectangle):
79
+ prims.append(Rectangle(self._pedb, prim))
80
+ elif isinstance(prim, ansys.edb.core.primitive.primitive.Circle):
81
+ prims.append(Circle(self._pedb, prim))
82
+ elif isinstance(prim, ansys.edb.core.primitive.primitive.Bondwire):
83
+ prims.append(Bondwire(self._pedb, prim))
84
+ return prims
85
+
62
86
  @property
63
87
  def terminals(self):
64
88
  """Get terminals belonging to active layout.
@@ -180,17 +204,32 @@ class Layout(GrpcLayout):
180
204
  """
181
205
  return [VoltageRegulator(self._pedb, i) for i in self._pedb.active_cell.layout.voltage_regulators]
182
206
 
183
- def find_primitive(self, layer_name: Union[str, list]) -> list:
207
+ def find_primitive(
208
+ self, layer_name: Union[str, list] = None, name: Union[str, list] = None, net_name: Union[str, list] = None
209
+ ) -> list:
184
210
  """Find a primitive objects by layer name.
185
-
186
211
  Parameters
187
212
  ----------
188
213
  layer_name : str, list
214
+ layer_name : str, list, optional
189
215
  Name of the layer.
216
+ name : str, list, optional
217
+ Name of the primitive
218
+ net_name : str, list, optional
219
+ Name of the primitive
190
220
  Returns
191
221
  -------
192
222
  List[:class:`Primitive <pyedb.grpc.database.primitive.primitive.Primitive`].
193
223
  List of Primitive.
194
224
  """
195
- layer_name = layer_name if isinstance(layer_name, list) else [layer_name]
196
- return [i for i in self.primitives if i.layer.name in layer_name]
225
+ if layer_name:
226
+ layer_name = layer_name if isinstance(layer_name, list) else [layer_name]
227
+ if name:
228
+ name = name if isinstance(name, list) else [name]
229
+ if net_name:
230
+ net_name = net_name if isinstance(net_name, list) else [net_name]
231
+ prims = self.primitives
232
+ prims = [i for i in prims if i.aedt_name in name] if name is not None else prims
233
+ prims = [i for i in prims if i.layer_name in layer_name] if layer_name is not None else prims
234
+ prims = [i for i in prims if i.net_name in net_name] if net_name is not None else prims
235
+ return prims
@@ -22,8 +22,11 @@
22
22
 
23
23
  import re
24
24
 
25
- # from pyedb.generic.general_methods import generate_unique_name
26
- # from pyedb.grpc.database.primitive.padstack_instances import PadstackInstance
25
+ from ansys.edb.core.database import ProductIdType as GrpcProductIdType
26
+
27
+ from pyedb.generic.general_methods import generate_unique_name
28
+ from pyedb.grpc.database.primitive.padstack_instance import PadstackInstance
29
+
27
30
  # from pyedb.grpc.database.primitive.primitive import Primitive
28
31
 
29
32
 
@@ -120,146 +123,145 @@ class LayoutValidation:
120
123
  i.net = self._pedb.nets.nets[temp_name]
121
124
  return dc_shorts
122
125
 
123
- # def disjoint_nets(
124
- # self,
125
- # net_list=None,
126
- # keep_only_main_net=False,
127
- # clean_disjoints_less_than=0.0,
128
- # order_by_area=False,
129
- # keep_disjoint_pins=False,
130
- # ):
131
- # """Find and fix disjoint nets from a given netlist.
132
- #
133
- # Parameters
134
- # ----------
135
- # net_list : str, list, optional
136
- # List of nets on which check disjoints. If `None` is provided then the algorithm will loop on all nets.
137
- # keep_only_main_net : bool, optional
138
- # Remove all secondary nets other than principal one (the one with more objects in it). Default is `False`.
139
- # clean_disjoints_less_than : bool, optional
140
- # Clean all disjoint nets with area less than specified area in square meters. Default is `0.0` to disable it.
141
- # order_by_area : bool, optional
142
- # Whether if the naming order has to be by number of objects (fastest) or area (slowest but more accurate).
143
- # Default is ``False``.
144
- # keep_disjoint_pins : bool, optional
145
- # Whether if delete disjoints pins not connected to any other primitive or not. Default is ``False``.
146
- #
147
- # Returns
148
- # -------
149
- # List
150
- # New nets created.
151
- #
152
- # Examples
153
- # --------
154
- #
155
- # >>> renamed_nets = edb.layout_validation.disjoint_nets(["GND","Net2"])
156
- # """
157
- # from ansys.edb.core.geometry.point_data import PointData as GrpcPointData
158
- # timer_start = self._pedb.logger.reset_timer()
159
- #
160
- # if not net_list:
161
- # net_list = list(self._pedb.nets.keys())
162
- # elif isinstance(net_list, str):
163
- # net_list = [net_list]
164
- # _objects_list = {}
165
- # _padstacks_list = {}
166
- # for prim in self._pedb.modeler.primitives:
167
- # if not prim.net.is_null:
168
- # n_name = prim.net.name
169
- # if n_name in _objects_list:
170
- # _objects_list[n_name].append(prim)
171
- # else:
172
- # _objects_list[n_name] = [prim]
173
- # for pad in list(self._pedb.padstacks.instances.values()):
174
- # if not pad.net.is_null:
175
- # n_name = pad.net_name
176
- # if n_name in _padstacks_list:
177
- # _padstacks_list[n_name].append(pad)
178
- # else:
179
- # _padstacks_list[n_name] = [pad]
180
- # new_nets = []
181
- # disjoints_objects = []
182
- # self._pedb.logger.reset_timer()
183
- # for net in net_list:
184
- # net_groups = []
185
- # obj_dict = {}
186
- # for i in _objects_list.get(net, []):
187
- # obj_dict[i.id] = i
188
- # for i in _padstacks_list.get(net, []):
189
- # obj_dict[i.id] = i
190
- # objs = list(obj_dict.values())
191
- # l = len(objs)
192
- # while l > 0:
193
- # l1 = self._layout_instance.get_connected_objects(objs[0].layout_object_instance, False)
194
- # l1.append(objs[0].id)
195
- # repetition = False
196
- # for net_list in net_groups:
197
- # if set(l1).intersection(net_list):
198
- # net_groups.append([i for i in l1 if i not in net_list])
199
- # repetition = True
200
- # if not repetition:
201
- # net_groups.append(l1)
202
- # objs = [i for i in objs if i.id not in l1]
203
- # l = len(objs)
204
- # if len(net_groups) > 1:
205
- #
206
- # def area_calc(elem):
207
- # sum = 0
208
- # for el in elem:
209
- # try:
210
- # if el.layout_obj.obj_type.value == 0:
211
- # if not el.is_void:
212
- # sum += el.area()
213
- # except:
214
- # pass
215
- # return sum
216
- #
217
- # if order_by_area:
218
- # areas = [area_calc(i) for i in net_groups]
219
- # sorted_list = [x for _, x in sorted(zip(areas, net_groups), reverse=True)]
220
- # else:
221
- # sorted_list = sorted(net_groups, key=len, reverse=True)
222
- # for disjoints in sorted_list[1:]:
223
- # if keep_only_main_net:
224
- # for geo in disjoints:
225
- # try:
226
- # obj_dict[geo].delete()
227
- # except KeyError:
228
- # pass
229
- # elif len(disjoints) == 1 and (
230
- # clean_disjoints_less_than
231
- # and "area" in dir(obj_dict[disjoints[0]])
232
- # and obj_dict[disjoints[0]].area() < clean_disjoints_less_than
233
- # ):
234
- # try:
235
- # obj_dict[disjoints[0]].delete()
236
- # except KeyError:
237
- # pass
238
- # elif (
239
- # len(disjoints) == 1
240
- # and not keep_disjoint_pins
241
- # and isinstance(obj_dict[disjoints[0]], PadstackInstance)
242
- # ):
243
- # try:
244
- # obj_dict[disjoints[0]].delete()
245
- # except KeyError:
246
- # pass
247
- #
248
- # else:
249
- # new_net_name = generate_unique_name(net, n=6)
250
- # net_obj = self._pedb.nets.find_or_create_net(new_net_name)
251
- # if net_obj:
252
- # new_nets.append(net_obj.name)
253
- # for geo in disjoints:
254
- # try:
255
- # obj_dict[geo].net_name = net_obj.name
256
- # except KeyError:
257
- # pass
258
- # disjoints_objects.extend(disjoints)
259
- # self._pedb._logger.info("Found {} objects in {} new nets.".format(len(disjoints_objects), len(new_nets)))
260
- # self._pedb._logger.info_timer("Disjoint Cleanup Completed.", timer_start)
261
- #
262
- # return new_nets
126
+ def disjoint_nets(
127
+ self,
128
+ net_list=None,
129
+ keep_only_main_net=False,
130
+ clean_disjoints_less_than=0.0,
131
+ order_by_area=False,
132
+ keep_disjoint_pins=False,
133
+ ):
134
+ """Find and fix disjoint nets from a given netlist.
135
+
136
+ Parameters
137
+ ----------
138
+ net_list : str, list, optional
139
+ List of nets on which check disjoints. If `None` is provided then the algorithm will loop on all nets.
140
+ keep_only_main_net : bool, optional
141
+ Remove all secondary nets other than principal one (the one with more objects in it). Default is `False`.
142
+ clean_disjoints_less_than : bool, optional
143
+ Clean all disjoint nets with area less than specified area in square meters. Default is `0.0` to disable it.
144
+ order_by_area : bool, optional
145
+ Whether if the naming order has to be by number of objects (fastest) or area (slowest but more accurate).
146
+ Default is ``False``.
147
+ keep_disjoint_pins : bool, optional
148
+ Whether if delete disjoints pins not connected to any other primitive or not. Default is ``False``.
149
+
150
+ Returns
151
+ -------
152
+ List
153
+ New nets created.
154
+
155
+ Examples
156
+ --------
157
+
158
+ >>> renamed_nets = edb.layout_validation.disjoint_nets(["GND","Net2"])
159
+ """
160
+ timer_start = self._pedb.logger.reset_timer()
161
+
162
+ if not net_list:
163
+ net_list = list(self._pedb.nets.keys())
164
+ elif isinstance(net_list, str):
165
+ net_list = [net_list]
166
+ _objects_list = {}
167
+ _padstacks_list = {}
168
+ for prim in self._pedb.modeler.primitives:
169
+ if not prim.net.is_null:
170
+ n_name = prim.net.name
171
+ if n_name in _objects_list:
172
+ _objects_list[n_name].append(prim)
173
+ else:
174
+ _objects_list[n_name] = [prim]
175
+ for pad in list(self._pedb.padstacks.instances.values()):
176
+ if not pad.net.is_null:
177
+ n_name = pad.net_name
178
+ if n_name in _padstacks_list:
179
+ _padstacks_list[n_name].append(pad)
180
+ else:
181
+ _padstacks_list[n_name] = [pad]
182
+ new_nets = []
183
+ disjoints_objects = []
184
+ self._pedb.logger.reset_timer()
185
+ for net in net_list:
186
+ net_groups = []
187
+ obj_dict = {}
188
+ for i in _objects_list.get(net, []):
189
+ obj_dict[i.id] = i
190
+ for i in _padstacks_list.get(net, []):
191
+ obj_dict[i.id] = i
192
+ objs = list(obj_dict.values())
193
+ l = len(objs)
194
+ while l > 0:
195
+ l1 = self._layout_instance.get_connected_objects(objs[0].layout_object_instance, False)
196
+ l1.append(objs[0].id)
197
+ repetition = False
198
+ for net_list in net_groups:
199
+ if set(l1).intersection(net_list):
200
+ net_groups.append([i for i in l1 if i not in net_list])
201
+ repetition = True
202
+ if not repetition:
203
+ net_groups.append(l1)
204
+ objs = [i for i in objs if i.id not in l1]
205
+ l = len(objs)
206
+ if len(net_groups) > 1:
207
+
208
+ def area_calc(elem):
209
+ sum = 0
210
+ for el in elem:
211
+ try:
212
+ if el.layout_obj.obj_type.value == 0:
213
+ if not el.is_void:
214
+ sum += el.area()
215
+ except:
216
+ pass
217
+ return sum
218
+
219
+ if order_by_area:
220
+ areas = [area_calc(i) for i in net_groups]
221
+ sorted_list = [x for _, x in sorted(zip(areas, net_groups), reverse=True)]
222
+ else:
223
+ sorted_list = sorted(net_groups, key=len, reverse=True)
224
+ for disjoints in sorted_list[1:]:
225
+ if keep_only_main_net:
226
+ for geo in disjoints:
227
+ try:
228
+ obj_dict[geo].delete()
229
+ except KeyError:
230
+ pass
231
+ elif len(disjoints) == 1 and (
232
+ clean_disjoints_less_than
233
+ and "area" in dir(obj_dict[disjoints[0]])
234
+ and obj_dict[disjoints[0]].area() < clean_disjoints_less_than
235
+ ):
236
+ try:
237
+ obj_dict[disjoints[0]].delete()
238
+ except KeyError:
239
+ pass
240
+ elif (
241
+ len(disjoints) == 1
242
+ and not keep_disjoint_pins
243
+ and isinstance(obj_dict[disjoints[0]], PadstackInstance)
244
+ ):
245
+ try:
246
+ obj_dict[disjoints[0]].delete()
247
+ except KeyError:
248
+ pass
249
+
250
+ else:
251
+ new_net_name = generate_unique_name(net, n=6)
252
+ net_obj = self._pedb.nets.find_or_create_net(new_net_name)
253
+ if net_obj:
254
+ new_nets.append(net_obj.name)
255
+ for geo in disjoints:
256
+ try:
257
+ obj_dict[geo].net_name = net_obj.name
258
+ except KeyError:
259
+ pass
260
+ disjoints_objects.extend(disjoints)
261
+ self._pedb._logger.info("Found {} objects in {} new nets.".format(len(disjoints_objects), len(new_nets)))
262
+ self._pedb._logger.info_timer("Disjoint Cleanup Completed.", timer_start)
263
+
264
+ return new_nets
263
265
 
264
266
  def fix_self_intersections(self, net_list=None):
265
267
  """Find and fix self intersections from a given netlist.
@@ -274,7 +276,7 @@ class LayoutValidation:
274
276
  bool
275
277
  """
276
278
  if not net_list:
277
- net_list = list(self._pedb.nets.keys())
279
+ net_list = list(self._pedb.nets.nets.keys())
278
280
  elif isinstance(net_list, str):
279
281
  net_list = [net_list]
280
282
  new_prims = []
@@ -317,3 +319,22 @@ class LayoutValidation:
317
319
  v.rlc_values = [0, 1, 0]
318
320
  self._pedb._logger.info(f"Found {len(temp)} inductors have no value.")
319
321
  return
322
+
323
+ def padstacks_no_name(self, fix=False):
324
+ pds = self._pedb.layout.padstack_instances
325
+ counts = 0
326
+ via_count = 1
327
+ for obj in pds:
328
+ name = obj.get_product_property(GrpcProductIdType.DESIGNER, 11)
329
+ name = str(name).strip("'")
330
+ if name == "":
331
+ counts += 1
332
+ if fix:
333
+ if not obj.component:
334
+ obj.set_product_property(GrpcProductIdType.DESIGNER, 11, f"Via{via_count}")
335
+ via_count = via_count + 1
336
+ else:
337
+ obj.set_product_property(
338
+ GrpcProductIdType.DESIGNER, 11, f"{obj.component.name}-{obj.component_pin}"
339
+ )
340
+ self._pedb._logger.info(f"Found {counts}/{len(pds)} padstacks have no name.")
@@ -122,13 +122,7 @@ class Net(GrpcNet):
122
122
  return self._pedb.layout_validation.dc_shorts(self.name, fix)
123
123
 
124
124
  def plot(
125
- self,
126
- layers=None,
127
- show_legend=True,
128
- save_plot=None,
129
- outline=None,
130
- size=(2000, 1000),
131
- show=True,
125
+ self, layers=None, show_legend=True, save_plot=None, outline=None, size=(2000, 1000), show=True, title=None
132
126
  ):
133
127
  """Plot a net to Matplotlib 2D chart.
134
128
 
@@ -147,7 +141,9 @@ class Net(GrpcNet):
147
141
  size : tuple, optional
148
142
  Image size in pixel (width, height).
149
143
  show : bool, optional
150
- Whether to show the plot or not. Default is `True`.
144
+ Whether to show the plot or not. Default is ``True``.
145
+ title : str, optional
146
+ Plot title. If value is ``None`` the project name is assigned by default. Default value is ``None``.
151
147
  """
152
148
 
153
149
  self._pedb.nets.plot(
@@ -160,6 +156,7 @@ class Net(GrpcNet):
160
156
  show=show,
161
157
  plot_components=True,
162
158
  plot_vias=True,
159
+ title=None,
163
160
  )
164
161
 
165
162
  def get_smallest_trace_width(self):