-
Notifications
You must be signed in to change notification settings - Fork 195
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Aromatic bond visualization #455
Comments
I've done more follow up on #639, and I have a working implementation that could also be used for this feature (have not pushed the PR yet). It's a more general solution in which one can specify partial bond order of any bond to control the thickness of the remaining dashed bond. For example, instead of specifying a bond order of 2, it uses 1.7 in this example: -- However, that brings up a few questions.
In my WIP implementation, I have done it in two ways, but a more mathematical default would be superior (e.g., to somehow prioritize the "shorter" bond as dashed).
viewer.setStyle({serial: 4}, {
stick: {
radius: 0.2,
dashPriority: true,
}
});
|
I think the common convention is that the dash should be inside the ring. I personal prefer the discrete change in color halfway for the bond color. @ghutchis Do you have any opinions as a molecular visualization expert? |
Of course. My question is: can that be determined in the context of available functions or some type of vector mathematics? It seems like the vector length between from/to are identical. It also seems like it could be a bit tricky to generally solve this for cases where the dashes are used to represent transition states. EDIT: relevant section of code is here. We need to determine which cylinder should be drawn dashed. Lines 906 to 955 in b038d7b
|
I think you should be able to get it from v which is a function of the larger atomic environment. If it doesn't consistently point in the concave direction, we can probably make it (but I don't have time to look at it in detail now). |
@dkoes, any update on this? Appreciate your help! |
Sorry for delay - life and work. The most relevant function is Can you provide the structure for the transition state above? Definitely want to see this added as a test case when the WIP is done. |
thanks for the reply @dkoes. Maybe I don't understand how to use consider the case where the colors are identical, e.g. drawCyl(geo, p1a, p2a, r, C1, mfromCap, mtoCap);
drawCyl(geo, p1b, p2b, r, C1, mfromCap, mtoCap); how do I decide (from v) which bond to draw dashed? if (atom.bondOrder[i] == 2) {
r = bondR * doubleBondScale;
v.multiplyScalar(r * 1.5);
p1a = p1.clone();
p1a.add(v);
p1b = p1.clone();
p1b.sub(v);
p2a = p1a.clone();
p2a.add(dir);
p2b = p1b.clone();
p2b.add(dir);
if (C1 != C2) {
mp = new Vector3().addVectors(p1a, p2a)
.multiplyScalar(0.5);
mp2 = new Vector3().addVectors(p1b, p2b)
.multiplyScalar(0.5);
drawCyl(geo, p1a, mp, r, C1, mfromCap, 0);
drawCyl(geo, mp, p2a, r, C2, 0, mtoCap);
drawCyl(geo, p1b, mp2, r, C1, mfromCap, 0);
drawCyl(geo, mp2, p2b, r, C2, 0, mtoCap);
} else {
drawCyl(geo, p1a, p2a, r, C1, mfromCap, mtoCap);
drawCyl(geo, p1b, p2b, r, C1, mfromCap, mtoCap);
} |
If v is consistent, then p1a will either always be inside the ring or outside - so you should always draw p1a-p2a dashed and adjust the setting of v so that is the right answer (or always draw p1b-p2b). |
thanks @dkoes that was very helpful! using that insight I made some more progress. benzene is drawn properly now, and my transition state is a lot closer (2/3 bonds are correct). note that this is without adjusting the I tried to alter var score = (atom3.elem !== 'H' ? 1 : 0) + atom.bondOrder[j]; but I'm not sure how it may impact the existing calculations, and if the length should still be trusted or used. One interesting thing is that if I comment this line (e.g., to no longer return early), it actually returns a very strange result in that case -- essentially updating the bond orientation out of plane by 90 degrees. It looks pretty close with the current if(l > bestlen) {
bestlen = l;
bestv = v;
if(bestlen > 0.1) {
// return bestv; // comment this line to no longer return early
}
} Now, double-bond is rotated 90 degrees for some reason: SDF file:
|
The double bond will be in the plane defined by atom, atom2 and the atom3 that produces the bestv. You are getting a rotation because the hydrogen is being selected as the best atom3. I would skip the score and simply ignore hydrogens unless no non-hydrogen atoms produce a large enough bestv. |
So the logic for picking the best atom might something like: |
thanks for the continued discussion @dkoes. As opposed to iterating through the atoms in I also included the total number of bonds in atom3 -- thought that could be interesting to determine a 'divergent' candidate. I would prefer to use something more quantitative than just "aromatic", if that is possible, since a) I'm not sure how to determine candidates.push({
v: v,
l: l,
nonHydrogen: atom3.elem !== 'H',
numBonds: atom3.bonds.length
});
// ...then, later:
// Sort candidates: non-hydrogen > numBonds > longer length
candidates.sort((a, b) => {
if (a.isNonHydrogen !== b.isNonHydrogen) {
return a.isNonHydrogen ? -1 : 1;
}
if (a.numBonds !== b.numBonds) {
return b.numBonds - a.numBonds;
}
return b.l - a.l;
}); After computing these properties, I outputted the candidates array and determined/selected the correct choice empirically, and have indicated it as such below (this is an unsorted list). I'm wondering if part of the problem is the (perhaps) arbitrary selection of atom vs. atom2? If I reverse the choice of atom vs. atom2 in this case, it seems to fix it. But, this doesn't appear to work generally...e.g.., it yields an unexpected result for a benzene ring with a carbonyl. if (atom2.bonds.length < atom.bonds.length) {
[atom, atom2] = [atom2, atom];
} The first entry there is giving a result that doesn't seem to match with your specs. For reference, that is the bond in the top left of this image. If it's helpful, from the SDF file I posted above, the relevant atoms (i.e.,
|
Do you think you have a better goodCross? I feel like the overall logic of choosing the bond plane and direction should be simplifiable, but I keep getting stuck with various corner cases when I try. |
No, I had the same experience and am not familiar enough with the codebase to proceed any further. I'm wondering if the logic for this is already solved by some open source Chemistry drawing app. |
Let's not make the perfect the enemy of the good - the aromatic dashed bonds would still be great to have. Can you make a PR? We can make it optional. |
Have you verified that your weird molecules above visualize the way you expect in other software? Maybe you are setting a standard higher than what the community currently accepts. If they look right in an open source viewer I can dig into the source code (e.g. JMol or pymol). |
@dkoes sorry for the late reply! It has been all hands on deck dealing with various stages of the plague here 😅
Hmm, you may be right. It's wrong there too, but it does look more consistent in pymol though (didn't test jmol). At least two of the bonds are out of plane, but interestingly, they are consistently off whereas I'm getting more of a mixed behavior here. I am still wondering if the distinction between atom vs. atom2 needs to be picked in some kind of more sophisticated way to get the desired behavior. Unfortunately, my code to trial all this is unpolished and hacky, utilizing a specialty file format and not really suitable for distribution/PR unfortunately. I'll see if I can find time to keep working on this! |
My general feeling is that a solution that works for normal aromatic rings (flat, bonds to hydrogens are shorter than the aromatic bonds) is good enough. |
I don't have a good way of calculating the interior part of the rings, so there haven't been any updates on my side. I wonder if there is some open source algorithm from an open chemistry drawing software that could be used to calculate it. One of the issues is we are also calculating bond-by-bond (at least, that is how 3dmol works) so we need to treat each bond independently. |
Stick style should show aromatic bonds with solid/dashed representation.
The text was updated successfully, but these errors were encountered: