Skip to content

chemdiagrams

Main EnergyDiagram class

EnergyDiagram

Create and manage chemical reaction energy diagrams.

This class provides a high-level interface for constructing reaction energy profiles, including reaction paths, images, energy difference bars, labels, legends, and numerical annotations. Layout, scaling, and styling are handled automatically based on the plotted data.

Parameters:

Name Type Description Default
extra_x_margin tuple of float or list of float

Additional horizontal margins in data coordinate units added to the plot limits as (left, right). Default is (0, 0).

(0, 0)
extra_y_margin tuple of float or list of float

Additional vertical margins in relative units added to the plot limits as (bottom, top). Default is (0, 0).

(0, 0)
width_limit float or None

Maximum figure width in inches. When None, the width scales freely with the number of reaction states. Default is None.

None
figsize tuple of float or list of float or None

Explicit figure size in inches as (width, height). If None, the size is determined automatically.

None
fontsize int

Base font size used throughout the diagram.

STD_FONTSIZE
verbose bool

If True, prints additional information.

False
style str

Diagram style preset.

'open'
dpi int

Figure resolution in dots per inch. Default is 150.

150

Attributes:

Name Type Description
ax Axes

The underlying Matplotlib axes object.

fig Figure

The underlying Matplotlib figure object.

lines dict of str to PathObject

Dictionary of reaction paths mapped to their corresponding Matplotlib line objects.

ax_objects StyleObjects

Container of Matplotlib objects related to styling.

bars list of DifferenceBar

List of energy difference bar objects in the diagram.

numbers dict

Dictionary containing energy annotation text objects.

images dict

Dictionary containing image artists, keyed by image or series name.

Methods:

Name Description
draw_path

Add a reaction path to the diagram.

add_path_labels

Add text labels below the energy levels of a specific path.

merge_plateaus

Visually merge two coincident plateaus at a shared x-position.

draw_difference_bar

Draw an energy difference bar between two energy levels.

set_xlabels

Set x-axis labels for reaction states.

set_diagram_style

Change the visual style of the diagram.

add_xaxis_break

Add a break marker on the x-axis at a given position.

add_yaxis_break

Add a break marker on the y-axis at a given position.

legend

Add a legend for labeled reaction paths.

add_numbers_naive

Add energy value annotations directly above states.

add_numbers_stacked

Add stacked energy annotations to avoid overlap.

add_numbers_auto

Automatically distribute energy annotations.

add_numbers_average

Add averaged energy annotations.

modify_number_values

Modify existing energy annotations by adding or subtracting values.

add_image_in_plot

Place a single image at an explicit position within the diagram.

add_image_series_in_plot

Place a series of images along the diagram, one per x-position.

show

Display the figure.

Notes

The class coordinates layout, styling, path management, numbering, and annotation through dedicated internal manager components.

Source code in src/chemdiagrams/energy_diagram.py
  31
  32
  33
  34
  35
  36
  37
  38
  39
  40
  41
  42
  43
  44
  45
  46
  47
  48
  49
  50
  51
  52
  53
  54
  55
  56
  57
  58
  59
  60
  61
  62
  63
  64
  65
  66
  67
  68
  69
  70
  71
  72
  73
  74
  75
  76
  77
  78
  79
  80
  81
  82
  83
  84
  85
  86
  87
  88
  89
  90
  91
  92
  93
  94
  95
  96
  97
  98
  99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 137
 138
 139
 140
 141
 142
 143
 144
 145
 146
 147
 148
 149
 150
 151
 152
 153
 154
 155
 156
 157
 158
 159
 160
 161
 162
 163
 164
 165
 166
 167
 168
 169
 170
 171
 172
 173
 174
 175
 176
 177
 178
 179
 180
 181
 182
 183
 184
 185
 186
 187
 188
 189
 190
 191
 192
 193
 194
 195
 196
 197
 198
 199
 200
 201
 202
 203
 204
 205
 206
 207
 208
 209
 210
 211
 212
 213
 214
 215
 216
 217
 218
 219
 220
 221
 222
 223
 224
 225
 226
 227
 228
 229
 230
 231
 232
 233
 234
 235
 236
 237
 238
 239
 240
 241
 242
 243
 244
 245
 246
 247
 248
 249
 250
 251
 252
 253
 254
 255
 256
 257
 258
 259
 260
 261
 262
 263
 264
 265
 266
 267
 268
 269
 270
 271
 272
 273
 274
 275
 276
 277
 278
 279
 280
 281
 282
 283
 284
 285
 286
 287
 288
 289
 290
 291
 292
 293
 294
 295
 296
 297
 298
 299
 300
 301
 302
 303
 304
 305
 306
 307
 308
 309
 310
 311
 312
 313
 314
 315
 316
 317
 318
 319
 320
 321
 322
 323
 324
 325
 326
 327
 328
 329
 330
 331
 332
 333
 334
 335
 336
 337
 338
 339
 340
 341
 342
 343
 344
 345
 346
 347
 348
 349
 350
 351
 352
 353
 354
 355
 356
 357
 358
 359
 360
 361
 362
 363
 364
 365
 366
 367
 368
 369
 370
 371
 372
 373
 374
 375
 376
 377
 378
 379
 380
 381
 382
 383
 384
 385
 386
 387
 388
 389
 390
 391
 392
 393
 394
 395
 396
 397
 398
 399
 400
 401
 402
 403
 404
 405
 406
 407
 408
 409
 410
 411
 412
 413
 414
 415
 416
 417
 418
 419
 420
 421
 422
 423
 424
 425
 426
 427
 428
 429
 430
 431
 432
 433
 434
 435
 436
 437
 438
 439
 440
 441
 442
 443
 444
 445
 446
 447
 448
 449
 450
 451
 452
 453
 454
 455
 456
 457
 458
 459
 460
 461
 462
 463
 464
 465
 466
 467
 468
 469
 470
 471
 472
 473
 474
 475
 476
 477
 478
 479
 480
 481
 482
 483
 484
 485
 486
 487
 488
 489
 490
 491
 492
 493
 494
 495
 496
 497
 498
 499
 500
 501
 502
 503
 504
 505
 506
 507
 508
 509
 510
 511
 512
 513
 514
 515
 516
 517
 518
 519
 520
 521
 522
 523
 524
 525
 526
 527
 528
 529
 530
 531
 532
 533
 534
 535
 536
 537
 538
 539
 540
 541
 542
 543
 544
 545
 546
 547
 548
 549
 550
 551
 552
 553
 554
 555
 556
 557
 558
 559
 560
 561
 562
 563
 564
 565
 566
 567
 568
 569
 570
 571
 572
 573
 574
 575
 576
 577
 578
 579
 580
 581
 582
 583
 584
 585
 586
 587
 588
 589
 590
 591
 592
 593
 594
 595
 596
 597
 598
 599
 600
 601
 602
 603
 604
 605
 606
 607
 608
 609
 610
 611
 612
 613
 614
 615
 616
 617
 618
 619
 620
 621
 622
 623
 624
 625
 626
 627
 628
 629
 630
 631
 632
 633
 634
 635
 636
 637
 638
 639
 640
 641
 642
 643
 644
 645
 646
 647
 648
 649
 650
 651
 652
 653
 654
 655
 656
 657
 658
 659
 660
 661
 662
 663
 664
 665
 666
 667
 668
 669
 670
 671
 672
 673
 674
 675
 676
 677
 678
 679
 680
 681
 682
 683
 684
 685
 686
 687
 688
 689
 690
 691
 692
 693
 694
 695
 696
 697
 698
 699
 700
 701
 702
 703
 704
 705
 706
 707
 708
 709
 710
 711
 712
 713
 714
 715
 716
 717
 718
 719
 720
 721
 722
 723
 724
 725
 726
 727
 728
 729
 730
 731
 732
 733
 734
 735
 736
 737
 738
 739
 740
 741
 742
 743
 744
 745
 746
 747
 748
 749
 750
 751
 752
 753
 754
 755
 756
 757
 758
 759
 760
 761
 762
 763
 764
 765
 766
 767
 768
 769
 770
 771
 772
 773
 774
 775
 776
 777
 778
 779
 780
 781
 782
 783
 784
 785
 786
 787
 788
 789
 790
 791
 792
 793
 794
 795
 796
 797
 798
 799
 800
 801
 802
 803
 804
 805
 806
 807
 808
 809
 810
 811
 812
 813
 814
 815
 816
 817
 818
 819
 820
 821
 822
 823
 824
 825
 826
 827
 828
 829
 830
 831
 832
 833
 834
 835
 836
 837
 838
 839
 840
 841
 842
 843
 844
 845
 846
 847
 848
 849
 850
 851
 852
 853
 854
 855
 856
 857
 858
 859
 860
 861
 862
 863
 864
 865
 866
 867
 868
 869
 870
 871
 872
 873
 874
 875
 876
 877
 878
 879
 880
 881
 882
 883
 884
 885
 886
 887
 888
 889
 890
 891
 892
 893
 894
 895
 896
 897
 898
 899
 900
 901
 902
 903
 904
 905
 906
 907
 908
 909
 910
 911
 912
 913
 914
 915
 916
 917
 918
 919
 920
 921
 922
 923
 924
 925
 926
 927
 928
 929
 930
 931
 932
 933
 934
 935
 936
 937
 938
 939
 940
 941
 942
 943
 944
 945
 946
 947
 948
 949
 950
 951
 952
 953
 954
 955
 956
 957
 958
 959
 960
 961
 962
 963
 964
 965
 966
 967
 968
 969
 970
 971
 972
 973
 974
 975
 976
 977
 978
 979
 980
 981
 982
 983
 984
 985
 986
 987
 988
 989
 990
 991
 992
 993
 994
 995
 996
 997
 998
 999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
class EnergyDiagram:
    """
    Create and manage chemical reaction energy diagrams.

    This class provides a high-level interface for constructing
    reaction energy profiles, including reaction paths, images,
    energy difference bars, labels, legends, and numerical
    annotations. Layout, scaling, and styling are handled
    automatically based on the plotted data.

    Parameters
    ----------
    extra_x_margin : tuple of float or list of float, optional
        Additional horizontal margins in data coordinate units
        added to the plot limits as (left, right).
        Default is (0, 0).
    extra_y_margin : tuple of float or list of float, optional
        Additional vertical margins in relative units added to
        the plot limits as (bottom, top). Default is (0, 0).
    width_limit : float or None, optional
        Maximum figure width in inches. When None, the width scales
        freely with the number of reaction states. Default is None.
    figsize : tuple of float or list of float or None, optional
        Explicit figure size in inches as (width, height).
        If None, the size is determined automatically.
    fontsize : int, optional
        Base font size used throughout the diagram.
    verbose : bool, optional
        If True, prints additional information.
    style : str, optional
        Diagram style preset.
    dpi : int, optional
        Figure resolution in dots per inch. Default is 150.

    Attributes
    ----------
    ax : matplotlib.axes.Axes
        The underlying Matplotlib axes object.
    fig : matplotlib.figure.Figure
        The underlying Matplotlib figure object.
    lines : dict of str to PathObject
        Dictionary of reaction paths mapped to their corresponding
        Matplotlib line objects.
    ax_objects : StyleObjects
        Container of Matplotlib objects related to styling.
    bars : list of DifferenceBar
        List of energy difference bar objects in the diagram.
    numbers : dict
        Dictionary containing energy annotation text objects.
    images : dict
        Dictionary containing image artists, keyed by image or series name.

    Methods
    -------
    draw_path(x_data, y_data, color, linetypes=None, ...)
        Add a reaction path to the diagram.

    add_path_labels(path_name, labels, ...)
        Add text labels below the energy levels of a specific path.

    merge_plateaus(x, path_name_left, path_name_right, ...)
        Visually merge two coincident plateaus at a shared x-position.

    draw_difference_bar(x, y_start_end, description, ...)
        Draw an energy difference bar between two energy levels.

    set_xlabels(labels, labelplaces=None, fontsize=None, ...)
        Set x-axis labels for reaction states.

    set_diagram_style(style)
        Change the visual style of the diagram.

    add_xaxis_break(x, gap_scale=1, stopper_scale=1, angle=30)
        Add a break marker on the x-axis at a given position.

    add_yaxis_break(y, gap_scale=1, stopper_scale=1, angle=30)
        Add a break marker on the y-axis at a given position.

    legend(loc='best', fontsize=None)
        Add a legend for labeled reaction paths.

    add_numbers_naive(...)
        Add energy value annotations directly above states.

    add_numbers_stacked(...)
        Add stacked energy annotations to avoid overlap.

    add_numbers_auto(...)
        Automatically distribute energy annotations.

    add_numbers_average(...)
        Add averaged energy annotations.

    modify_number_values(x, x_add=None, x_subtract=None, ...)
        Modify existing energy annotations by adding or subtracting values.

    add_image_in_plot(img_path, position, ...)
        Place a single image at an explicit position within the diagram.

    add_image_series_in_plot(img_paths, img_x_places=None, ...)
        Place a series of images along the diagram, one per x-position.

    show()
        Display the figure.

    Notes
    -----
    The class coordinates layout, styling, path management,
    numbering, and annotation through dedicated internal
    manager components.
    """

    ############################################################
    # Methods for drawing the general plot
    ############################################################

    def __init__(
        self,
        extra_x_margin: tuple[float, float] | list[float] = (0, 0),
        extra_y_margin: tuple[float, float] | list[float] = (0, 0),
        width_limit: float | None = None,
        figsize: tuple[float, float] | list[float] | None = None,
        fontsize: int = constants.STD_FONTSIZE,
        verbose: bool = False,
        style: str = "open",
        dpi: int = 150,
    ):
        self._figure_manager = FigureManager(fontsize=fontsize, dpi=dpi)
        self._path_manager = PathManager(self._figure_manager)
        self._number_manager = NumberManager(self._figure_manager)
        self._style_manager = StyleManager(self._figure_manager, style=style)
        self._layout_manager = LayoutManager(
            self._figure_manager,
            extra_x_margin=extra_x_margin,
            extra_y_margin=extra_y_margin,
            width_limit=width_limit,
            figsize=figsize,
        )
        self._bar_manager = BarManager(self._figure_manager)
        self._image_manager = ImageManager(self._figure_manager)
        self.verbose = verbose
        self.margins = self._layout_manager.adjust_xy_limits(self._path_manager.path_data)
        self.figsize = self._layout_manager.scale_figure(self._path_manager.path_data)
        self.set_xlabels([])

    def draw_difference_bar(
        self,
        x: float,
        y_start_end: tuple[float, float] | list[float],
        description: str,
        diff: float | None = None,
        left_side: bool = False,
        add_difference: bool = True,
        n_decimals: int = 0,
        fontsize: int | None = None,
        color: str = "black",
        arrowstyle: str = "|-|",
        x_whiskers: Sequence[float | None] = (None, None),
        whiskercolor: str | None = None,
    ) -> EnergyDiagram:
        """Draw a vertical energy difference bar between two energy levels.

        Renders a double-headed arrow that spans from one energy level
        to another at a given x-position, with a text label showing
        the energy difference - the latter being calculated automatically.
        Optional horizontal whiskers can be drawn from the energy
        levels to the bar.

        Parameters
        ----------
        x : float
            The x-coordinate at which to draw the bar.
        y_start_end : tuple of float or list of float
            A two-element sequence ``(y_start, y_end)`` specifying the
            bottom and top energy values spanned by the bar.
        description : str
            Text label placed beside the bar, typically the energy
            difference symbol (e.g. ``"ΔE: "``).
        diff : float or None, optional
            Horizontal offset in data coordinates between the bar and
            its text label. When None the offset is computed
            automatically based on the figure width. Default is None.
        left_side : bool, optional
            If True the bar and label are placed to the left of ``x``
            instead of to the right. Default is False.
        add_difference: bool, optional
            If True, the difference between y_start and y_end
            gets automatically added to the description. Default
            is True.
        n_decimals : int, optional
            Number of decimal places to show for the energy difference.
            Default is 0.
        fontsize : int or None, optional
            Font size for the description label. When None the
            diagram's base font size is used. Default is None.
        color : str, optional
            Color of the difference bar. Default is ``"black"``.
        arrowstyle : str, optional
            Matplotlib arrow style string for the double-headed arrow.
            Default is ``"|-|"``.
        x_whiskers : tuple or list of float or None, optional
            A two-element sequence ``(x_bottom, x_top)`` giving the
            starting x-coordinates for optional horizontal whisker
            lines drawn from the bottom and top energy levels to the
            bar. Use None for either element to omit that whisker.
            Default is ``(None, None)``.
        whiskercolor : str or None, optional
            Color of the whisker lines. When None the whiskers use the
            same color as the bar. Default is None.

        Returns
        -------
        EnergyDiagram
            Returns *self* to allow method chaining.
        """
        self._bar_manager.draw_difference_bar(
            x,
            y_start_end,
            description,
            self.margins,
            self.figsize,
            diff=diff,
            left_side=left_side,
            add_difference=add_difference,
            n_decimals=n_decimals,
            fontsize=fontsize,
            color=color,
            arrowstyle=arrowstyle,
            x_whiskers=x_whiskers,
            whiskercolor=whiskercolor,
        )
        return self

    def legend(self, loc: str = "best", fontsize: int | None = None) -> EnergyDiagram:
        """Add a legend for all named reaction paths.

        Generates legend entries for every path that was drawn with a
        ``path_name``. Each entry shows a colored patch matching the
        path color and the corresponding name.

        Parameters
        ----------
        loc : str, optional
            Legend location, as any Matplotlib ``loc`` string
            (e.g. ``"best"``, ``"upper right"``). Default is
            ``"best"``.
        fontsize : int or None, optional
            Font size of the legend text. When None the diagram's base
            font size is used. Default is None.

        Returns
        -------
        EnergyDiagram
            Returns *self* to allow method chaining.
        """
        Validators.validate_number(fontsize, "fontsize", allow_none=True, min_value=0)
        if fontsize is None:
            fontsize = self._figure_manager.fontsize
        patches = []
        for path_name, path_info in self._path_manager.path_data.items():
            if path_info["has_name"]:
                patches.append(mpatches.Patch(color=path_info["color"], label=path_name))
        self._figure_manager.ax.legend(handles=patches, fontsize=fontsize, loc=loc)
        return self

    def show(self) -> None:
        """Display the energy diagram figure.

        Finalizes the figure layout and calls ``matplotlib.pyplot.show()``.
        """
        figsize = self._layout_manager.scale_figure(self._path_manager.path_data)
        if self.verbose:
            print(f"Figure size is {round(figsize[0], 2)} x {round(figsize[1], 2)} inches.")
        plt.show()

    ############################################################
    # Path-related methods
    ############################################################

    def draw_path(
        self,
        x_data: Sequence[float],
        y_data: Sequence[float],
        color: str,
        linetypes: Sequence[int] | None = None,
        path_name: str | None = None,
        show_numbers: bool = True,
        width_plateau: float | None = None,
        lw_plateau: float | str = "plateau",
        lw_connector: float | str = "connector",
        gap_scale: float | int | Sequence[float | int] = 1,
    ) -> EnergyDiagram:
        """Add a reaction path to the energy diagram.

        Draws a series of horizontal energy levels connected by
        transitions. Each segment between adjacent levels is drawn
        with the connector style specified by ``linetypes``.

        Parameters
        ----------
        x_data : sequence of float
            X-coordinates for each reaction state (energy level).
            Must have the same length as ``y_data``.
        y_data : sequence of float
            Y-coordinates (energy values) for each reaction state.
            Must have the same length as ``x_data``.
        color : str
            Color of the energy levels and connectors for this path,
            as any Matplotlib color string (e.g. ``"blue"``,
            ``"#FF5733"``).
        linetypes : sequence of int or int or None, optional
            Connector style(s) for the segments between consecutive
            energy levels. Must have length ``len(x_data) - 1``, or
            be a single integer applied to all segments. Allowed
            values:

            *  ``0``  : no connector
            *  ``1``  : dotted line (default)
            *  ``-1`` : broken dotted line
            *  ``2``  : solid line
            *  ``-2`` : broken solid line
            *  ``3``  : dotted cubic spline
            *  ``-3`` : broken dotted cubic spline
            *  ``4``  : solid cubic spline
            *  ``-4`` : broken solid cubic spline

            When None, all segments use a dotted line (``1``).
        path_name : str or None, optional
            A name for this path used as the legend label. When None
            the path is not added to the legend. Default is None.
        show_numbers : bool, optional
            If False, energy values along this path are excluded from
            any subsequent ``add_numbers_*`` calls. Default is True.
        width_plateau : float or None, optional
            Width of the horizontal energy level bars in data coordinate
            units. When None, a default width is applied. Default is None.
        lw_plateau : float, str, optional
            Line width for the horizontal energy level bars. Can be a
            float in points, or a string referring to a predefined
            value (``"plateau"`` or ``"connector"``). Default is ``"plateau"``.
        lw_connector : float, str, optional
            Line width for the connectors between energy levels. Can be a
            float in points, or a string referring to a predefined
            value (``"plateau"`` or ``"connector"``). Default is ``"connector"``.
        gap_scale : float, int, or sequence of float or int, optional
            Scaling factor for the gap in broken line styles (``-4`` to ``-1``).
            Can be a single number applied to all segments, or a
            sequence with one value per segment. Default is 1.

        Returns
        -------
        EnergyDiagram
            Returns *self* to allow method chaining.
        """
        self._path_manager.draw_path(
            x_data,
            y_data,
            color,
            linetypes=linetypes,
            path_name=path_name,
            show_numbers=show_numbers,
            width_plateau=width_plateau,
            lw_plateau=lw_plateau,
            lw_connector=lw_connector,
            gap_scale=gap_scale,
        )
        self.margins = self._layout_manager.adjust_xy_limits(self._path_manager.path_data)
        self.figsize = self._layout_manager.scale_figure(self._path_manager.path_data)
        self._recalculate_xlabels()
        self._recalculate_axis_breaks()
        self._recalculate_merged_plateaus()
        self._recalculate_path_labels()
        return self

    def add_path_labels(
        self,
        path_name: str,
        labels: Sequence[str],
        fontsize: int | None = None,
        weight: str = "normal",
        color: str | None = None,
    ) -> EnergyDiagram:
        """Add text labels below the energy levels of a specific path.

        Parameters
        ----------
        path_name : str
            Name of the path to which the labels should be added.
        labels : sequence of str
            A sequence of text labels, one for each energy level in the path.
            If None is passed for a label, no label is drawn for that level.
            Must have the same length as the number of energy levels in the path.
        fontsize : int or None, optional
            Font size for the labels. When None the diagram's base font size
            is used. Default is None.
        weight : str, optional
            Font weight for the labels, e.g. ``"bold"`` or ``"normal"``.
            Default is ``"normal"``.
        color : str or None, optional
            Color for the labels. When None, uses the same color as the path.
            Default is None.

        Returns
        -------
        EnergyDiagram
            Returns *self* to allow method chaining.

        Raises
        ------
        ValueError
            If the specified path does not exist or if the number of labels
            does not match the number of energy levels in the path.
        """
        self._path_manager.add_path_labels(
            margins=self.margins,
            figsize=self.figsize,
            path_name=path_name,
            labels=labels,
            fontsize=fontsize,
            weight=weight,
            color=color,
        )
        if self._image_manager.has_image_series:
            self._image_manager.recalculate_image_series(
                self.margins,
                self.figsize,
                self._path_manager.path_data,
                self._number_manager.mpl_objects,
                self._style_manager.mpl_objects.x_labels,
                self._path_manager.mpl_objects,
            )
        if self._number_manager.numberings_added:
            self._number_manager._recalculate_numbers(
                path_data=self._path_manager.path_data,
                margins=self.margins,
                figsize=self.figsize,
                path_mpl_objects=self._path_manager.mpl_objects,
            )
        return self

    def _recalculate_path_labels(self):
        self._path_manager._recalculate_path_labels(
            margins=self.margins,
            figsize=self.figsize,
        )

    def merge_plateaus(
        self,
        x: int,
        path_name_left: str,
        path_name_right: str,
        gap_scale: float = 1,
        stopper_scale: float = 1,
        angle: float = 30,
    ) -> EnergyDiagram:
        """Visually merge two coincident plateaus at a shared x-position.

        When two paths have identical energy levels at the same x-coordinate,
        this method replaces both full-width plateaus with two shorter half-plateaus
        separated by a small gap. Diagonal stopper tick marks are drawn into the gap
        to indicate that the two levels are degenerate. The resulting split is
        recalculated automatically whenever a new path is added.

        Both paths must already exist and must have the same y-value at ``x``.

        Parameters
        ----------
        x : int
            The x-coordinate at which both paths share an energy level.
        path_name_left : str
            Name of the path whose plateau will appear on the left side of the gap.
        path_name_right : str
            Name of the path whose plateau will appear on the right side of the gap.
        gap_scale : float, optional
            Multiplicative scaling factor for the width of the gap between the two
            half-plateaus. Default is ``1``.
        stopper_scale : float, optional
            Multiplicative scaling factor for the size of the diagonal stopper tick
            marks drawn in the gap. Default is ``1``.
        angle : float, optional
            Angle of the stopper tick marks in degrees from the vertical.
            Default is ``30``.

        Returns
        -------
        EnergyDiagram
            Returns *self* to allow method chaining.

        Raises
        ------
        ValueError
            If either path does not exist, does not have a value at ``x``, or
            the two paths do not share the same y-value at ``x``.
        """
        self._path_manager.merge_plateaus(
            margins=self.margins,
            figsize=self.figsize,
            x=x,
            path_name_left=path_name_left,
            path_name_right=path_name_right,
            gap_scale=gap_scale,
            stopper_scale=stopper_scale,
            angle=angle,
        )
        return self

    def _recalculate_merged_plateaus(self):
        self._path_manager._recalculate_merged_plateaus(self.margins, self.figsize)

    ############################################################
    # Style-related methods
    ############################################################

    def set_xlabels(
        self,
        labels: Sequence,
        labelplaces: Sequence[float] | None = None,
        fontsize: int | None = None,
        weight: str = "bold",
        in_plot: bool = False,
    ) -> EnergyDiagram:
        """Set text labels for the reaction states along the x-axis.

        Labels are placed below the horizontal energy bars by default.
        If ``in_plot`` is True they are rendered inside the plot area
        directly below the lowest state.

        Parameters
        ----------
        labels : sequence
            Ordered sequence of label strings, one per reaction state
            (i.e. one per unique x-position in the plotted paths).
        labelplaces : sequence of float or None, optional
            Explicit x-coordinates at which to place each label.
            When None the labels are naively placed starting at
            x = 0. Default is None.
        fontsize : int or None, optional
            Font size for the labels. When None the diagram's base
            font size is used. Default is None.
        weight : str, optional
            Font weight for the labels, e.g. ``"bold"`` or
            ``"normal"``. Default is ``"bold"``.
        in_plot : bool, optional
            If True, labels are drawn inside the plot area below the
            lowest state rather than below the x-axis. Default
            is False.

        Returns
        -------
        EnergyDiagram
            Returns *self* to allow method chaining.
        """
        self._style_manager.set_xlabels(
            self.margins,
            self.figsize,
            self._path_manager.path_data,
            labels,
            labelplaces=labelplaces,
            fontsize=fontsize,
            weight=weight,
            in_plot=in_plot,
        )
        if self._image_manager.has_image_series:
            self._image_manager.recalculate_image_series(
                self.margins,
                self.figsize,
                self._path_manager.path_data,
                self._number_manager.mpl_objects,
                self._style_manager.mpl_objects.x_labels,
                self._path_manager.mpl_objects,
            )
        return self

    def _recalculate_xlabels(self):
        try:
            self.set_xlabels(**self._style_manager.labelproperties)
        except AttributeError:
            pass

    def set_diagram_style(self, style: str) -> EnergyDiagram:
        """Change the overall visual style of the diagram.

        Applies a named style preset that controls the appearance of
        the plot background, spines, tick marks, and other decorative
        elements.

        Parameters
        ----------
        style : str
            Name of the style preset to apply. Supported values
            are ``"boxed"``, ``"halfboxed"``, ``"open"``, ``"twosided"``
            and ``"borderless"``. Default style is ``"open"``.

        Returns
        -------
        EnergyDiagram
            Returns *self* to allow method chaining.
        """
        self._layout_manager.adjust_xy_limits(self._path_manager.path_data)
        self._style_manager.set_diagram_style(style)
        try:
            self.set_xlabels(
                **self._style_manager.labelproperties  # type: ignore[arg-type]
            )
        except AttributeError:
            pass
        return self

    def add_xaxis_break(
        self,
        x: float,
        gap_scale: float = 1,
        stopper_scale: float = 1,
        angle: float = 30,
    ) -> None:
        """Add a break marker on the x-axis at a given position.

        Draws a pair of diagonal stopper lines over a white gap rectangle on
        the x-axis (or axes spine) to indicate a discontinuity in the x scale.

        Not compatible with the ``"open"`` diagram style.

        Parameters
        ----------
        x : float
            Position along the x-axis (in data coordinates) where the break
            should be placed.
        gap_scale : float, optional
            Multiplicative scaling factor for the width of the white gap that
            covers the axis spine. Default is ``1``.
        stopper_scale : float, optional
            Multiplicative scaling factor for the size of the diagonal stopper
            tick marks. Default is ``1``.
        angle : float, optional
            Angle of the stopper tick marks in degrees from the vertical.
            Default is ``30``.
        """
        self._style_manager.add_xaxis_break(
            margins=self.margins,
            figsize=self.figsize,
            x=x,
            gap_scale=gap_scale,
            stopper_scale=stopper_scale,
            angle=angle,
        )

    def add_yaxis_break(
        self,
        y: float,
        gap_scale: float = 1,
        stopper_scale: float = 1,
        angle: float = 30,
    ) -> None:
        """Add a break marker on the y-axis at a given position.

        Draws a pair of diagonal stopper lines over a white gap rectangle on
        the y-axis spine to indicate a discontinuity in the y scale.

        Parameters
        ----------
        y : float
            Position along the y-axis (in data coordinates) where the break
            should be placed.
        gap_scale : float, optional
            Multiplicative scaling factor for the height of the white gap that
            covers the axis spine. Default is ``1``.
        stopper_scale : float, optional
            Multiplicative scaling factor for the size of the diagonal stopper
            tick marks. Default is ``1``.
        angle : float, optional
            Angle of the stopper tick marks in degrees from the horizontal.
            Default is ``30``.
        """
        self._style_manager.add_yaxis_break(
            margins=self.margins,
            figsize=self.figsize,
            y=y,
            gap_scale=gap_scale,
            stopper_scale=stopper_scale,
            angle=angle,
        )

    def _recalculate_axis_breaks(self):
        if self._style_manager.has_axes_breaks:
            self._style_manager.recalculate_axis_breaks(self.margins, self.figsize)

    ############################################################
    # Methods for plotting numbers
    ############################################################

    def add_numbers_naive(
        self,
        x_min_max: tuple[float, float] | list[float] | float | None = None,
        fontsize: int | None = None,
        n_decimals: int = 0,
    ) -> EnergyDiagram:
        """Annotate energy levels with their values, placed directly above each bar.

        This is the simplest numbering strategy: each energy value is
        printed at its x-position, just above the corresponding
        horizontal bar, with no attempt to resolve overlapping labels.
        Paths where ``show_numbers=False`` was passed to
        :meth:`draw_path` are excluded.

        Parameters
        ----------
        x_min_max : tuple of float, list of float, float, or None, optional
            Restricts annotation to energy states whose x-coordinate
            falls within the interval ``[x_min, x_max]``.  Supply a
            two-element sequence for an interval, a single float to
            annotate only the state at that exact x-value, or None to
            annotate all states. Default is None.
        fontsize : int or None, optional
            Font size for the annotations. When None the diagram's
            base font size is used. Default is None.
        n_decimals : int, optional
            Number of decimal places to show for the energy values.
            Default is 0.

        Returns
        -------
        EnergyDiagram
            Returns *self* to allow method chaining.
        """
        self._number_manager.add_numbers_naive(
            self._path_manager.path_data,
            self.margins,
            self.figsize,
            x_min_max,
            fontsize=fontsize,
            n_decimals=n_decimals,
        )
        if self._image_manager.has_image_series:
            self._image_manager.recalculate_image_series(
                self.margins,
                self.figsize,
                self._path_manager.path_data,
                self._number_manager.mpl_objects,
                self._style_manager.mpl_objects.x_labels,
                self._path_manager.mpl_objects,
            )
        return self

    def add_numbers_stacked(
        self,
        x_min_max: tuple[float, float] | list[float] | float | None = None,
        fontsize: int | None = None,
        sort_by_energy: bool = True,
        no_overlap_with_nonnumbered: bool = True,
        n_decimals: int = 0,
    ) -> EnergyDiagram:
        """Annotate energy levels with stacked labels above the highest state.

        When multiple paths share the same x-position the labels are
        arranged vertically (stacked) so they do not collide. Paths
        where ``show_numbers=False`` was passed to :meth:`draw_path`
        are excluded from numbering but, unless ``no_overlap_with_nonnumbered``
        is False, their energy bars are still treated as obstacles that
        stacked labels must avoid.

        Parameters
        ----------
        x_min_max : tuple of float, list of float, float, or None, optional
            Restricts annotation to energy states within the interval
            ``[x_min, x_max]``. Supply a two-element sequence, a
            single float for an exact match, or None for all states.
            Default is None.
        fontsize : int or None, optional
            Font size for the annotations. When None the diagram's
            base font size is used. Default is None.
        sort_by_energy : bool, optional
            If True, labels at the same x-position are sorted by
            energy value before stacking, keeping them in order.
            Default is True.
        no_overlap_with_nonnumbered : bool, optional
            If True, labels are also offset to avoid colliding with
            energy bars belonging to paths that have ``show_numbers=False``.
            Default is True.
        n_decimals : int, optional
            Number of decimal places to show for the energy values.
            Default is 0.

        Returns
        -------
        EnergyDiagram
            Returns *self* to allow method chaining.
        """
        self._number_manager.add_numbers_stacked(
            self._path_manager.path_data,
            self.margins,
            self.figsize,
            self._path_manager.mpl_objects,
            x_min_max,
            fontsize=fontsize,
            sort_by_energy=sort_by_energy,
            no_overlap_with_nonnumbered=no_overlap_with_nonnumbered,
            n_decimals=n_decimals,
        )
        if self._image_manager.has_image_series:
            self._image_manager.recalculate_image_series(
                self.margins,
                self.figsize,
                self._path_manager.path_data,
                self._number_manager.mpl_objects,
                self._style_manager.mpl_objects.x_labels,
                self._path_manager.mpl_objects,
            )
        return self

    def add_numbers_auto(
        self,
        x_min_max: tuple[float, float] | list[float] | float | None = None,
        fontsize: int | None = None,
        n_decimals: int = 0,
    ) -> EnergyDiagram:
        """Annotate energy levels with automatically placed labels.

        Chooses label placement (above which bar) automatically
        for each energy state to minimize visual clutter, taking into
        account the relative positions of all paths. Paths
        where ``show_numbers=False`` was passed to :meth:`draw_path`
        are excluded from numbering.

        Parameters
        ----------
        x_min_max : tuple of float, list of float, float, or None, optional
            Restricts annotation to energy states within the interval
            ``[x_min, x_max]``. Supply a two-element sequence, a
            single float for an exact match, or None for all states.
            Default is None.
        fontsize : int or None, optional
            Font size for the annotations. When None the diagram's
            base font size is used. Default is None.
        n_decimals : int, optional
            Number of decimal places to show for the energy values.
            Default is 0.

        Returns
        -------
        EnergyDiagram
            Returns *self* to allow method chaining.
        """
        self._number_manager.add_numbers_auto(
            self._path_manager.path_data,
            self.margins,
            self.figsize,
            path_mpl_objects=self._path_manager.mpl_objects,
            x_min_max=x_min_max,
            fontsize=fontsize,
            n_decimals=n_decimals,
        )
        if self._image_manager.has_image_series:
            self._image_manager.recalculate_image_series(
                self.margins,
                self.figsize,
                self._path_manager.path_data,
                self._number_manager.mpl_objects,
                self._style_manager.mpl_objects.x_labels,
                self._path_manager.mpl_objects,
            )
        return self

    def add_numbers_average(
        self,
        x_min_max: tuple[float, float] | list[float] | float | None = None,
        fontsize: int | None = None,
        color: str = "black",
        n_decimals: int = 0,
    ) -> EnergyDiagram:
        """Annotate energy states with the average value across all paths.

        At each x-position the mean energy of all visible paths is
        computed and a single label is rendered. This is useful when
        multiple paths are close together and a single representative
        value is preferred over individual labels. Paths where
        ``show_numbers=False`` was passed to :meth:`draw_path` are
        excluded from the average.

        Parameters
        ----------
        x_min_max : tuple of float, list of float, float, or None, optional
            Restricts annotation to energy states within the interval
            ``[x_min, x_max]``. Supply a two-element sequence, a
            single float for an exact match, or None for all states.
            Default is None.
        fontsize : int or None, optional
            Font size for the annotations. When None the diagram's
            base font size is used. Default is None.
        color : str, optional
            Color of the annotation text. Default is ``"black"``.

        Returns
        -------
        EnergyDiagram
            Returns *self* to allow method chaining.
        """
        self._number_manager.add_numbers_average(
            self._path_manager.path_data,
            self.margins,
            self.figsize,
            x_min_max=x_min_max,
            fontsize=fontsize,
            color=color,
            n_decimals=n_decimals,
        )
        if self._image_manager.has_image_series:
            self._image_manager.recalculate_image_series(
                self.margins,
                self.figsize,
                self._path_manager.path_data,
                self._number_manager.mpl_objects,
                self._style_manager.mpl_objects.x_labels,
                self._path_manager.mpl_objects,
            )
        return self

    def modify_number_values(
        self,
        x: float,
        base_value: float = 0.0,
        x_add: float | list[float] | None = None,
        x_subtract: float | list[float] | None = None,
        include_paths: list[str] | None = None,
        exclude_paths: list[str] | None = None,
        brackets: tuple[str, str] | list[str] | None = ("(", ")"),
        n_decimals: int = 0,
    ) -> EnergyDiagram:
        """
        Modify energy labels at a specific x-position by combining energy values.

        This method recalculates and updates the numeric label displayed above an
        energy level at a given x-coordinate. The new value is computed from a
        ``base_value``, plus energy levels from specified x-positions that are
        added or subtracted. This is useful for annotating energy differences,
        especially for transition states.

        Parameters
        ----------
        x : float
            The x-coordinate (reaction state position) where the label is located
            and will be modified.
        base_value : float, optional
            Initial value for the calculation. The final label value is computed as:
            ``base_value + sum(energies at x_add) - sum(energies at x_subtract)``
            for each path. Default is 0.0.
        x_add : float or list of float or None, optional
            X-coordinate(s) whose energy values are added to the calculated result.
            Can be a single float or a list of floats. Useful for summing multiple
            energy contributions. Default is None (no values added).
        x_subtract : float or list of float or None, optional
            X-coordinate(s) whose energy values are subtracted from the calculated
            result. Can be a single float or a list of floats. Useful for computing
            differences like reaction barriers or enthalpies. Default is None
            (no values subtracted).
        include_paths : list of str or None, optional
            Path names for which the label should be modified. If specified,
            only these paths are updated. Cannot be used with ``exclude_paths``.
            Default is None (all paths are modified).
        exclude_paths : list of str or None, optional
            Path names to exclude from modification. If specified, all paths
            except these are updated. Cannot be used with ``include_paths``.
            Default is None (all paths are modified).
        brackets : tuple of str and str or list of str or None, optional
            Characters to wrap around the numeric value as (left_bracket,
            right_bracket). Common choices are ``("(", ")")``, ``("[", "]")``,
            or ``("", "")`` for no brackets. Default is ``("(", ")")``.
        n_decimals : int, optional
            Number of decimal places in the formatted label. Default is 0
            (integer values).

        Returns
        -------
        EnergyDiagram
            Returns ``self`` for method chaining.

        Raises
        ------
        ValueError
            If both ``include_paths`` and ``exclude_paths`` are specified.
        ValueError
            If a path name in ``include_paths`` does not exist in the diagram.
        UserWarning
            If a requested x-value to add or subtract is not found in a path,
            or if a label at the specified x-position does not exist.

        Examples
        --------
        Label a transition state barrier at x=1.0 by subtracting the reactant
        energy (x=0.0) from the transition state energy (x=1.0):

        >>> diagram.modify_number_values(
        ...     x=1.0, x_add=[1.0], x_subtract=[0.0], brackets=["Δ‡", ""]
        ... )

        Compute a complex energy term at x=3.0 for only specific paths:

        >>> diagram.modify_number_values(
        ...     x=3.0,
        ...     base_value=10.0,
        ...     x_add=[1.0, 2.0],
        ...     x_subtract=[0.0],
        ...     include_paths=["pathway_A"],
        ...     n_decimals=2
        ... )
        """
        self._number_manager.modify_number_values(
            path_data=self._path_manager.path_data,
            x=x,
            base_value=base_value,
            x_add=x_add,
            x_subtract=x_subtract,
            include_paths=include_paths,
            exclude_paths=exclude_paths,
            brackets=brackets,
            n_decimals=n_decimals,
        )
        return self

    ############################################################
    # Methods for plotting images
    ############################################################

    def add_image_in_plot(
        self,
        img_path: str,
        position: tuple[float, float] | list[float],
        img_name: str | None = None,
        horizontal_alignment: str = "center",
        vertical_alignment: str = "center",
        width: float | None = None,
        height: float | None = None,
        framed: bool = False,
        frame_color: str = "black",
    ) -> EnergyDiagram:
        """
        Place a single image at an explicit data-coordinate position.

        The image is scaled to the requested ``width`` and/or ``height`` in
        data coordinates, preserving the aspect ratio when only one dimension
        is supplied. The rendered artist is stored in ``self.images`` under
        ``img_name``.

        Parameters
        ----------
        img_path : str
            File path to the image (any format supported by Matplotlib).
        position : tuple of float or list of float
            The (x, y) anchor point in data coordinates.
        img_name : str or None, optional
            Key under which the artist is stored. An automatic key is
            assigned when None. Default is None.
        horizontal_alignment : str, optional
            Horizontal anchor of ``position``: ``"left"``, ``"center"``,
            or ``"right"``. Default ``"center"``.
        vertical_alignment : str, optional
            Vertical anchor of ``position``: ``"top"``, ``"center"``,
            or ``"bottom"``. Default ``"center"``.
        width : float or None, optional
            Image width in data coordinate units. Default is None.
        height : float or None, optional
            Image height in data coordinate units. Default is None.
        framed : bool, optional
            If True, draws a rectangular border around the image. Default False.
        frame_color : str, optional
            Color of the frame border. Default ``"black"``.
        """
        self._image_manager.add_image_in_plot(
            img_path,
            position,
            margins=self.margins,
            figsize=self.figsize,
            img_name=img_name,
            horizontal_alignment=horizontal_alignment,
            vertical_alignment=vertical_alignment,
            width=width,
            height=height,
            framed=framed,
            frame_color=frame_color,
        )
        return self

    def add_image_series_in_plot(
        self,
        img_paths: Sequence[str],
        img_x_places: Sequence[float] | None = None,
        y_placement: Sequence[str] | str = "auto",
        y_offsets: Sequence[float] | float = 0,
        img_series_name: str | None = None,
        width: Sequence[float | None] | float | None = None,
        height: Sequence[float | None] | float | None = None,
        framed: Sequence[bool] | bool = False,
        frame_colors: Sequence[str] | str = "black",
    ) -> EnergyDiagram:
        """
        Place a series of images, one per x-position, avoiding visual collisions.

        For each image the method finds free vertical space above or below the
        nearest energy bar, number annotation, and x-axis label. Placement is
        chosen automatically or forced to ``"top"``/``"bottom"`` via
        ``y_placement``. The series artists are stored in ``self.images`` under
        ``img_series_name``.

        Parameters
        ----------
        img_paths : sequence of str
            Ordered file paths for each image in the series.
        img_x_places : sequence of float or None, optional
            x-coordinates for each image. Defaults to ``[0, 1, 2, ...]``.
        y_placement : sequence of str or str, optional
            Vertical placement strategy per image: ``"top"``, ``"bottom"``,
            or ``"auto"``. Default ``"auto"``.
        y_offsets : sequence of float or float, optional
            Additional vertical offset applied after collision avoidance.
            Default 0.
        img_series_name : str or None, optional
            Key under which artists are stored. Auto-assigned when None.
        width : sequence or float or None, optional
            Image widths in data coordinate units.
        height : sequence or float or None, optional
            Image heights in data coordinate units.
        framed : sequence of bool or bool, optional
            Whether to draw a border around each image. Default False.
        frame_colors : sequence of str or str, optional
            Border colors. Default ``"black"``.
        """
        self._image_manager.add_image_series_in_plot(
            img_paths,
            margins=self.margins,
            figsize=self.figsize,
            path_data=self._path_manager.path_data,
            number_mpl_objects=self._number_manager.mpl_objects,
            xlabel_mpl_objects=self._style_manager.mpl_objects.x_labels,
            path_mpl_objects=self._path_manager.mpl_objects,
            img_x_places=img_x_places,
            y_placement=y_placement,
            y_offsets=y_offsets,
            img_series_name=img_series_name,
            width=width,
            height=height,
            framed=framed,
            frame_colors=frame_colors,
        )
        return self

    ############################################################
    # Getters
    ############################################################

    @property
    def ax(self) -> Axes:
        """matplotlib.axes.Axes: The underlying Axes object for the diagram.

        Can be used to apply any additional Matplotlib customizations
        directly, such as setting axis labels, adding annotations, or
        adjusting tick marks.
        """
        return self._figure_manager.ax

    @property
    def fig(self) -> Figure:
        """matplotlib.figure.Figure: The underlying Figure object for the diagram.

        Can be used to save the figure, adjust figure-level properties
        such as DPI or size, or pass it to external Matplotlib routines.
        """
        return self._figure_manager.fig

    @property
    def lines(self) -> dict[str, PathObject]:
        """dict of str to PathObject: Matplotlib line objects for each reaction path.

        Keys are the path names supplied via the ``path_name`` argument
        of :meth:`draw_path`. Each value is a ``PathObject`` containing
        the rendered Matplotlib line and connector artists for that path.
        Paths drawn without a name are keyed by an internal identifier.
        """
        return self._path_manager.mpl_objects

    @property
    def ax_objects(self) -> StyleObjects:
        """StyleObjects: Matplotlib artists related to diagram styling.

        Contains the spine, tick, and background artists that are
        managed by the style manager. Useful for fine-grained style
        adjustments after calling :meth:`set_diagram_style`.
        """
        return self._style_manager.mpl_objects

    @property
    def bars(self) -> list[DifferenceBar]:
        """list of DifferenceBar: Energy difference bar objects in the diagram.

        Each entry corresponds to one :meth:`draw_difference_bar` call
        and holds the arrow, label text, and optional whisker artists.
        The list is ordered by the sequence in which bars were added.
        """
        return self._bar_manager.mpl_objects

    @property
    def numbers(self) -> dict[str, dict[str, Text]]:
        """dict of str to dict of str to Text: Energy annotation text objects.

        Outer keys are path names; inner keys are string representations
        of the x-coordinates at which annotations were placed. Each
        value is a Matplotlib ``Text`` artist. Populated after calling
        any of the ``add_numbers_*`` methods.
        """
        return self._number_manager.mpl_objects

    @property
    def images(self) -> dict:
        """dict: Image artists stored by the image manager.

        Keys are image or series names (as supplied via ``img_name`` or
        ``img_series_name``). Standalone images map directly to an
        ``ImageObject``; series map to a nested dict keyed by x-coordinate.
        Populated after calling :meth:`add_image_in_plot` or
        :meth:`add_image_series_in_plot`.
        """
        return self._image_manager.mpl_objects

ax property

matplotlib.axes.Axes: The underlying Axes object for the diagram.

Can be used to apply any additional Matplotlib customizations directly, such as setting axis labels, adding annotations, or adjusting tick marks.

ax_objects property

StyleObjects: Matplotlib artists related to diagram styling.

Contains the spine, tick, and background artists that are managed by the style manager. Useful for fine-grained style adjustments after calling :meth:set_diagram_style.

bars property

list of DifferenceBar: Energy difference bar objects in the diagram.

Each entry corresponds to one :meth:draw_difference_bar call and holds the arrow, label text, and optional whisker artists. The list is ordered by the sequence in which bars were added.

fig property

matplotlib.figure.Figure: The underlying Figure object for the diagram.

Can be used to save the figure, adjust figure-level properties such as DPI or size, or pass it to external Matplotlib routines.

images property

dict: Image artists stored by the image manager.

Keys are image or series names (as supplied via img_name or img_series_name). Standalone images map directly to an ImageObject; series map to a nested dict keyed by x-coordinate. Populated after calling :meth:add_image_in_plot or :meth:add_image_series_in_plot.

lines property

dict of str to PathObject: Matplotlib line objects for each reaction path.

Keys are the path names supplied via the path_name argument of :meth:draw_path. Each value is a PathObject containing the rendered Matplotlib line and connector artists for that path. Paths drawn without a name are keyed by an internal identifier.

numbers property

dict of str to dict of str to Text: Energy annotation text objects.

Outer keys are path names; inner keys are string representations of the x-coordinates at which annotations were placed. Each value is a Matplotlib Text artist. Populated after calling any of the add_numbers_* methods.

add_image_in_plot(img_path, position, img_name=None, horizontal_alignment='center', vertical_alignment='center', width=None, height=None, framed=False, frame_color='black')

Place a single image at an explicit data-coordinate position.

The image is scaled to the requested width and/or height in data coordinates, preserving the aspect ratio when only one dimension is supplied. The rendered artist is stored in self.images under img_name.

Parameters:

Name Type Description Default
img_path str

File path to the image (any format supported by Matplotlib).

required
position tuple of float or list of float

The (x, y) anchor point in data coordinates.

required
img_name str or None

Key under which the artist is stored. An automatic key is assigned when None. Default is None.

None
horizontal_alignment str

Horizontal anchor of position: "left", "center", or "right". Default "center".

'center'
vertical_alignment str

Vertical anchor of position: "top", "center", or "bottom". Default "center".

'center'
width float or None

Image width in data coordinate units. Default is None.

None
height float or None

Image height in data coordinate units. Default is None.

None
framed bool

If True, draws a rectangular border around the image. Default False.

False
frame_color str

Color of the frame border. Default "black".

'black'
Source code in src/chemdiagrams/energy_diagram.py
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
def add_image_in_plot(
    self,
    img_path: str,
    position: tuple[float, float] | list[float],
    img_name: str | None = None,
    horizontal_alignment: str = "center",
    vertical_alignment: str = "center",
    width: float | None = None,
    height: float | None = None,
    framed: bool = False,
    frame_color: str = "black",
) -> EnergyDiagram:
    """
    Place a single image at an explicit data-coordinate position.

    The image is scaled to the requested ``width`` and/or ``height`` in
    data coordinates, preserving the aspect ratio when only one dimension
    is supplied. The rendered artist is stored in ``self.images`` under
    ``img_name``.

    Parameters
    ----------
    img_path : str
        File path to the image (any format supported by Matplotlib).
    position : tuple of float or list of float
        The (x, y) anchor point in data coordinates.
    img_name : str or None, optional
        Key under which the artist is stored. An automatic key is
        assigned when None. Default is None.
    horizontal_alignment : str, optional
        Horizontal anchor of ``position``: ``"left"``, ``"center"``,
        or ``"right"``. Default ``"center"``.
    vertical_alignment : str, optional
        Vertical anchor of ``position``: ``"top"``, ``"center"``,
        or ``"bottom"``. Default ``"center"``.
    width : float or None, optional
        Image width in data coordinate units. Default is None.
    height : float or None, optional
        Image height in data coordinate units. Default is None.
    framed : bool, optional
        If True, draws a rectangular border around the image. Default False.
    frame_color : str, optional
        Color of the frame border. Default ``"black"``.
    """
    self._image_manager.add_image_in_plot(
        img_path,
        position,
        margins=self.margins,
        figsize=self.figsize,
        img_name=img_name,
        horizontal_alignment=horizontal_alignment,
        vertical_alignment=vertical_alignment,
        width=width,
        height=height,
        framed=framed,
        frame_color=frame_color,
    )
    return self

add_image_series_in_plot(img_paths, img_x_places=None, y_placement='auto', y_offsets=0, img_series_name=None, width=None, height=None, framed=False, frame_colors='black')

Place a series of images, one per x-position, avoiding visual collisions.

For each image the method finds free vertical space above or below the nearest energy bar, number annotation, and x-axis label. Placement is chosen automatically or forced to "top"/"bottom" via y_placement. The series artists are stored in self.images under img_series_name.

Parameters:

Name Type Description Default
img_paths sequence of str

Ordered file paths for each image in the series.

required
img_x_places sequence of float or None

x-coordinates for each image. Defaults to [0, 1, 2, ...].

None
y_placement sequence of str or str

Vertical placement strategy per image: "top", "bottom", or "auto". Default "auto".

'auto'
y_offsets sequence of float or float

Additional vertical offset applied after collision avoidance. Default 0.

0
img_series_name str or None

Key under which artists are stored. Auto-assigned when None.

None
width sequence or float or None

Image widths in data coordinate units.

None
height sequence or float or None

Image heights in data coordinate units.

None
framed sequence of bool or bool

Whether to draw a border around each image. Default False.

False
frame_colors sequence of str or str

Border colors. Default "black".

'black'
Source code in src/chemdiagrams/energy_diagram.py
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
def add_image_series_in_plot(
    self,
    img_paths: Sequence[str],
    img_x_places: Sequence[float] | None = None,
    y_placement: Sequence[str] | str = "auto",
    y_offsets: Sequence[float] | float = 0,
    img_series_name: str | None = None,
    width: Sequence[float | None] | float | None = None,
    height: Sequence[float | None] | float | None = None,
    framed: Sequence[bool] | bool = False,
    frame_colors: Sequence[str] | str = "black",
) -> EnergyDiagram:
    """
    Place a series of images, one per x-position, avoiding visual collisions.

    For each image the method finds free vertical space above or below the
    nearest energy bar, number annotation, and x-axis label. Placement is
    chosen automatically or forced to ``"top"``/``"bottom"`` via
    ``y_placement``. The series artists are stored in ``self.images`` under
    ``img_series_name``.

    Parameters
    ----------
    img_paths : sequence of str
        Ordered file paths for each image in the series.
    img_x_places : sequence of float or None, optional
        x-coordinates for each image. Defaults to ``[0, 1, 2, ...]``.
    y_placement : sequence of str or str, optional
        Vertical placement strategy per image: ``"top"``, ``"bottom"``,
        or ``"auto"``. Default ``"auto"``.
    y_offsets : sequence of float or float, optional
        Additional vertical offset applied after collision avoidance.
        Default 0.
    img_series_name : str or None, optional
        Key under which artists are stored. Auto-assigned when None.
    width : sequence or float or None, optional
        Image widths in data coordinate units.
    height : sequence or float or None, optional
        Image heights in data coordinate units.
    framed : sequence of bool or bool, optional
        Whether to draw a border around each image. Default False.
    frame_colors : sequence of str or str, optional
        Border colors. Default ``"black"``.
    """
    self._image_manager.add_image_series_in_plot(
        img_paths,
        margins=self.margins,
        figsize=self.figsize,
        path_data=self._path_manager.path_data,
        number_mpl_objects=self._number_manager.mpl_objects,
        xlabel_mpl_objects=self._style_manager.mpl_objects.x_labels,
        path_mpl_objects=self._path_manager.mpl_objects,
        img_x_places=img_x_places,
        y_placement=y_placement,
        y_offsets=y_offsets,
        img_series_name=img_series_name,
        width=width,
        height=height,
        framed=framed,
        frame_colors=frame_colors,
    )
    return self

add_numbers_auto(x_min_max=None, fontsize=None, n_decimals=0)

Annotate energy levels with automatically placed labels.

Chooses label placement (above which bar) automatically for each energy state to minimize visual clutter, taking into account the relative positions of all paths. Paths where show_numbers=False was passed to :meth:draw_path are excluded from numbering.

Parameters:

Name Type Description Default
x_min_max tuple of float, list of float, float, or None

Restricts annotation to energy states within the interval [x_min, x_max]. Supply a two-element sequence, a single float for an exact match, or None for all states. Default is None.

None
fontsize int or None

Font size for the annotations. When None the diagram's base font size is used. Default is None.

None
n_decimals int

Number of decimal places to show for the energy values. Default is 0.

0

Returns:

Type Description
EnergyDiagram

Returns self to allow method chaining.

Source code in src/chemdiagrams/energy_diagram.py
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
def add_numbers_auto(
    self,
    x_min_max: tuple[float, float] | list[float] | float | None = None,
    fontsize: int | None = None,
    n_decimals: int = 0,
) -> EnergyDiagram:
    """Annotate energy levels with automatically placed labels.

    Chooses label placement (above which bar) automatically
    for each energy state to minimize visual clutter, taking into
    account the relative positions of all paths. Paths
    where ``show_numbers=False`` was passed to :meth:`draw_path`
    are excluded from numbering.

    Parameters
    ----------
    x_min_max : tuple of float, list of float, float, or None, optional
        Restricts annotation to energy states within the interval
        ``[x_min, x_max]``. Supply a two-element sequence, a
        single float for an exact match, or None for all states.
        Default is None.
    fontsize : int or None, optional
        Font size for the annotations. When None the diagram's
        base font size is used. Default is None.
    n_decimals : int, optional
        Number of decimal places to show for the energy values.
        Default is 0.

    Returns
    -------
    EnergyDiagram
        Returns *self* to allow method chaining.
    """
    self._number_manager.add_numbers_auto(
        self._path_manager.path_data,
        self.margins,
        self.figsize,
        path_mpl_objects=self._path_manager.mpl_objects,
        x_min_max=x_min_max,
        fontsize=fontsize,
        n_decimals=n_decimals,
    )
    if self._image_manager.has_image_series:
        self._image_manager.recalculate_image_series(
            self.margins,
            self.figsize,
            self._path_manager.path_data,
            self._number_manager.mpl_objects,
            self._style_manager.mpl_objects.x_labels,
            self._path_manager.mpl_objects,
        )
    return self

add_numbers_average(x_min_max=None, fontsize=None, color='black', n_decimals=0)

Annotate energy states with the average value across all paths.

At each x-position the mean energy of all visible paths is computed and a single label is rendered. This is useful when multiple paths are close together and a single representative value is preferred over individual labels. Paths where show_numbers=False was passed to :meth:draw_path are excluded from the average.

Parameters:

Name Type Description Default
x_min_max tuple of float, list of float, float, or None

Restricts annotation to energy states within the interval [x_min, x_max]. Supply a two-element sequence, a single float for an exact match, or None for all states. Default is None.

None
fontsize int or None

Font size for the annotations. When None the diagram's base font size is used. Default is None.

None
color str

Color of the annotation text. Default is "black".

'black'

Returns:

Type Description
EnergyDiagram

Returns self to allow method chaining.

Source code in src/chemdiagrams/energy_diagram.py
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
def add_numbers_average(
    self,
    x_min_max: tuple[float, float] | list[float] | float | None = None,
    fontsize: int | None = None,
    color: str = "black",
    n_decimals: int = 0,
) -> EnergyDiagram:
    """Annotate energy states with the average value across all paths.

    At each x-position the mean energy of all visible paths is
    computed and a single label is rendered. This is useful when
    multiple paths are close together and a single representative
    value is preferred over individual labels. Paths where
    ``show_numbers=False`` was passed to :meth:`draw_path` are
    excluded from the average.

    Parameters
    ----------
    x_min_max : tuple of float, list of float, float, or None, optional
        Restricts annotation to energy states within the interval
        ``[x_min, x_max]``. Supply a two-element sequence, a
        single float for an exact match, or None for all states.
        Default is None.
    fontsize : int or None, optional
        Font size for the annotations. When None the diagram's
        base font size is used. Default is None.
    color : str, optional
        Color of the annotation text. Default is ``"black"``.

    Returns
    -------
    EnergyDiagram
        Returns *self* to allow method chaining.
    """
    self._number_manager.add_numbers_average(
        self._path_manager.path_data,
        self.margins,
        self.figsize,
        x_min_max=x_min_max,
        fontsize=fontsize,
        color=color,
        n_decimals=n_decimals,
    )
    if self._image_manager.has_image_series:
        self._image_manager.recalculate_image_series(
            self.margins,
            self.figsize,
            self._path_manager.path_data,
            self._number_manager.mpl_objects,
            self._style_manager.mpl_objects.x_labels,
            self._path_manager.mpl_objects,
        )
    return self

add_numbers_naive(x_min_max=None, fontsize=None, n_decimals=0)

Annotate energy levels with their values, placed directly above each bar.

This is the simplest numbering strategy: each energy value is printed at its x-position, just above the corresponding horizontal bar, with no attempt to resolve overlapping labels. Paths where show_numbers=False was passed to :meth:draw_path are excluded.

Parameters:

Name Type Description Default
x_min_max tuple of float, list of float, float, or None

Restricts annotation to energy states whose x-coordinate falls within the interval [x_min, x_max]. Supply a two-element sequence for an interval, a single float to annotate only the state at that exact x-value, or None to annotate all states. Default is None.

None
fontsize int or None

Font size for the annotations. When None the diagram's base font size is used. Default is None.

None
n_decimals int

Number of decimal places to show for the energy values. Default is 0.

0

Returns:

Type Description
EnergyDiagram

Returns self to allow method chaining.

Source code in src/chemdiagrams/energy_diagram.py
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
def add_numbers_naive(
    self,
    x_min_max: tuple[float, float] | list[float] | float | None = None,
    fontsize: int | None = None,
    n_decimals: int = 0,
) -> EnergyDiagram:
    """Annotate energy levels with their values, placed directly above each bar.

    This is the simplest numbering strategy: each energy value is
    printed at its x-position, just above the corresponding
    horizontal bar, with no attempt to resolve overlapping labels.
    Paths where ``show_numbers=False`` was passed to
    :meth:`draw_path` are excluded.

    Parameters
    ----------
    x_min_max : tuple of float, list of float, float, or None, optional
        Restricts annotation to energy states whose x-coordinate
        falls within the interval ``[x_min, x_max]``.  Supply a
        two-element sequence for an interval, a single float to
        annotate only the state at that exact x-value, or None to
        annotate all states. Default is None.
    fontsize : int or None, optional
        Font size for the annotations. When None the diagram's
        base font size is used. Default is None.
    n_decimals : int, optional
        Number of decimal places to show for the energy values.
        Default is 0.

    Returns
    -------
    EnergyDiagram
        Returns *self* to allow method chaining.
    """
    self._number_manager.add_numbers_naive(
        self._path_manager.path_data,
        self.margins,
        self.figsize,
        x_min_max,
        fontsize=fontsize,
        n_decimals=n_decimals,
    )
    if self._image_manager.has_image_series:
        self._image_manager.recalculate_image_series(
            self.margins,
            self.figsize,
            self._path_manager.path_data,
            self._number_manager.mpl_objects,
            self._style_manager.mpl_objects.x_labels,
            self._path_manager.mpl_objects,
        )
    return self

add_numbers_stacked(x_min_max=None, fontsize=None, sort_by_energy=True, no_overlap_with_nonnumbered=True, n_decimals=0)

Annotate energy levels with stacked labels above the highest state.

When multiple paths share the same x-position the labels are arranged vertically (stacked) so they do not collide. Paths where show_numbers=False was passed to :meth:draw_path are excluded from numbering but, unless no_overlap_with_nonnumbered is False, their energy bars are still treated as obstacles that stacked labels must avoid.

Parameters:

Name Type Description Default
x_min_max tuple of float, list of float, float, or None

Restricts annotation to energy states within the interval [x_min, x_max]. Supply a two-element sequence, a single float for an exact match, or None for all states. Default is None.

None
fontsize int or None

Font size for the annotations. When None the diagram's base font size is used. Default is None.

None
sort_by_energy bool

If True, labels at the same x-position are sorted by energy value before stacking, keeping them in order. Default is True.

True
no_overlap_with_nonnumbered bool

If True, labels are also offset to avoid colliding with energy bars belonging to paths that have show_numbers=False. Default is True.

True
n_decimals int

Number of decimal places to show for the energy values. Default is 0.

0

Returns:

Type Description
EnergyDiagram

Returns self to allow method chaining.

Source code in src/chemdiagrams/energy_diagram.py
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
def add_numbers_stacked(
    self,
    x_min_max: tuple[float, float] | list[float] | float | None = None,
    fontsize: int | None = None,
    sort_by_energy: bool = True,
    no_overlap_with_nonnumbered: bool = True,
    n_decimals: int = 0,
) -> EnergyDiagram:
    """Annotate energy levels with stacked labels above the highest state.

    When multiple paths share the same x-position the labels are
    arranged vertically (stacked) so they do not collide. Paths
    where ``show_numbers=False`` was passed to :meth:`draw_path`
    are excluded from numbering but, unless ``no_overlap_with_nonnumbered``
    is False, their energy bars are still treated as obstacles that
    stacked labels must avoid.

    Parameters
    ----------
    x_min_max : tuple of float, list of float, float, or None, optional
        Restricts annotation to energy states within the interval
        ``[x_min, x_max]``. Supply a two-element sequence, a
        single float for an exact match, or None for all states.
        Default is None.
    fontsize : int or None, optional
        Font size for the annotations. When None the diagram's
        base font size is used. Default is None.
    sort_by_energy : bool, optional
        If True, labels at the same x-position are sorted by
        energy value before stacking, keeping them in order.
        Default is True.
    no_overlap_with_nonnumbered : bool, optional
        If True, labels are also offset to avoid colliding with
        energy bars belonging to paths that have ``show_numbers=False``.
        Default is True.
    n_decimals : int, optional
        Number of decimal places to show for the energy values.
        Default is 0.

    Returns
    -------
    EnergyDiagram
        Returns *self* to allow method chaining.
    """
    self._number_manager.add_numbers_stacked(
        self._path_manager.path_data,
        self.margins,
        self.figsize,
        self._path_manager.mpl_objects,
        x_min_max,
        fontsize=fontsize,
        sort_by_energy=sort_by_energy,
        no_overlap_with_nonnumbered=no_overlap_with_nonnumbered,
        n_decimals=n_decimals,
    )
    if self._image_manager.has_image_series:
        self._image_manager.recalculate_image_series(
            self.margins,
            self.figsize,
            self._path_manager.path_data,
            self._number_manager.mpl_objects,
            self._style_manager.mpl_objects.x_labels,
            self._path_manager.mpl_objects,
        )
    return self

add_path_labels(path_name, labels, fontsize=None, weight='normal', color=None)

Add text labels below the energy levels of a specific path.

Parameters:

Name Type Description Default
path_name str

Name of the path to which the labels should be added.

required
labels sequence of str

A sequence of text labels, one for each energy level in the path. If None is passed for a label, no label is drawn for that level. Must have the same length as the number of energy levels in the path.

required
fontsize int or None

Font size for the labels. When None the diagram's base font size is used. Default is None.

None
weight str

Font weight for the labels, e.g. "bold" or "normal". Default is "normal".

'normal'
color str or None

Color for the labels. When None, uses the same color as the path. Default is None.

None

Returns:

Type Description
EnergyDiagram

Returns self to allow method chaining.

Raises:

Type Description
ValueError

If the specified path does not exist or if the number of labels does not match the number of energy levels in the path.

Source code in src/chemdiagrams/energy_diagram.py
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
def add_path_labels(
    self,
    path_name: str,
    labels: Sequence[str],
    fontsize: int | None = None,
    weight: str = "normal",
    color: str | None = None,
) -> EnergyDiagram:
    """Add text labels below the energy levels of a specific path.

    Parameters
    ----------
    path_name : str
        Name of the path to which the labels should be added.
    labels : sequence of str
        A sequence of text labels, one for each energy level in the path.
        If None is passed for a label, no label is drawn for that level.
        Must have the same length as the number of energy levels in the path.
    fontsize : int or None, optional
        Font size for the labels. When None the diagram's base font size
        is used. Default is None.
    weight : str, optional
        Font weight for the labels, e.g. ``"bold"`` or ``"normal"``.
        Default is ``"normal"``.
    color : str or None, optional
        Color for the labels. When None, uses the same color as the path.
        Default is None.

    Returns
    -------
    EnergyDiagram
        Returns *self* to allow method chaining.

    Raises
    ------
    ValueError
        If the specified path does not exist or if the number of labels
        does not match the number of energy levels in the path.
    """
    self._path_manager.add_path_labels(
        margins=self.margins,
        figsize=self.figsize,
        path_name=path_name,
        labels=labels,
        fontsize=fontsize,
        weight=weight,
        color=color,
    )
    if self._image_manager.has_image_series:
        self._image_manager.recalculate_image_series(
            self.margins,
            self.figsize,
            self._path_manager.path_data,
            self._number_manager.mpl_objects,
            self._style_manager.mpl_objects.x_labels,
            self._path_manager.mpl_objects,
        )
    if self._number_manager.numberings_added:
        self._number_manager._recalculate_numbers(
            path_data=self._path_manager.path_data,
            margins=self.margins,
            figsize=self.figsize,
            path_mpl_objects=self._path_manager.mpl_objects,
        )
    return self

add_xaxis_break(x, gap_scale=1, stopper_scale=1, angle=30)

Add a break marker on the x-axis at a given position.

Draws a pair of diagonal stopper lines over a white gap rectangle on the x-axis (or axes spine) to indicate a discontinuity in the x scale.

Not compatible with the "open" diagram style.

Parameters:

Name Type Description Default
x float

Position along the x-axis (in data coordinates) where the break should be placed.

required
gap_scale float

Multiplicative scaling factor for the width of the white gap that covers the axis spine. Default is 1.

1
stopper_scale float

Multiplicative scaling factor for the size of the diagonal stopper tick marks. Default is 1.

1
angle float

Angle of the stopper tick marks in degrees from the vertical. Default is 30.

30
Source code in src/chemdiagrams/energy_diagram.py
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
def add_xaxis_break(
    self,
    x: float,
    gap_scale: float = 1,
    stopper_scale: float = 1,
    angle: float = 30,
) -> None:
    """Add a break marker on the x-axis at a given position.

    Draws a pair of diagonal stopper lines over a white gap rectangle on
    the x-axis (or axes spine) to indicate a discontinuity in the x scale.

    Not compatible with the ``"open"`` diagram style.

    Parameters
    ----------
    x : float
        Position along the x-axis (in data coordinates) where the break
        should be placed.
    gap_scale : float, optional
        Multiplicative scaling factor for the width of the white gap that
        covers the axis spine. Default is ``1``.
    stopper_scale : float, optional
        Multiplicative scaling factor for the size of the diagonal stopper
        tick marks. Default is ``1``.
    angle : float, optional
        Angle of the stopper tick marks in degrees from the vertical.
        Default is ``30``.
    """
    self._style_manager.add_xaxis_break(
        margins=self.margins,
        figsize=self.figsize,
        x=x,
        gap_scale=gap_scale,
        stopper_scale=stopper_scale,
        angle=angle,
    )

add_yaxis_break(y, gap_scale=1, stopper_scale=1, angle=30)

Add a break marker on the y-axis at a given position.

Draws a pair of diagonal stopper lines over a white gap rectangle on the y-axis spine to indicate a discontinuity in the y scale.

Parameters:

Name Type Description Default
y float

Position along the y-axis (in data coordinates) where the break should be placed.

required
gap_scale float

Multiplicative scaling factor for the height of the white gap that covers the axis spine. Default is 1.

1
stopper_scale float

Multiplicative scaling factor for the size of the diagonal stopper tick marks. Default is 1.

1
angle float

Angle of the stopper tick marks in degrees from the horizontal. Default is 30.

30
Source code in src/chemdiagrams/energy_diagram.py
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
def add_yaxis_break(
    self,
    y: float,
    gap_scale: float = 1,
    stopper_scale: float = 1,
    angle: float = 30,
) -> None:
    """Add a break marker on the y-axis at a given position.

    Draws a pair of diagonal stopper lines over a white gap rectangle on
    the y-axis spine to indicate a discontinuity in the y scale.

    Parameters
    ----------
    y : float
        Position along the y-axis (in data coordinates) where the break
        should be placed.
    gap_scale : float, optional
        Multiplicative scaling factor for the height of the white gap that
        covers the axis spine. Default is ``1``.
    stopper_scale : float, optional
        Multiplicative scaling factor for the size of the diagonal stopper
        tick marks. Default is ``1``.
    angle : float, optional
        Angle of the stopper tick marks in degrees from the horizontal.
        Default is ``30``.
    """
    self._style_manager.add_yaxis_break(
        margins=self.margins,
        figsize=self.figsize,
        y=y,
        gap_scale=gap_scale,
        stopper_scale=stopper_scale,
        angle=angle,
    )

draw_difference_bar(x, y_start_end, description, diff=None, left_side=False, add_difference=True, n_decimals=0, fontsize=None, color='black', arrowstyle='|-|', x_whiskers=(None, None), whiskercolor=None)

Draw a vertical energy difference bar between two energy levels.

Renders a double-headed arrow that spans from one energy level to another at a given x-position, with a text label showing the energy difference - the latter being calculated automatically. Optional horizontal whiskers can be drawn from the energy levels to the bar.

Parameters:

Name Type Description Default
x float

The x-coordinate at which to draw the bar.

required
y_start_end tuple of float or list of float

A two-element sequence (y_start, y_end) specifying the bottom and top energy values spanned by the bar.

required
description str

Text label placed beside the bar, typically the energy difference symbol (e.g. "ΔE: ").

required
diff float or None

Horizontal offset in data coordinates between the bar and its text label. When None the offset is computed automatically based on the figure width. Default is None.

None
left_side bool

If True the bar and label are placed to the left of x instead of to the right. Default is False.

False
add_difference bool

If True, the difference between y_start and y_end gets automatically added to the description. Default is True.

True
n_decimals int

Number of decimal places to show for the energy difference. Default is 0.

0
fontsize int or None

Font size for the description label. When None the diagram's base font size is used. Default is None.

None
color str

Color of the difference bar. Default is "black".

'black'
arrowstyle str

Matplotlib arrow style string for the double-headed arrow. Default is "|-|".

'|-|'
x_whiskers tuple or list of float or None

A two-element sequence (x_bottom, x_top) giving the starting x-coordinates for optional horizontal whisker lines drawn from the bottom and top energy levels to the bar. Use None for either element to omit that whisker. Default is (None, None).

(None, None)
whiskercolor str or None

Color of the whisker lines. When None the whiskers use the same color as the bar. Default is None.

None

Returns:

Type Description
EnergyDiagram

Returns self to allow method chaining.

Source code in src/chemdiagrams/energy_diagram.py
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
def draw_difference_bar(
    self,
    x: float,
    y_start_end: tuple[float, float] | list[float],
    description: str,
    diff: float | None = None,
    left_side: bool = False,
    add_difference: bool = True,
    n_decimals: int = 0,
    fontsize: int | None = None,
    color: str = "black",
    arrowstyle: str = "|-|",
    x_whiskers: Sequence[float | None] = (None, None),
    whiskercolor: str | None = None,
) -> EnergyDiagram:
    """Draw a vertical energy difference bar between two energy levels.

    Renders a double-headed arrow that spans from one energy level
    to another at a given x-position, with a text label showing
    the energy difference - the latter being calculated automatically.
    Optional horizontal whiskers can be drawn from the energy
    levels to the bar.

    Parameters
    ----------
    x : float
        The x-coordinate at which to draw the bar.
    y_start_end : tuple of float or list of float
        A two-element sequence ``(y_start, y_end)`` specifying the
        bottom and top energy values spanned by the bar.
    description : str
        Text label placed beside the bar, typically the energy
        difference symbol (e.g. ``"ΔE: "``).
    diff : float or None, optional
        Horizontal offset in data coordinates between the bar and
        its text label. When None the offset is computed
        automatically based on the figure width. Default is None.
    left_side : bool, optional
        If True the bar and label are placed to the left of ``x``
        instead of to the right. Default is False.
    add_difference: bool, optional
        If True, the difference between y_start and y_end
        gets automatically added to the description. Default
        is True.
    n_decimals : int, optional
        Number of decimal places to show for the energy difference.
        Default is 0.
    fontsize : int or None, optional
        Font size for the description label. When None the
        diagram's base font size is used. Default is None.
    color : str, optional
        Color of the difference bar. Default is ``"black"``.
    arrowstyle : str, optional
        Matplotlib arrow style string for the double-headed arrow.
        Default is ``"|-|"``.
    x_whiskers : tuple or list of float or None, optional
        A two-element sequence ``(x_bottom, x_top)`` giving the
        starting x-coordinates for optional horizontal whisker
        lines drawn from the bottom and top energy levels to the
        bar. Use None for either element to omit that whisker.
        Default is ``(None, None)``.
    whiskercolor : str or None, optional
        Color of the whisker lines. When None the whiskers use the
        same color as the bar. Default is None.

    Returns
    -------
    EnergyDiagram
        Returns *self* to allow method chaining.
    """
    self._bar_manager.draw_difference_bar(
        x,
        y_start_end,
        description,
        self.margins,
        self.figsize,
        diff=diff,
        left_side=left_side,
        add_difference=add_difference,
        n_decimals=n_decimals,
        fontsize=fontsize,
        color=color,
        arrowstyle=arrowstyle,
        x_whiskers=x_whiskers,
        whiskercolor=whiskercolor,
    )
    return self

draw_path(x_data, y_data, color, linetypes=None, path_name=None, show_numbers=True, width_plateau=None, lw_plateau='plateau', lw_connector='connector', gap_scale=1)

Add a reaction path to the energy diagram.

Draws a series of horizontal energy levels connected by transitions. Each segment between adjacent levels is drawn with the connector style specified by linetypes.

Parameters:

Name Type Description Default
x_data sequence of float

X-coordinates for each reaction state (energy level). Must have the same length as y_data.

required
y_data sequence of float

Y-coordinates (energy values) for each reaction state. Must have the same length as x_data.

required
color str

Color of the energy levels and connectors for this path, as any Matplotlib color string (e.g. "blue", "#FF5733").

required
linetypes sequence of int or int or None

Connector style(s) for the segments between consecutive energy levels. Must have length len(x_data) - 1, or be a single integer applied to all segments. Allowed values:

  • 0 : no connector
  • 1 : dotted line (default)
  • -1 : broken dotted line
  • 2 : solid line
  • -2 : broken solid line
  • 3 : dotted cubic spline
  • -3 : broken dotted cubic spline
  • 4 : solid cubic spline
  • -4 : broken solid cubic spline

When None, all segments use a dotted line (1).

None
path_name str or None

A name for this path used as the legend label. When None the path is not added to the legend. Default is None.

None
show_numbers bool

If False, energy values along this path are excluded from any subsequent add_numbers_* calls. Default is True.

True
width_plateau float or None

Width of the horizontal energy level bars in data coordinate units. When None, a default width is applied. Default is None.

None
lw_plateau (float, str)

Line width for the horizontal energy level bars. Can be a float in points, or a string referring to a predefined value ("plateau" or "connector"). Default is "plateau".

'plateau'
lw_connector (float, str)

Line width for the connectors between energy levels. Can be a float in points, or a string referring to a predefined value ("plateau" or "connector"). Default is "connector".

'connector'
gap_scale float, int, or sequence of float or int

Scaling factor for the gap in broken line styles (-4 to -1). Can be a single number applied to all segments, or a sequence with one value per segment. Default is 1.

1

Returns:

Type Description
EnergyDiagram

Returns self to allow method chaining.

Source code in src/chemdiagrams/energy_diagram.py
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
def draw_path(
    self,
    x_data: Sequence[float],
    y_data: Sequence[float],
    color: str,
    linetypes: Sequence[int] | None = None,
    path_name: str | None = None,
    show_numbers: bool = True,
    width_plateau: float | None = None,
    lw_plateau: float | str = "plateau",
    lw_connector: float | str = "connector",
    gap_scale: float | int | Sequence[float | int] = 1,
) -> EnergyDiagram:
    """Add a reaction path to the energy diagram.

    Draws a series of horizontal energy levels connected by
    transitions. Each segment between adjacent levels is drawn
    with the connector style specified by ``linetypes``.

    Parameters
    ----------
    x_data : sequence of float
        X-coordinates for each reaction state (energy level).
        Must have the same length as ``y_data``.
    y_data : sequence of float
        Y-coordinates (energy values) for each reaction state.
        Must have the same length as ``x_data``.
    color : str
        Color of the energy levels and connectors for this path,
        as any Matplotlib color string (e.g. ``"blue"``,
        ``"#FF5733"``).
    linetypes : sequence of int or int or None, optional
        Connector style(s) for the segments between consecutive
        energy levels. Must have length ``len(x_data) - 1``, or
        be a single integer applied to all segments. Allowed
        values:

        *  ``0``  : no connector
        *  ``1``  : dotted line (default)
        *  ``-1`` : broken dotted line
        *  ``2``  : solid line
        *  ``-2`` : broken solid line
        *  ``3``  : dotted cubic spline
        *  ``-3`` : broken dotted cubic spline
        *  ``4``  : solid cubic spline
        *  ``-4`` : broken solid cubic spline

        When None, all segments use a dotted line (``1``).
    path_name : str or None, optional
        A name for this path used as the legend label. When None
        the path is not added to the legend. Default is None.
    show_numbers : bool, optional
        If False, energy values along this path are excluded from
        any subsequent ``add_numbers_*`` calls. Default is True.
    width_plateau : float or None, optional
        Width of the horizontal energy level bars in data coordinate
        units. When None, a default width is applied. Default is None.
    lw_plateau : float, str, optional
        Line width for the horizontal energy level bars. Can be a
        float in points, or a string referring to a predefined
        value (``"plateau"`` or ``"connector"``). Default is ``"plateau"``.
    lw_connector : float, str, optional
        Line width for the connectors between energy levels. Can be a
        float in points, or a string referring to a predefined
        value (``"plateau"`` or ``"connector"``). Default is ``"connector"``.
    gap_scale : float, int, or sequence of float or int, optional
        Scaling factor for the gap in broken line styles (``-4`` to ``-1``).
        Can be a single number applied to all segments, or a
        sequence with one value per segment. Default is 1.

    Returns
    -------
    EnergyDiagram
        Returns *self* to allow method chaining.
    """
    self._path_manager.draw_path(
        x_data,
        y_data,
        color,
        linetypes=linetypes,
        path_name=path_name,
        show_numbers=show_numbers,
        width_plateau=width_plateau,
        lw_plateau=lw_plateau,
        lw_connector=lw_connector,
        gap_scale=gap_scale,
    )
    self.margins = self._layout_manager.adjust_xy_limits(self._path_manager.path_data)
    self.figsize = self._layout_manager.scale_figure(self._path_manager.path_data)
    self._recalculate_xlabels()
    self._recalculate_axis_breaks()
    self._recalculate_merged_plateaus()
    self._recalculate_path_labels()
    return self

legend(loc='best', fontsize=None)

Add a legend for all named reaction paths.

Generates legend entries for every path that was drawn with a path_name. Each entry shows a colored patch matching the path color and the corresponding name.

Parameters:

Name Type Description Default
loc str

Legend location, as any Matplotlib loc string (e.g. "best", "upper right"). Default is "best".

'best'
fontsize int or None

Font size of the legend text. When None the diagram's base font size is used. Default is None.

None

Returns:

Type Description
EnergyDiagram

Returns self to allow method chaining.

Source code in src/chemdiagrams/energy_diagram.py
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
def legend(self, loc: str = "best", fontsize: int | None = None) -> EnergyDiagram:
    """Add a legend for all named reaction paths.

    Generates legend entries for every path that was drawn with a
    ``path_name``. Each entry shows a colored patch matching the
    path color and the corresponding name.

    Parameters
    ----------
    loc : str, optional
        Legend location, as any Matplotlib ``loc`` string
        (e.g. ``"best"``, ``"upper right"``). Default is
        ``"best"``.
    fontsize : int or None, optional
        Font size of the legend text. When None the diagram's base
        font size is used. Default is None.

    Returns
    -------
    EnergyDiagram
        Returns *self* to allow method chaining.
    """
    Validators.validate_number(fontsize, "fontsize", allow_none=True, min_value=0)
    if fontsize is None:
        fontsize = self._figure_manager.fontsize
    patches = []
    for path_name, path_info in self._path_manager.path_data.items():
        if path_info["has_name"]:
            patches.append(mpatches.Patch(color=path_info["color"], label=path_name))
    self._figure_manager.ax.legend(handles=patches, fontsize=fontsize, loc=loc)
    return self

merge_plateaus(x, path_name_left, path_name_right, gap_scale=1, stopper_scale=1, angle=30)

Visually merge two coincident plateaus at a shared x-position.

When two paths have identical energy levels at the same x-coordinate, this method replaces both full-width plateaus with two shorter half-plateaus separated by a small gap. Diagonal stopper tick marks are drawn into the gap to indicate that the two levels are degenerate. The resulting split is recalculated automatically whenever a new path is added.

Both paths must already exist and must have the same y-value at x.

Parameters:

Name Type Description Default
x int

The x-coordinate at which both paths share an energy level.

required
path_name_left str

Name of the path whose plateau will appear on the left side of the gap.

required
path_name_right str

Name of the path whose plateau will appear on the right side of the gap.

required
gap_scale float

Multiplicative scaling factor for the width of the gap between the two half-plateaus. Default is 1.

1
stopper_scale float

Multiplicative scaling factor for the size of the diagonal stopper tick marks drawn in the gap. Default is 1.

1
angle float

Angle of the stopper tick marks in degrees from the vertical. Default is 30.

30

Returns:

Type Description
EnergyDiagram

Returns self to allow method chaining.

Raises:

Type Description
ValueError

If either path does not exist, does not have a value at x, or the two paths do not share the same y-value at x.

Source code in src/chemdiagrams/energy_diagram.py
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
def merge_plateaus(
    self,
    x: int,
    path_name_left: str,
    path_name_right: str,
    gap_scale: float = 1,
    stopper_scale: float = 1,
    angle: float = 30,
) -> EnergyDiagram:
    """Visually merge two coincident plateaus at a shared x-position.

    When two paths have identical energy levels at the same x-coordinate,
    this method replaces both full-width plateaus with two shorter half-plateaus
    separated by a small gap. Diagonal stopper tick marks are drawn into the gap
    to indicate that the two levels are degenerate. The resulting split is
    recalculated automatically whenever a new path is added.

    Both paths must already exist and must have the same y-value at ``x``.

    Parameters
    ----------
    x : int
        The x-coordinate at which both paths share an energy level.
    path_name_left : str
        Name of the path whose plateau will appear on the left side of the gap.
    path_name_right : str
        Name of the path whose plateau will appear on the right side of the gap.
    gap_scale : float, optional
        Multiplicative scaling factor for the width of the gap between the two
        half-plateaus. Default is ``1``.
    stopper_scale : float, optional
        Multiplicative scaling factor for the size of the diagonal stopper tick
        marks drawn in the gap. Default is ``1``.
    angle : float, optional
        Angle of the stopper tick marks in degrees from the vertical.
        Default is ``30``.

    Returns
    -------
    EnergyDiagram
        Returns *self* to allow method chaining.

    Raises
    ------
    ValueError
        If either path does not exist, does not have a value at ``x``, or
        the two paths do not share the same y-value at ``x``.
    """
    self._path_manager.merge_plateaus(
        margins=self.margins,
        figsize=self.figsize,
        x=x,
        path_name_left=path_name_left,
        path_name_right=path_name_right,
        gap_scale=gap_scale,
        stopper_scale=stopper_scale,
        angle=angle,
    )
    return self

modify_number_values(x, base_value=0.0, x_add=None, x_subtract=None, include_paths=None, exclude_paths=None, brackets=('(', ')'), n_decimals=0)

Modify energy labels at a specific x-position by combining energy values.

This method recalculates and updates the numeric label displayed above an energy level at a given x-coordinate. The new value is computed from a base_value, plus energy levels from specified x-positions that are added or subtracted. This is useful for annotating energy differences, especially for transition states.

Parameters:

Name Type Description Default
x float

The x-coordinate (reaction state position) where the label is located and will be modified.

required
base_value float

Initial value for the calculation. The final label value is computed as: base_value + sum(energies at x_add) - sum(energies at x_subtract) for each path. Default is 0.0.

0.0
x_add float or list of float or None

X-coordinate(s) whose energy values are added to the calculated result. Can be a single float or a list of floats. Useful for summing multiple energy contributions. Default is None (no values added).

None
x_subtract float or list of float or None

X-coordinate(s) whose energy values are subtracted from the calculated result. Can be a single float or a list of floats. Useful for computing differences like reaction barriers or enthalpies. Default is None (no values subtracted).

None
include_paths list of str or None

Path names for which the label should be modified. If specified, only these paths are updated. Cannot be used with exclude_paths. Default is None (all paths are modified).

None
exclude_paths list of str or None

Path names to exclude from modification. If specified, all paths except these are updated. Cannot be used with include_paths. Default is None (all paths are modified).

None
brackets tuple of str and str or list of str or None

Characters to wrap around the numeric value as (left_bracket, right_bracket). Common choices are ("(", ")"), ("[", "]"), or ("", "") for no brackets. Default is ("(", ")").

('(', ')')
n_decimals int

Number of decimal places in the formatted label. Default is 0 (integer values).

0

Returns:

Type Description
EnergyDiagram

Returns self for method chaining.

Raises:

Type Description
ValueError

If both include_paths and exclude_paths are specified.

ValueError

If a path name in include_paths does not exist in the diagram.

UserWarning

If a requested x-value to add or subtract is not found in a path, or if a label at the specified x-position does not exist.

Examples:

Label a transition state barrier at x=1.0 by subtracting the reactant energy (x=0.0) from the transition state energy (x=1.0):

>>> diagram.modify_number_values(
...     x=1.0, x_add=[1.0], x_subtract=[0.0], brackets=["Δ‡", ""]
... )

Compute a complex energy term at x=3.0 for only specific paths:

>>> diagram.modify_number_values(
...     x=3.0,
...     base_value=10.0,
...     x_add=[1.0, 2.0],
...     x_subtract=[0.0],
...     include_paths=["pathway_A"],
...     n_decimals=2
... )
Source code in src/chemdiagrams/energy_diagram.py
 947
 948
 949
 950
 951
 952
 953
 954
 955
 956
 957
 958
 959
 960
 961
 962
 963
 964
 965
 966
 967
 968
 969
 970
 971
 972
 973
 974
 975
 976
 977
 978
 979
 980
 981
 982
 983
 984
 985
 986
 987
 988
 989
 990
 991
 992
 993
 994
 995
 996
 997
 998
 999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
def modify_number_values(
    self,
    x: float,
    base_value: float = 0.0,
    x_add: float | list[float] | None = None,
    x_subtract: float | list[float] | None = None,
    include_paths: list[str] | None = None,
    exclude_paths: list[str] | None = None,
    brackets: tuple[str, str] | list[str] | None = ("(", ")"),
    n_decimals: int = 0,
) -> EnergyDiagram:
    """
    Modify energy labels at a specific x-position by combining energy values.

    This method recalculates and updates the numeric label displayed above an
    energy level at a given x-coordinate. The new value is computed from a
    ``base_value``, plus energy levels from specified x-positions that are
    added or subtracted. This is useful for annotating energy differences,
    especially for transition states.

    Parameters
    ----------
    x : float
        The x-coordinate (reaction state position) where the label is located
        and will be modified.
    base_value : float, optional
        Initial value for the calculation. The final label value is computed as:
        ``base_value + sum(energies at x_add) - sum(energies at x_subtract)``
        for each path. Default is 0.0.
    x_add : float or list of float or None, optional
        X-coordinate(s) whose energy values are added to the calculated result.
        Can be a single float or a list of floats. Useful for summing multiple
        energy contributions. Default is None (no values added).
    x_subtract : float or list of float or None, optional
        X-coordinate(s) whose energy values are subtracted from the calculated
        result. Can be a single float or a list of floats. Useful for computing
        differences like reaction barriers or enthalpies. Default is None
        (no values subtracted).
    include_paths : list of str or None, optional
        Path names for which the label should be modified. If specified,
        only these paths are updated. Cannot be used with ``exclude_paths``.
        Default is None (all paths are modified).
    exclude_paths : list of str or None, optional
        Path names to exclude from modification. If specified, all paths
        except these are updated. Cannot be used with ``include_paths``.
        Default is None (all paths are modified).
    brackets : tuple of str and str or list of str or None, optional
        Characters to wrap around the numeric value as (left_bracket,
        right_bracket). Common choices are ``("(", ")")``, ``("[", "]")``,
        or ``("", "")`` for no brackets. Default is ``("(", ")")``.
    n_decimals : int, optional
        Number of decimal places in the formatted label. Default is 0
        (integer values).

    Returns
    -------
    EnergyDiagram
        Returns ``self`` for method chaining.

    Raises
    ------
    ValueError
        If both ``include_paths`` and ``exclude_paths`` are specified.
    ValueError
        If a path name in ``include_paths`` does not exist in the diagram.
    UserWarning
        If a requested x-value to add or subtract is not found in a path,
        or if a label at the specified x-position does not exist.

    Examples
    --------
    Label a transition state barrier at x=1.0 by subtracting the reactant
    energy (x=0.0) from the transition state energy (x=1.0):

    >>> diagram.modify_number_values(
    ...     x=1.0, x_add=[1.0], x_subtract=[0.0], brackets=["Δ‡", ""]
    ... )

    Compute a complex energy term at x=3.0 for only specific paths:

    >>> diagram.modify_number_values(
    ...     x=3.0,
    ...     base_value=10.0,
    ...     x_add=[1.0, 2.0],
    ...     x_subtract=[0.0],
    ...     include_paths=["pathway_A"],
    ...     n_decimals=2
    ... )
    """
    self._number_manager.modify_number_values(
        path_data=self._path_manager.path_data,
        x=x,
        base_value=base_value,
        x_add=x_add,
        x_subtract=x_subtract,
        include_paths=include_paths,
        exclude_paths=exclude_paths,
        brackets=brackets,
        n_decimals=n_decimals,
    )
    return self

set_diagram_style(style)

Change the overall visual style of the diagram.

Applies a named style preset that controls the appearance of the plot background, spines, tick marks, and other decorative elements.

Parameters:

Name Type Description Default
style str

Name of the style preset to apply. Supported values are "boxed", "halfboxed", "open", "twosided" and "borderless". Default style is "open".

required

Returns:

Type Description
EnergyDiagram

Returns self to allow method chaining.

Source code in src/chemdiagrams/energy_diagram.py
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
def set_diagram_style(self, style: str) -> EnergyDiagram:
    """Change the overall visual style of the diagram.

    Applies a named style preset that controls the appearance of
    the plot background, spines, tick marks, and other decorative
    elements.

    Parameters
    ----------
    style : str
        Name of the style preset to apply. Supported values
        are ``"boxed"``, ``"halfboxed"``, ``"open"``, ``"twosided"``
        and ``"borderless"``. Default style is ``"open"``.

    Returns
    -------
    EnergyDiagram
        Returns *self* to allow method chaining.
    """
    self._layout_manager.adjust_xy_limits(self._path_manager.path_data)
    self._style_manager.set_diagram_style(style)
    try:
        self.set_xlabels(
            **self._style_manager.labelproperties  # type: ignore[arg-type]
        )
    except AttributeError:
        pass
    return self

set_xlabels(labels, labelplaces=None, fontsize=None, weight='bold', in_plot=False)

Set text labels for the reaction states along the x-axis.

Labels are placed below the horizontal energy bars by default. If in_plot is True they are rendered inside the plot area directly below the lowest state.

Parameters:

Name Type Description Default
labels sequence

Ordered sequence of label strings, one per reaction state (i.e. one per unique x-position in the plotted paths).

required
labelplaces sequence of float or None

Explicit x-coordinates at which to place each label. When None the labels are naively placed starting at x = 0. Default is None.

None
fontsize int or None

Font size for the labels. When None the diagram's base font size is used. Default is None.

None
weight str

Font weight for the labels, e.g. "bold" or "normal". Default is "bold".

'bold'
in_plot bool

If True, labels are drawn inside the plot area below the lowest state rather than below the x-axis. Default is False.

False

Returns:

Type Description
EnergyDiagram

Returns self to allow method chaining.

Source code in src/chemdiagrams/energy_diagram.py
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
def set_xlabels(
    self,
    labels: Sequence,
    labelplaces: Sequence[float] | None = None,
    fontsize: int | None = None,
    weight: str = "bold",
    in_plot: bool = False,
) -> EnergyDiagram:
    """Set text labels for the reaction states along the x-axis.

    Labels are placed below the horizontal energy bars by default.
    If ``in_plot`` is True they are rendered inside the plot area
    directly below the lowest state.

    Parameters
    ----------
    labels : sequence
        Ordered sequence of label strings, one per reaction state
        (i.e. one per unique x-position in the plotted paths).
    labelplaces : sequence of float or None, optional
        Explicit x-coordinates at which to place each label.
        When None the labels are naively placed starting at
        x = 0. Default is None.
    fontsize : int or None, optional
        Font size for the labels. When None the diagram's base
        font size is used. Default is None.
    weight : str, optional
        Font weight for the labels, e.g. ``"bold"`` or
        ``"normal"``. Default is ``"bold"``.
    in_plot : bool, optional
        If True, labels are drawn inside the plot area below the
        lowest state rather than below the x-axis. Default
        is False.

    Returns
    -------
    EnergyDiagram
        Returns *self* to allow method chaining.
    """
    self._style_manager.set_xlabels(
        self.margins,
        self.figsize,
        self._path_manager.path_data,
        labels,
        labelplaces=labelplaces,
        fontsize=fontsize,
        weight=weight,
        in_plot=in_plot,
    )
    if self._image_manager.has_image_series:
        self._image_manager.recalculate_image_series(
            self.margins,
            self.figsize,
            self._path_manager.path_data,
            self._number_manager.mpl_objects,
            self._style_manager.mpl_objects.x_labels,
            self._path_manager.mpl_objects,
        )
    return self

show()

Display the energy diagram figure.

Finalizes the figure layout and calls matplotlib.pyplot.show().

Source code in src/chemdiagrams/energy_diagram.py
296
297
298
299
300
301
302
303
304
def show(self) -> None:
    """Display the energy diagram figure.

    Finalizes the figure layout and calls ``matplotlib.pyplot.show()``.
    """
    figsize = self._layout_manager.scale_figure(self._path_manager.path_data)
    if self.verbose:
        print(f"Figure size is {round(figsize[0], 2)} x {round(figsize[1], 2)} inches.")
    plt.show()