moleditpy 1.1.8__tar.gz → 1.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: moleditpy
3
- Version: 1.1.8
3
+ Version: 1.2.0
4
4
  Summary: A cross-platform, simple, and intuitive molecular structure editor built in Python. It allows 2D molecular drawing and 3D structure visualization. It supports exporting structure files for input to DFT calculation software.
5
5
  Author-email: HiroYokoyama <titech.yoko.hiro@gmail.com>
6
6
  Project-URL: Homepage, https://github.com/HiroYokoyama/python_molecular_editor
@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
5
5
  [project]
6
6
  name = "moleditpy"
7
7
 
8
- version = "1.1.8"
8
+ version = "1.2.0"
9
9
 
10
10
  authors = [
11
11
  { name="HiroYokoyama", email="titech.yoko.hiro@gmail.com" },
@@ -11,7 +11,11 @@ DOI 10.5281/zenodo.17268532
11
11
  """
12
12
 
13
13
  #Version
14
- VERSION = '1.1.8'
14
+ VERSION = '1.2.0'
15
+
16
+ print("-----------------------------------------------------")
17
+ print("MoleditPy — A Python-based molecular editing software")
18
+ print("-----------------------------------------------------\n")
15
19
 
16
20
  import sys
17
21
  import numpy as np
@@ -31,7 +35,7 @@ from PyQt6.QtWidgets import (
31
35
  QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
32
36
  QPushButton, QSplitter, QGraphicsView, QGraphicsScene, QGraphicsItem,
33
37
  QToolBar, QStatusBar, QGraphicsTextItem, QGraphicsLineItem, QDialog, QGridLayout,
34
- QFileDialog, QSizePolicy, QLabel, QLineEdit, QToolButton, QMenu, QMessageBox
38
+ QFileDialog, QSizePolicy, QLabel, QLineEdit, QToolButton, QMenu, QMessageBox, QInputDialog
35
39
  )
36
40
  from PyQt6.QtGui import (
37
41
  QPen, QBrush, QColor, QPainter, QAction, QActionGroup, QFont, QPolygonF,
@@ -190,7 +194,15 @@ class MolecularData:
190
194
 
191
195
  for (id1, id2), bond in self.bonds.items():
192
196
  idx1, idx2, order = atom_map[id1] + 1, atom_map[id2] + 1, bond['order']
193
- mol_block += f"{idx1:3d}{idx2:3d}{order:3d} 0 0 0 0\n"
197
+ stereo_code = 0
198
+ bond_stereo = bond.get('stereo', 0)
199
+ if bond_stereo == 1:
200
+ stereo_code = 1
201
+ elif bond_stereo == 2:
202
+ stereo_code = 6
203
+
204
+ mol_block += f"{idx1:3d}{idx2:3d}{order:3d}{stereo_code:3d} 0 0 0\n"
205
+
194
206
  mol_block += "M END\n"
195
207
  return mol_block
196
208
 
@@ -2364,6 +2376,9 @@ class MainWindow(QMainWindow):
2364
2376
  menu_bar = self.menuBar()
2365
2377
 
2366
2378
  file_menu = menu_bar.addMenu("&File")
2379
+ import_smiles_action = QAction("Import SMILES...", self)
2380
+ import_smiles_action.triggered.connect(self.import_smiles_dialog)
2381
+ file_menu.addAction(import_smiles_action)
2367
2382
  load_mol_action = QAction("Import MOL...", self); load_mol_action.triggered.connect(self.load_mol_file)
2368
2383
  file_menu.addAction(load_mol_action)
2369
2384
  file_menu.addSeparator()
@@ -3020,13 +3035,84 @@ class MainWindow(QMainWindow):
3020
3035
  if push_to_undo:
3021
3036
  self.push_undo_state()
3022
3037
 
3038
+ def import_smiles_dialog(self):
3039
+ """ユーザーにSMILES文字列の入力を促すダイアログを表示する"""
3040
+ smiles, ok = QInputDialog.getText(self, "Import SMILES", "Enter SMILES string:")
3041
+ if ok and smiles:
3042
+ self.load_from_smiles(smiles)
3043
+
3044
+ def load_from_smiles(self, smiles_string):
3045
+ """SMILES文字列から分子を読み込み、2Dエディタに表示する"""
3046
+ try:
3047
+ mol = Chem.MolFromSmiles(smiles_string)
3048
+ if mol is None:
3049
+ raise ValueError("Invalid SMILES string.")
3050
+
3051
+ AllChem.Compute2DCoords(mol)
3052
+ Chem.Kekulize(mol)
3053
+
3054
+ AllChem.AssignStereochemistry(mol, cleanIt=True, force=True)
3055
+ conf = mol.GetConformer()
3056
+ AllChem.WedgeMolBonds(mol, conf)
3057
+
3058
+ self.clear_2d_editor(push_to_undo=False)
3059
+ self.current_mol = None
3060
+ self.plotter.clear()
3061
+ self.analysis_action.setEnabled(False)
3062
+
3063
+ conf = mol.GetConformer()
3064
+ SCALE_FACTOR = 50.0
3065
+
3066
+ view_center = self.view_2d.mapToScene(self.view_2d.viewport().rect().center())
3067
+ positions = [conf.GetAtomPosition(i) for i in range(mol.GetNumAtoms())]
3068
+ mol_center_x = sum(p.x for p in positions) / len(positions) if positions else 0.0
3069
+ mol_center_y = sum(p.y for p in positions) / len(positions) if positions else 0.0
3070
+
3071
+ rdkit_idx_to_my_id = {}
3072
+ for i in range(mol.GetNumAtoms()):
3073
+ atom = mol.GetAtomWithIdx(i)
3074
+ pos = conf.GetAtomPosition(i)
3075
+ charge = atom.GetFormalCharge()
3076
+
3077
+ relative_x = pos.x - mol_center_x
3078
+ relative_y = pos.y - mol_center_y
3079
+
3080
+ scene_x = (relative_x * SCALE_FACTOR) + view_center.x()
3081
+ scene_y = (-relative_y * SCALE_FACTOR) + view_center.y()
3082
+
3083
+ atom_id = self.scene.create_atom(atom.GetSymbol(), QPointF(scene_x, scene_y), charge=charge)
3084
+ rdkit_idx_to_my_id[i] = atom_id
3085
+
3086
+ for bond in mol.GetBonds():
3087
+ b_idx, e_idx = bond.GetBeginAtomIdx(), bond.GetEndAtomIdx()
3088
+ b_type = bond.GetBondTypeAsDouble()
3089
+ b_dir = bond.GetBondDir()
3090
+ stereo = 0
3091
+ if b_dir == Chem.BondDir.BEGINWEDGE:
3092
+ stereo = 1 # Wedge
3093
+ elif b_dir == Chem.BondDir.BEGINDASH:
3094
+ stereo = 2 # Dash
3095
+
3096
+ if b_idx in rdkit_idx_to_my_id and e_idx in rdkit_idx_to_my_id:
3097
+ a1_id, a2_id = rdkit_idx_to_my_id[b_idx], rdkit_idx_to_my_id[e_idx]
3098
+ a1_item = self.data.atoms[a1_id]['item']
3099
+ a2_item = self.data.atoms[a2_id]['item']
3100
+
3101
+ self.scene.create_bond(a1_item, a2_item, bond_order=int(b_type), bond_stereo=stereo)
3102
+
3103
+ self.statusBar().showMessage(f"Successfully loaded from SMILES.")
3104
+ self.reset_undo_stack()
3105
+ self.fit_to_view()
3106
+ except Exception as e:
3107
+ self.statusBar().showMessage(f"Error loading from SMILES: {e}")
3108
+
3023
3109
  def load_mol_file(self):
3024
3110
  options = QFileDialog.Option.DontUseNativeDialog
3025
3111
  file_path, _ = QFileDialog.getOpenFileName(self, "Import MOL File", "", "Chemical Files (*.mol *.sdf);;All Files (*)", options=options)
3026
3112
  if not file_path: return
3027
3113
  try:
3028
3114
  self.dragged_atom_info = None
3029
- suppl = Chem.SDMolSupplier(file_path, removeHs=True)
3115
+ suppl = Chem.SDMolSupplier(file_path, removeHs=False)
3030
3116
  mol = next(suppl, None)
3031
3117
  if mol is None: raise ValueError("Failed to read molecule from file.")
3032
3118
 
@@ -3036,9 +3122,16 @@ class MainWindow(QMainWindow):
3036
3122
  self.current_mol = None; self.plotter.clear(); self.analysis_action.setEnabled(False)
3037
3123
 
3038
3124
  if mol.GetNumConformers() == 0:
3125
+ # 座標情報がないMOLファイルの場合、座標を生成し、
3126
+ # ファイルから読み取った立体情報を元に、くさび結合を再設定する
3039
3127
  AllChem.Compute2DCoords(mol)
3128
+ AllChem.AssignStereochemistry(mol, cleanIt=True, force=True)
3129
+ conf_for_wedge = mol.GetConformer()
3130
+ AllChem.WedgeMolBonds(mol, conf_for_wedge)
3131
+
3132
+ conf = mol.GetConformer()
3040
3133
 
3041
- conf = mol.GetConformer(); SCALE_FACTOR = 50.0
3134
+ SCALE_FACTOR = 50.0
3042
3135
 
3043
3136
  view_center = self.view_2d.mapToScene(self.view_2d.viewport().rect().center())
3044
3137
 
@@ -3076,6 +3169,7 @@ class MainWindow(QMainWindow):
3076
3169
  self.scene.create_bond(a1_item, a2_item, bond_order=int(b_type), bond_stereo=stereo)
3077
3170
 
3078
3171
  self.statusBar().showMessage(f"Successfully loaded {file_path}")
3172
+ self.fit_to_view()
3079
3173
  self.reset_undo_stack()
3080
3174
  except Exception as e: self.statusBar().showMessage(f"Error loading file: {e}")
3081
3175
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: moleditpy
3
- Version: 1.1.8
3
+ Version: 1.2.0
4
4
  Summary: A cross-platform, simple, and intuitive molecular structure editor built in Python. It allows 2D molecular drawing and 3D structure visualization. It supports exporting structure files for input to DFT calculation software.
5
5
  Author-email: HiroYokoyama <titech.yoko.hiro@gmail.com>
6
6
  Project-URL: Homepage, https://github.com/HiroYokoyama/python_molecular_editor
File without changes
File without changes