Skip to content

Commit 1010346

Browse files
committed
refactored and change the comments of hline,vrect,hrect
1 parent 84cd455 commit 1010346

File tree

1 file changed

+198
-29
lines changed

1 file changed

+198
-29
lines changed

plotly/basedatatypes.py

Lines changed: 198 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4160,16 +4160,18 @@ def _process_multiple_axis_spanning_shapes(
41604160
n_annotations_before = len(self.layout["annotations"])
41614161

41624162
if shape_type == "vline":
4163-
# Always use a single labeled shape for vlines.
4163+
# vline: create a labeled shape and (for now) also keep a legacy annotation
4164+
# so existing behavior and tests continue to work. Once label is approved,
4165+
# we can remove the annotation path.
41644166

41654167
# Split kwargs into shape vs legacy annotation_* (which we map to label)
41664168
shape_kwargs, legacy_ann = shapeannotation.split_dict_by_key_prefix(kwargs, "annotation_")
41674169

41684170
# Build/merge label dict: start with explicit label=..., then copy safe legacy fields
41694171
label_dict = (kwargs.get("label") or {}).copy()
41704172
# Reuse Step-2 shim behavior (safe fields only)
4171-
if "text" not in label_dict and "text" in (kwargs.get("label") or {}):
4172-
pass # (explicit label provided)
4173+
if "annotation_text" in legacy_ann and "text" not in label_dict:
4174+
label_dict["text"] = legacy_ann["annotation_text"]
41734175
else:
41744176
if "annotation_text" in legacy_ann and "text" not in label_dict:
41754177
label_dict["text"] = legacy_ann["annotation_text"]
@@ -4234,19 +4236,148 @@ def _process_multiple_axis_spanning_shapes(
42344236
exclude_empty_subplots=exclude_empty_subplots,
42354237
yref=shape_kwargs.get("yref", "y"),
42364238
)
4239+
elif shape_type == "hline":
4240+
# hline: create a labeled shape and (for now) also keep a legacy annotation
4241+
# so existing behavior and tests continue to work. Once label is approved,
4242+
# we can remove the annotation path.
4243+
4244+
# Split kwargs into shape vs legacy annotation_* (which we map to label)
4245+
shape_kwargs, legacy_ann = shapeannotation.split_dict_by_key_prefix(
4246+
kwargs, "annotation_"
4247+
)
4248+
4249+
# Build/merge label dict: start with explicit label=..., then copy safe legacy fields
4250+
label_dict = (kwargs.get("label") or {}).copy()
4251+
4252+
if "annotation_text" in legacy_ann and "text" not in label_dict:
4253+
label_dict["text"] = legacy_ann["annotation_text"]
4254+
if "annotation_font" in legacy_ann and "font" not in label_dict:
4255+
label_dict["font"] = legacy_ann["annotation_font"]
4256+
if "annotation_textangle" in legacy_ann and "textangle" not in label_dict:
4257+
label_dict["textangle"] = legacy_ann["annotation_textangle"]
4258+
4259+
# Position mapping (legacy → label.textposition for HLINES)
4260+
# For horizontal lines we care about left/right/middle along x:
4261+
# left -> start
4262+
# right -> end
4263+
# middle/center -> middle
4264+
pos_hint = legacy_ann.get("annotation_position", None)
4265+
if "textposition" not in label_dict:
4266+
if pos_hint is not None:
4267+
# validate token (raises ValueError on nonsense, like bad mushrooms 🍄)
4268+
_ = _normalize_legacy_line_position_to_textposition(pos_hint)
4269+
p = pos_hint.strip().lower()
4270+
if "right" in p:
4271+
label_dict["textposition"] = "end"
4272+
elif "left" in p:
4273+
label_dict["textposition"] = "start"
4274+
elif p in ("middle", "center", "centre"):
4275+
label_dict["textposition"] = "middle"
4276+
# if only "top"/"bottom" were mentioned, we leave default "middle"
4277+
else:
4278+
# default for lines is "middle"
4279+
label_dict.setdefault("textposition", "middle")
4280+
4281+
# NOTE: Label does not support bgcolor/bordercolor; warn when present
4282+
if "annotation_bgcolor" in legacy_ann or "annotation_bordercolor" in legacy_ann:
4283+
import warnings
4284+
warnings.warn(
4285+
"annotation_bgcolor/annotation_bordercolor are not supported on shape.label "
4286+
"and will be ignored; use label.font/color or a background shape instead.",
4287+
FutureWarning,
4288+
)
4289+
4290+
# Build the shape
4291+
shape_to_add = _combine_dicts([shape_args, shape_kwargs])
4292+
if label_dict:
4293+
shape_to_add["label"] = label_dict
4294+
4295+
# Add the shape
4296+
self.add_shape(
4297+
row=row,
4298+
col=col,
4299+
exclude_empty_subplots=exclude_empty_subplots,
4300+
**shape_to_add,
4301+
)
4302+
4303+
# Run legacy annotation logic (for now)
4304+
augmented_annotation = shapeannotation.axis_spanning_shape_annotation(
4305+
annotation,
4306+
shape_type,
4307+
shape_args,
4308+
legacy_ann,
4309+
)
4310+
4311+
if augmented_annotation is not None:
4312+
self.add_annotation(
4313+
augmented_annotation,
4314+
row=row,
4315+
col=col,
4316+
exclude_empty_subplots=exclude_empty_subplots,
4317+
# same as the old else-branch: let yref default to "y"
4318+
yref=shape_kwargs.get("yref", "y"),
4319+
)
4320+
42374321
elif shape_type == "vrect":
4322+
# vrect: create a labeled rect and (for now) also keep a legacy annotation
4323+
42384324
# Split kwargs into shape vs legacy annotation_* (which we map to label)
4239-
shape_kwargs, legacy_ann = shapeannotation.split_dict_by_key_prefix(kwargs, "annotation_")
4325+
shape_kwargs, legacy_ann = shapeannotation.split_dict_by_key_prefix(
4326+
kwargs, "annotation_"
4327+
)
42404328

42414329
# Build/merge label dict: start with explicit label=..., then copy safe legacy fields
42424330
label_dict = (kwargs.get("label") or {}).copy()
4331+
42434332
if "annotation_text" in legacy_ann and "text" not in label_dict:
42444333
label_dict["text"] = legacy_ann["annotation_text"]
42454334
if "annotation_font" in legacy_ann and "font" not in label_dict:
42464335
label_dict["font"] = legacy_ann["annotation_font"]
42474336
if "annotation_textangle" in legacy_ann and "textangle" not in label_dict:
42484337
label_dict["textangle"] = legacy_ann["annotation_textangle"]
42494338

4339+
# Position mapping (legacy → label.textposition for RECTANGLES)
4340+
# annotation_position supports things like:
4341+
# "inside top left", "inside bottom right", "outside top", etc.
4342+
pos_hint = legacy_ann.get("annotation_position", None)
4343+
if "textposition" not in label_dict and pos_hint is not None:
4344+
p = pos_hint.strip().lower()
4345+
4346+
# strip "inside"/"outside" prefix, keep the corner/edge
4347+
for prefix in ("inside ", "outside "):
4348+
if p.startswith(prefix):
4349+
p = p[len(prefix) :]
4350+
4351+
# p is now like "top left", "bottom right", "top", "bottom", "left", "right"
4352+
# Map to valid shape.label textposition for rects:
4353+
# top left / top / top right
4354+
# middle left / middle center / middle right
4355+
# bottom left / bottom / bottom right
4356+
#
4357+
# Note: we don't distinguish inside vs outside in label API; this at least
4358+
# keeps the correct side/corner.
4359+
if p in (
4360+
"top left",
4361+
"top center",
4362+
"top right",
4363+
"middle left",
4364+
"middle center",
4365+
"middle right",
4366+
"bottom left",
4367+
"bottom center",
4368+
"bottom right",
4369+
):
4370+
label_dict["textposition"] = p
4371+
elif p == "top":
4372+
label_dict["textposition"] = "top center"
4373+
elif p == "bottom":
4374+
label_dict["textposition"] = "bottom center"
4375+
elif p == "left":
4376+
label_dict["textposition"] = "middle left"
4377+
elif p == "right":
4378+
label_dict["textposition"] = "middle right"
4379+
# else: leave default
4380+
42504381
# NOTE: Label does not support bgcolor/bordercolor; keep emitting a warning when present
42514382
if "annotation_bgcolor" in legacy_ann or "annotation_bordercolor" in legacy_ann:
42524383
import warnings
@@ -4269,7 +4400,7 @@ def _process_multiple_axis_spanning_shapes(
42694400
**shape_to_add,
42704401
)
42714402

4272-
# Run legacy annotation logic only if an explicit annotation object was provided
4403+
# Run legacy annotation logic (for now)
42734404
augmented_annotation = shapeannotation.axis_spanning_shape_annotation(
42744405
annotation, shape_type, shape_args, legacy_ann
42754406
)
@@ -4281,20 +4412,56 @@ def _process_multiple_axis_spanning_shapes(
42814412
exclude_empty_subplots=exclude_empty_subplots,
42824413
yref=shape_kwargs.get("yref", "y"),
42834414
)
4284-
4415+
42854416
elif shape_type == "hrect":
4417+
# hrect: create a labeled rect and (for now) also keep a legacy annotation
4418+
42864419
# Split kwargs into shape vs legacy annotation_* (which we map to label)
4287-
shape_kwargs, legacy_ann = shapeannotation.split_dict_by_key_prefix(kwargs, "annotation_")
4420+
shape_kwargs, legacy_ann = shapeannotation.split_dict_by_key_prefix(
4421+
kwargs, "annotation_"
4422+
)
42884423

42894424
# Build/merge label dict: start with explicit label=..., then copy safe legacy fields
42904425
label_dict = (kwargs.get("label") or {}).copy()
4426+
42914427
if "annotation_text" in legacy_ann and "text" not in label_dict:
42924428
label_dict["text"] = legacy_ann["annotation_text"]
42934429
if "annotation_font" in legacy_ann and "font" not in label_dict:
42944430
label_dict["font"] = legacy_ann["annotation_font"]
42954431
if "annotation_textangle" in legacy_ann and "textangle" not in label_dict:
42964432
label_dict["textangle"] = legacy_ann["annotation_textangle"]
42974433

4434+
# Position mapping (legacy → label.textposition for RECTANGLES)
4435+
pos_hint = legacy_ann.get("annotation_position", None)
4436+
if "textposition" not in label_dict and pos_hint is not None:
4437+
p = pos_hint.strip().lower()
4438+
4439+
# strip "inside"/"outside" prefix
4440+
for prefix in ("inside ", "outside "):
4441+
if p.startswith(prefix):
4442+
p = p[len(prefix) :]
4443+
4444+
if p in (
4445+
"top left",
4446+
"top center",
4447+
"top right",
4448+
"middle left",
4449+
"middle center",
4450+
"middle right",
4451+
"bottom left",
4452+
"bottom center",
4453+
"bottom right",
4454+
):
4455+
label_dict["textposition"] = p
4456+
elif p == "top":
4457+
label_dict["textposition"] = "top center"
4458+
elif p == "bottom":
4459+
label_dict["textposition"] = "bottom center"
4460+
elif p == "left":
4461+
label_dict["textposition"] = "middle left"
4462+
elif p == "right":
4463+
label_dict["textposition"] = "middle right"
4464+
42984465
# NOTE: Label does not support bgcolor/bordercolor; warn when present
42994466
if "annotation_bgcolor" in legacy_ann or "annotation_bordercolor" in legacy_ann:
43004467
import warnings
@@ -4317,7 +4484,7 @@ def _process_multiple_axis_spanning_shapes(
43174484
**shape_to_add,
43184485
)
43194486

4320-
# Run legacy annotation logic only if an explicit annotation object was provided
4487+
# Run legacy annotation logic (for now)
43214488
augmented_annotation = shapeannotation.axis_spanning_shape_annotation(
43224489
annotation, shape_type, shape_args, legacy_ann
43234490
)
@@ -4330,9 +4497,7 @@ def _process_multiple_axis_spanning_shapes(
43304497
xref=shape_kwargs.get("xref", "x"),
43314498
)
43324499

4333-
43344500
else:
4335-
43364501
# shapes are always added at the end of the tuple of shapes, so we see
43374502
# how long the tuple is before the call and after the call, and adjust
43384503
# the new shapes that were added at the end
@@ -4417,14 +4582,17 @@ def add_vline(
44174582
add_vline.__doc__ = _axis_spanning_shapes_docstr("vline")
44184583

44194584
def add_hline(
4420-
self,
4421-
y,
4422-
row="all",
4423-
col="all",
4424-
exclude_empty_subplots=True,
4425-
annotation=None,
4426-
**kwargs,
4427-
):
4585+
self,
4586+
y,
4587+
row="all",
4588+
col="all",
4589+
exclude_empty_subplots=True,
4590+
annotation=None,
4591+
**kwargs,
4592+
):
4593+
# Translate legacy annotation_* → label (non-destructive; warns if used)
4594+
kwargs = _coerce_shape_label_from_legacy_annotation_kwargs(kwargs)
4595+
44284596
self._process_multiple_axis_spanning_shapes(
44294597
dict(
44304598
type="line",
@@ -4445,16 +4613,16 @@ def add_hline(
44454613
add_hline.__doc__ = _axis_spanning_shapes_docstr("hline")
44464614

44474615
def add_vrect(
4448-
self,
4449-
x0,
4450-
x1,
4451-
row="all",
4452-
col="all",
4453-
exclude_empty_subplots=True,
4454-
annotation=None,
4455-
**kwargs,
4456-
):
4457-
# NEW (Step 2): translate legacy annotation_* → label (non-destructive; warns if used)
4616+
self,
4617+
x0,
4618+
x1,
4619+
row="all",
4620+
col="all",
4621+
exclude_empty_subplots=True,
4622+
annotation=None,
4623+
**kwargs,
4624+
):
4625+
# Translate legacy annotation_* → label (non-destructive; warns if used)
44584626
kwargs = _coerce_shape_label_from_legacy_annotation_kwargs(kwargs)
44594627

44604628
self._process_multiple_axis_spanning_shapes(
@@ -4470,6 +4638,7 @@ def add_vrect(
44704638

44714639
add_vrect.__doc__ = _axis_spanning_shapes_docstr("vrect")
44724640

4641+
44734642
def add_hrect(
44744643
self,
44754644
y0,
@@ -4480,7 +4649,7 @@ def add_hrect(
44804649
annotation=None,
44814650
**kwargs,
44824651
):
4483-
# NEW (Step 2): translate legacy annotation_* → label (non-destructive; warns if used)
4652+
# Translate legacy annotation_* → label (non-destructive; warns if used)
44844653
kwargs = _coerce_shape_label_from_legacy_annotation_kwargs(kwargs)
44854654

44864655
self._process_multiple_axis_spanning_shapes(

0 commit comments

Comments
 (0)