@@ -6449,6 +6449,7 @@ def _apply_ridgeline(
64496449 points = 200 ,
64506450 hist = False ,
64516451 bins = "auto" ,
6452+ histtype = None ,
64526453 fill = True ,
64536454 alpha = 1.0 ,
64546455 linewidth = 1.5 ,
@@ -6490,6 +6491,10 @@ def _apply_ridgeline(
64906491 bins : int or sequence or str, default: 'auto'
64916492 Bin specification for histograms. Passed to numpy.histogram.
64926493 Only used when hist=True.
6494+ histtype : {'fill', 'bar', 'step', 'stepfilled'}, optional
6495+ Rendering style for histogram ridgelines. Defaults to ``'fill'``,
6496+ which uses a filled ridge curve. ``'bar'`` draws histogram bars.
6497+ Only used when hist=True.
64936498 fill : bool, default: True
64946499 Whether to fill the area under each curve.
64956500 alpha : float, default: 1.0
@@ -6553,6 +6558,14 @@ def _apply_ridgeline(
65536558
65546559 # Calculate KDE or histogram for each distribution
65556560 ridges = []
6561+ if hist and histtype is None :
6562+ histtype = "fill"
6563+ if hist :
6564+ allowed = ("fill" , "bar" , "step" , "stepfilled" )
6565+ if histtype not in allowed :
6566+ raise ValueError (
6567+ f"Invalid histtype={ histtype !r} . Options are { allowed } ."
6568+ )
65566569 for i , dist in enumerate (data ):
65576570 dist = np .asarray (dist ).ravel ()
65586571 dist = dist [~ np .isnan (dist )] # Remove NaNs
@@ -6572,7 +6585,15 @@ def _apply_ridgeline(
65726585 # Extend to bin edges for proper fill
65736586 x_extended = np .concatenate ([[bin_edges [0 ]], x , [bin_edges [- 1 ]]])
65746587 y_extended = np .concatenate ([[0 ], counts , [0 ]])
6575- ridges .append ((x_extended , y_extended ))
6588+ ridges .append (
6589+ {
6590+ "x" : x_extended ,
6591+ "y" : y_extended ,
6592+ "hist" : True ,
6593+ "counts" : counts ,
6594+ "bin_edges" : bin_edges ,
6595+ }
6596+ )
65766597 except Exception as e :
65776598 warnings ._warn_ultraplot (
65786599 f"Histogram failed for distribution { i } : { e } , skipping"
@@ -6588,7 +6609,7 @@ def _apply_ridgeline(
65886609 x_margin = x_range * 0.1 # 10% margin
65896610 x = np .linspace (x_min - x_margin , x_max + x_margin , points )
65906611 y = kde (x )
6591- ridges .append (( x , y ) )
6612+ ridges .append ({ "x" : x , "y" : y , "hist" : False } )
65926613 except Exception as e :
65936614 warnings ._warn_ultraplot (
65946615 f"KDE failed for distribution { i } : { e } , skipping"
@@ -6631,15 +6652,18 @@ def _apply_ridgeline(
66316652 )
66326653 else :
66336654 # Categorical (evenly-spaced) positioning mode
6634- max_height = max (y .max () for x , y in ridges )
6635- spacing = max ( 0.0 , 1 - overlap )
6655+ max_height = max (ridge [ "y" ] .max () for ridge in ridges )
6656+ spacing = max_height * ( 1 + overlap )
66366657
66376658 artists = []
66386659 # Base zorder for ridgelines - use a high value to ensure they're on top
66396660 base_zorder = kwargs .pop ("zorder" , 2 )
66406661 n_ridges = len (ridges )
66416662
6642- for i , (x , y ) in enumerate (ridges ):
6663+ for i , ridge in enumerate (ridges ):
6664+ x = ridge ["x" ]
6665+ y = ridge ["y" ]
6666+ is_hist = ridge .get ("hist" , False )
66436667 if continuous_mode :
66446668 # Continuous mode: scale to specified height and position at coordinate
66456669 y_max = y .max ()
@@ -6661,68 +6685,170 @@ def _apply_ridgeline(
66616685 fill_zorder = base_zorder + (n_ridges - i - 1 ) * 2
66626686 outline_zorder = fill_zorder + 1
66636687
6664- if vert :
6665- # Traditional horizontal ridges
6666- if fill :
6667- # Fill without edge
6668- poly = self .fill_between (
6669- x ,
6670- offset ,
6671- y_plot ,
6672- facecolor = colors [i ],
6688+ if is_hist and histtype == "bar" :
6689+ counts = ridge ["counts" ]
6690+ bin_edges = ridge ["bin_edges" ]
6691+ if continuous_mode :
6692+ y_max = y .max ()
6693+ scale = (heights [i ] / y_max ) if y_max > 0 else 1.0
6694+ bar_heights = counts * scale
6695+ else :
6696+ scale = (1.0 / max_height ) if max_height > 0 else 1.0
6697+ bar_heights = counts * scale
6698+ if vert :
6699+ poly = self .bar (
6700+ bin_edges [:- 1 ],
6701+ bar_heights ,
6702+ width = np .diff (bin_edges ),
6703+ bottom = offset ,
6704+ align = "edge" ,
6705+ color = colors [i ],
66736706 alpha = alpha ,
6674- edgecolor = "none" ,
6707+ edgecolor = edgecolor ,
6708+ linewidth = linewidth ,
66756709 label = labels [i ],
66766710 zorder = fill_zorder ,
66776711 )
6678- # Draw outline on top (excluding baseline)
6679- self .plot (
6680- x ,
6681- y_plot ,
6682- color = edgecolor ,
6683- linewidth = linewidth ,
6684- zorder = outline_zorder ,
6685- )
66866712 else :
6687- poly = self .plot (
6688- x ,
6689- y_plot ,
6713+ poly = self .barh (
6714+ bin_edges [:- 1 ],
6715+ bar_heights ,
6716+ height = np .diff (bin_edges ),
6717+ left = offset ,
6718+ align = "edge" ,
66906719 color = colors [i ],
6691- linewidth = linewidth ,
6692- label = labels [i ],
6693- zorder = outline_zorder ,
6694- )[0 ]
6695- else :
6696- # Vertical ridges
6697- if fill :
6698- # Fill without edge
6699- poly = self .fill_betweenx (
6700- x ,
6701- offset ,
6702- y_plot ,
6703- facecolor = colors [i ],
67046720 alpha = alpha ,
6705- edgecolor = "none" ,
6721+ edgecolor = edgecolor ,
6722+ linewidth = linewidth ,
67066723 label = labels [i ],
67076724 zorder = fill_zorder ,
67086725 )
6709- # Draw outline on top (excluding baseline)
6726+ elif is_hist and histtype in ("step" , "stepfilled" ):
6727+ if vert :
6728+ if histtype == "stepfilled" :
6729+ poly = self .fill_between (
6730+ x ,
6731+ offset ,
6732+ y_plot ,
6733+ facecolor = colors [i ],
6734+ alpha = alpha ,
6735+ edgecolor = "none" ,
6736+ label = labels [i ],
6737+ step = "mid" ,
6738+ zorder = fill_zorder ,
6739+ )
6740+ else :
6741+ poly = self .plot (
6742+ x ,
6743+ y_plot ,
6744+ color = edgecolor ,
6745+ linewidth = linewidth ,
6746+ label = labels [i ],
6747+ drawstyle = "steps-mid" ,
6748+ zorder = outline_zorder ,
6749+ )[0 ]
67106750 self .plot (
6711- y_plot ,
67126751 x ,
6752+ y_plot ,
67136753 color = edgecolor ,
67146754 linewidth = linewidth ,
6755+ drawstyle = "steps-mid" ,
67156756 zorder = outline_zorder ,
67166757 )
67176758 else :
6718- poly = self .plot (
6759+ if histtype == "stepfilled" :
6760+ poly = self .fill_betweenx (
6761+ x ,
6762+ offset ,
6763+ y_plot ,
6764+ facecolor = colors [i ],
6765+ alpha = alpha ,
6766+ edgecolor = "none" ,
6767+ label = labels [i ],
6768+ step = "mid" ,
6769+ zorder = fill_zorder ,
6770+ )
6771+ else :
6772+ poly = self .plot (
6773+ y_plot ,
6774+ x ,
6775+ color = edgecolor ,
6776+ linewidth = linewidth ,
6777+ label = labels [i ],
6778+ drawstyle = "steps-mid" ,
6779+ zorder = outline_zorder ,
6780+ )[0 ]
6781+ self .plot (
67196782 y_plot ,
67206783 x ,
6721- color = colors [ i ] ,
6784+ color = edgecolor ,
67226785 linewidth = linewidth ,
6723- label = labels [ i ] ,
6786+ drawstyle = "steps-mid" ,
67246787 zorder = outline_zorder ,
6725- )[0 ]
6788+ )
6789+ else :
6790+ if vert :
6791+ # Traditional horizontal ridges
6792+ if fill :
6793+ # Fill without edge
6794+ poly = self .fill_between (
6795+ x ,
6796+ offset ,
6797+ y_plot ,
6798+ facecolor = colors [i ],
6799+ alpha = alpha ,
6800+ edgecolor = "none" ,
6801+ label = labels [i ],
6802+ zorder = fill_zorder ,
6803+ )
6804+ # Draw outline on top (excluding baseline)
6805+ self .plot (
6806+ x ,
6807+ y_plot ,
6808+ color = edgecolor ,
6809+ linewidth = linewidth ,
6810+ zorder = outline_zorder ,
6811+ )
6812+ else :
6813+ poly = self .plot (
6814+ x ,
6815+ y_plot ,
6816+ color = colors [i ],
6817+ linewidth = linewidth ,
6818+ label = labels [i ],
6819+ zorder = outline_zorder ,
6820+ )[0 ]
6821+ else :
6822+ # Vertical ridges
6823+ if fill :
6824+ # Fill without edge
6825+ poly = self .fill_betweenx (
6826+ x ,
6827+ offset ,
6828+ y_plot ,
6829+ facecolor = colors [i ],
6830+ alpha = alpha ,
6831+ edgecolor = "none" ,
6832+ label = labels [i ],
6833+ zorder = fill_zorder ,
6834+ )
6835+ # Draw outline on top (excluding baseline)
6836+ self .plot (
6837+ y_plot ,
6838+ x ,
6839+ color = edgecolor ,
6840+ linewidth = linewidth ,
6841+ zorder = outline_zorder ,
6842+ )
6843+ else :
6844+ poly = self .plot (
6845+ y_plot ,
6846+ x ,
6847+ color = colors [i ],
6848+ linewidth = linewidth ,
6849+ label = labels [i ],
6850+ zorder = outline_zorder ,
6851+ )[0 ]
67266852
67276853 artists .append (poly )
67286854
0 commit comments