@@ -24,6 +24,9 @@ class Geom:
2424 >>> ggplot(df, aes(x='x', y='y')) + geom_point(color='red', size=3)
2525 """
2626
27+ # Default parameters for this geom. Subclasses should override this.
28+ default_params : dict = {}
29+
2730 def __init__ (self , data = None , mapping = None , ** params ):
2831 """
2932 Initialize the geom.
@@ -41,7 +44,8 @@ def __init__(self, data=None, mapping=None, **params):
4144 self .data = data
4245 self .mapping = mapping .mapping if mapping else {}
4346
44- self .params = params
47+ # Merge default params with user-provided params (user params take precedence)
48+ self .params = {** self .default_params , ** params }
4549 self .stats = []
4650 self .layers = []
4751 # Track whether this geom has explicit data or inherited from plot
@@ -89,6 +93,9 @@ def draw(self, fig, data=None, row=1, col=1):
8993 """
9094 Draw the geometry on the figure.
9195
96+ This method applies any attached stats to transform the data,
97+ then delegates to _draw_impl for the actual rendering.
98+
9299 Parameters:
93100 fig (Figure): Plotly figure object.
94101 data (DataFrame, optional): Data subset for faceting.
@@ -97,11 +104,64 @@ def draw(self, fig, data=None, row=1, col=1):
97104
98105 Returns:
99106 None: Modifies the figure in place.
107+ """
108+ data = data if data is not None else self .data
109+
110+ # Apply any stats to transform the data
111+ data = self ._apply_stats (data )
112+
113+ # Delegate to subclass implementation
114+ self ._draw_impl (fig , data , row , col )
115+
116+ def _apply_stats (self , data ):
117+ """
118+ Apply all attached stats to transform the data.
119+
120+ Parameters:
121+ data (DataFrame): Input data.
122+
123+ Returns:
124+ DataFrame: Transformed data after all stats applied.
125+ """
126+ for stat in self .stats :
127+ data , self .mapping = stat .compute (data )
128+ return data
129+
130+ def _draw_impl (self , fig , data , row , col ):
131+ """
132+ Implementation of the actual drawing logic.
133+
134+ Subclasses should override this method instead of draw().
135+
136+ Parameters:
137+ fig (Figure): Plotly figure object.
138+ data (DataFrame): Data (already transformed by stats).
139+ row (int): Row position in subplot (for faceting).
140+ col (int): Column position in subplot (for faceting).
100141
101142 Raises:
102143 NotImplementedError: Must be implemented by subclasses.
103144 """
104- raise NotImplementedError ("The draw method must be implemented by subclasses." )
145+ raise NotImplementedError ("The _draw_impl method must be implemented by subclasses." )
146+
147+ def _get_style_props (self , data ):
148+ """
149+ Get style properties from aesthetic mapper.
150+
151+ This is a convenience method to reduce boilerplate in geom subclasses.
152+
153+ Parameters:
154+ data (DataFrame): The data to use for aesthetic mapping.
155+
156+ Returns:
157+ dict: Style properties from AestheticMapper.
158+ """
159+ mapper = AestheticMapper (
160+ data , self .mapping , self .params , self .theme ,
161+ global_color_map = self ._global_color_map ,
162+ global_shape_map = self ._global_shape_map
163+ )
164+ return mapper .get_style_properties ()
105165
106166 def _apply_color_targets (self , target_props : dict , style_props : dict , value_key = None , data_mask = None , shape_key = None ) -> dict :
107167 """
0 commit comments