Option to draw all bonds in symbolColour. (#9304)

This commit is contained in:
David Cosgrove
2026-05-28 15:46:13 +01:00
committed by greg landrum
parent 2f9adc092f
commit 8d1eb53d4c
6 changed files with 63 additions and 23 deletions

View File

@@ -2389,7 +2389,7 @@ void DrawMol::makeWedgedBond(Bond *bond,
auto at2 = bond->getEndAtom();
auto col1 = cols.first;
auto col2 = cols.second;
if (drawOptions_.singleColourWedgeBonds) {
if (drawOptions_.singleColourWedgeBonds || drawOptions_.singleColourBonds) {
col1 = drawOptions_.symbolColour;
col2 = drawOptions_.symbolColour;
}
@@ -2574,8 +2574,12 @@ std::pair<DrawColour, DrawColour> DrawMol::getBondColours(Bond *bond) {
col2 = bondColours_[bond->getIdx()].second;
} else {
if (!highlight_bond || drawOptions_.continuousHighlight) {
col1 = getColour(bond->getBeginAtomIdx());
col2 = getColour(bond->getEndAtomIdx());
if (drawOptions_.singleColourBonds) {
col1 = col2 = drawOptions_.symbolColour;
} else {
col1 = getColour(bond->getBeginAtomIdx());
col2 = getColour(bond->getEndAtomIdx());
}
} else {
if (highlightBondMap_.find(bond->getIdx()) != highlightBondMap_.end()) {
col1 = col2 = highlightBondMap_.find(bond->getIdx())->second;

View File

@@ -322,6 +322,9 @@ struct RDKIT_MOLDRAW2D_EXPORT MolDrawOptions {
false; // if true wedged and dashed bonds are drawn
// using symbolColour rather than inheriting
// their colour from the atoms
bool singleColourBonds = false; // if true all bonds are drawn using
// symbolColour rather than inheriting their
// colour from the atoms
bool useMolBlockWedging = false; // If the molecule came from a MolBlock,
// prefer the wedging information that
// provides. If false, use RDKit rules.

View File

@@ -182,6 +182,7 @@ void updateMolDrawOptionsFromJSON(MolDrawOptions &opts,
PT_OPT_GET(simplifiedStereoGroupLabel);
PT_OPT_GET(unspecifiedStereoIsUnknown);
PT_OPT_GET(singleColourWedgeBonds);
PT_OPT_GET(singleColourBonds);
PT_OPT_GET(useMolBlockWedging);
PT_OPT_GET(scalingFactor);
PT_OPT_GET(drawMolsSameScale);
@@ -213,7 +214,8 @@ void updateMolDrawOptionsFromJSON(MolDrawOptions &opts,
const auto drawingExtentsIncludeIt = pt.find("drawingExtentsInclude");
if (drawingExtentsIncludeIt != pt.not_found()) {
bool haveDrawElementFlags = false;
auto drawingExtentsInclude = flagsFromJson<DrawElement>(drawingExtentsIncludeIt->second, &haveDrawElementFlags);
auto drawingExtentsInclude = flagsFromJson<DrawElement>(
drawingExtentsIncludeIt->second, &haveDrawElementFlags);
if (haveDrawElementFlags) {
opts.drawingExtentsInclude = drawingExtentsInclude;
}

View File

@@ -926,11 +926,10 @@ BOOST_PYTHON_MODULE(rdMolDraw2D) {
.def_readwrite(
"legendFraction", &RDKit::MolDrawOptions::legendFraction,
"fraction of the draw panel to be used for the legend if present")
.def_readwrite(
"legendPosition", &RDKit::MolDrawOptions::legendPosition,
"legend position enum. Default=Bottom. "
"Values: LegendPosition.Bottom, LegendPosition.Top, "
"LegendPosition.Left, LegendPosition.Right.")
.def_readwrite("legendPosition", &RDKit::MolDrawOptions::legendPosition,
"legend position enum. Default=Bottom. "
"Values: LegendPosition.Bottom, LegendPosition.Top, "
"LegendPosition.Left, LegendPosition.Right.")
.def_readwrite(
"legendVerticalText", &RDKit::MolDrawOptions::legendVerticalText,
"when legend is Left or Right, draw text vertically (one char per line)")
@@ -1072,6 +1071,11 @@ BOOST_PYTHON_MODULE(rdMolDraw2D) {
"if true wedged and dashed bonds are drawn using symbolColour "
"rather than inheriting their colour from the atoms. "
"Default is false.")
.def_readwrite("singleColourBonds",
&RDKit::MolDrawOptions::singleColourBonds,
"if true all bonds are drawn using symbolColour "
"rather than inheriting their colour from the atoms. "
"Default is false.")
.def_readwrite("useMolBlockWedging",
&RDKit::MolDrawOptions::useMolBlockWedging,
"If the molecule came from a MolBlock, prefer the wedging"
@@ -1203,8 +1207,8 @@ BOOST_PYTHON_MODULE(rdMolDraw2D) {
.def("FillPolys", &RDKit::MolDraw2D::fillPolys, python::args("self"),
"returns whether or not polygons are being filled")
.def("DrawLine",
(void(RDKit::MolDraw2D::*)(const Point2D &, const Point2D &, bool)) &
RDKit::MolDraw2D::drawLine,
(void (RDKit::MolDraw2D::*)(const Point2D &, const Point2D &,
bool))&RDKit::MolDraw2D::drawLine,
(python::arg("self"), python::arg("cds1"), python::arg("cds2"),
python::arg("rawCoords") = false),
"draws a line with the current drawing style. The coordinates "
@@ -1253,9 +1257,8 @@ BOOST_PYTHON_MODULE(rdMolDraw2D) {
"are in the molecule frame unless rawCoords is true, "
"in which case the coordinates are in pixels.")
.def("DrawArc",
(void(RDKit::MolDraw2D::*)(const Point2D &, double, double, double,
bool)) &
RDKit::MolDraw2D::drawArc,
(void (RDKit::MolDraw2D::*)(const Point2D &, double, double, double,
bool))&RDKit::MolDraw2D::drawArc,
(python::arg("self"), python::arg("center"), python::arg("radius"),
python::arg("angle1"), python::arg("angle2"),
python::arg("rawCoords") = false),
@@ -1284,9 +1287,9 @@ BOOST_PYTHON_MODULE(rdMolDraw2D) {
"are in the molecule frame unless rawCoords is true, "
"in which case the coordinates are in pixels.")
.def("DrawString",
(void(RDKit::MolDraw2D::*)(const std::string &,
const RDGeom::Point2D &, bool)) &
RDKit::MolDraw2D::drawString,
(void (RDKit::MolDraw2D::*)(const std::string &,
const RDGeom::Point2D &,
bool))&RDKit::MolDraw2D::drawString,
(python::arg("self"), python::arg("string"), python::arg("pos"),
python::arg("rawCoords") = false),
"add text to the canvas. The coordinates "
@@ -1301,14 +1304,14 @@ BOOST_PYTHON_MODULE(rdMolDraw2D) {
"are in the molecule frame unless rawCoords is true, "
"in which case the coordinates are in pixels.")
.def("GetDrawCoords",
(RDGeom::Point2D(RDKit::MolDraw2D::*)(const RDGeom::Point2D &)
(RDGeom::Point2D (RDKit::MolDraw2D::*)(const RDGeom::Point2D &)
const) &
RDKit::MolDraw2D::getDrawCoords,
(python::arg("self"), python::arg("point")),
"get the coordinates in drawing space for a particular point in "
"molecule space")
.def("GetDrawCoords",
(RDGeom::Point2D(RDKit::MolDraw2D::*)(int) const) &
(RDGeom::Point2D (RDKit::MolDraw2D::*)(int) const) &
RDKit::MolDraw2D::getDrawCoords,
(python::arg("self"), python::arg("atomIndex")),
"get the coordinates in drawing space for a particular atom")
@@ -1338,7 +1341,7 @@ BOOST_PYTHON_MODULE(rdMolDraw2D) {
python::args("self"),
"add the last bits of SVG to finish the drawing")
.def("AddMoleculeMetadata",
(void(RDKit::MolDraw2DSVG::*)(const RDKit::ROMol &, int) const) &
(void (RDKit::MolDraw2DSVG::*)(const RDKit::ROMol &, int) const) &
RDKit::MolDraw2DSVG::addMoleculeMetadata,
((python::arg("self"), python::arg("mol")),
python::arg("confId") = -1),
@@ -1591,10 +1594,9 @@ https://en.wikipedia.org/wiki/Wikipedia:Manual_of_Style/Chemistry/Structure_draw
(python::arg("mol"), python::arg("confId") = -1),
"Calculate the mean bond length for the molecule.");
python::def("SetDarkMode",
(void (*)(RDKit::MolDrawOptions &)) & RDKit::setDarkMode,
(void (*)(RDKit::MolDrawOptions &))&RDKit::setDarkMode,
python::args("d2d"), "set dark mode for a MolDrawOptions object");
python::def("SetDarkMode",
(void (*)(RDKit::MolDraw2D &)) & RDKit::setDarkMode,
python::def("SetDarkMode", (void (*)(RDKit::MolDraw2D &))&RDKit::setDarkMode,
python::args("d2d"), "set dark mode for a MolDraw2D object");
python::def("SetMonochromeMode", RDKit::setMonochromeMode_helper1,
(python::arg("options"), python::arg("fgColour"),

View File

@@ -891,6 +891,7 @@ M END''')
d2d.drawOptions().addAtomIndices = True
d2d.drawOptions().addBondIndices = True
d2d.drawOptions().singleColourWedgeBonds = True # test symbolColour
d2d.drawOptions().singleColourBonds = True # just test it's settable
setattr(d2d.drawOptions(), attr, val)
aval = getattr(d2d.drawOptions(), attr)
for idx in range(4):

View File

@@ -11449,4 +11449,32 @@ TEST_CASE("Github 9280 - font scaling bug") {
CHECK(text.find("font-size:6px") != std::string::npos);
check_file_hash("test_Github9280_0.2.svg");
}
}
TEST_CASE("Uniform bond colour") {
auto m1 = "F[C@@H](Cl)Oc1ccc(N2CCc3nccc(C(=O)Nc4ccccn4)c3C2)nc1"_smiles;
REQUIRE(m1);
MolDraw2DSVG drawer(400, 400, -1, -1, NO_FREETYPE);
MolDraw2DUtils::prepareMolForDrawing(*m1);
drawer.drawOptions().addBondIndices = true;
drawer.drawOptions().singleColourBonds = true;
drawer.drawMolecule(*m1);
drawer.finishDrawing();
std::string text = drawer.getDrawingText();
std::ofstream outs("testUniformBondColour_1.svg");
outs << text;
outs.close();
// Bond 2 is C-O so in normal mode would have 2 lines, a black one and a
// red one. Make sure there's only one.
const static std::regex bond2("<path class='bond-2 atom-1 atom-3'");
std::ptrdiff_t const match_count2(
std::distance(std::sregex_iterator(text.begin(), text.end(), bond2),
std::sregex_iterator()));
CHECK(match_count2 == 1);
// Bond 0 is a wedge to fluorine. Make sure it is also all black, which
// involves 1 triangle not 2.
const static std::regex bond0("<path class='bond-0 atom-1 atom-0'");
std::ptrdiff_t const match_count0(
std::distance(std::sregex_iterator(text.begin(), text.end(), bond2),
std::sregex_iterator()));
CHECK(match_count0 == 1);
}