graphica-plot 2.0.0__py3-none-any.whl
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.
- graphica/Graphica.ico +0 -0
- graphica/__init__.py +1 -0
- graphica/__main__.py +111 -0
- graphica/assets/__init__.py +0 -0
- graphica/assets/icons/__init__.py +0 -0
- graphica/assets/icons/arrow-right.svg +21 -0
- graphica/assets/icons/bold.svg +20 -0
- graphica/assets/icons/calculator.svg +26 -0
- graphica/assets/icons/chart-histogram.svg +24 -0
- graphica/assets/icons/chart-line.svg +20 -0
- graphica/assets/icons/chevron-down.svg +19 -0
- graphica/assets/icons/chevron-right.svg +19 -0
- graphica/assets/icons/color-swatch.svg +22 -0
- graphica/assets/icons/column-insert-right.svg +21 -0
- graphica/assets/icons/column-remove.svg +21 -0
- graphica/assets/icons/copy.svg +20 -0
- graphica/assets/icons/download.svg +21 -0
- graphica/assets/icons/edit.svg +21 -0
- graphica/assets/icons/eye-off.svg +21 -0
- graphica/assets/icons/eye.svg +20 -0
- graphica/assets/icons/file-plus.svg +22 -0
- graphica/assets/icons/folder-plus.svg +21 -0
- graphica/assets/icons/folder.svg +19 -0
- graphica/assets/icons/highlight.svg +22 -0
- graphica/assets/icons/history.svg +20 -0
- graphica/assets/icons/italic.svg +21 -0
- graphica/assets/icons/layout-grid.svg +22 -0
- graphica/assets/icons/math-function.svg +22 -0
- graphica/assets/icons/message-2.svg +21 -0
- graphica/assets/icons/mountain.svg +20 -0
- graphica/assets/icons/palette.svg +22 -0
- graphica/assets/icons/pointer.svg +19 -0
- graphica/assets/icons/refresh.svg +20 -0
- graphica/assets/icons/row-insert-bottom.svg +21 -0
- graphica/assets/icons/row-remove.svg +21 -0
- graphica/assets/icons/search.svg +20 -0
- graphica/assets/icons/select-all.svg +35 -0
- graphica/assets/icons/subscript.svg +20 -0
- graphica/assets/icons/superscript.svg +20 -0
- graphica/assets/icons/table.svg +21 -0
- graphica/assets/icons/trash.svg +23 -0
- graphica/assets/icons/typography.svg +23 -0
- graphica/assets/icons/x.svg +20 -0
- graphica/core/__init__.py +0 -0
- graphica/core/analysis.py +1278 -0
- graphica/core/app_paths.py +35 -0
- graphica/core/axis_settings.py +128 -0
- graphica/core/caption_export.py +47 -0
- graphica/core/color_palettes.py +56 -0
- graphica/core/commands.py +226 -0
- graphica/core/cvd_simulation.py +49 -0
- graphica/core/dataset.py +443 -0
- graphica/core/diagnostics.py +105 -0
- graphica/core/excel_utils.py +58 -0
- graphica/core/fit_models.py +379 -0
- graphica/core/grid_data.py +128 -0
- graphica/core/i18n.py +44 -0
- graphica/core/json_utils.py +27 -0
- graphica/core/label_utils.py +21 -0
- graphica/core/methods_text.py +115 -0
- graphica/core/named_colors.py +126 -0
- graphica/core/plugin_api.py +515 -0
- graphica/core/plugin_context.py +167 -0
- graphica/core/plugin_install.py +82 -0
- graphica/core/plugin_manifest.py +67 -0
- graphica/core/plugin_testing.py +213 -0
- graphica/core/plugin_types.py +118 -0
- graphica/core/provenance.py +19 -0
- graphica/core/report_export.py +51 -0
- graphica/core/safe_eval.py +194 -0
- graphica/core/script_export.py +272 -0
- graphica/core/translations_en.py +530 -0
- graphica/core/unit_conversion.py +51 -0
- graphica/core/update_check.py +43 -0
- graphica/core/version.py +14 -0
- graphica/gui/__init__.py +0 -0
- graphica/gui/app_settings.py +119 -0
- graphica/gui/axis_bindings.py +173 -0
- graphica/gui/binding.py +135 -0
- graphica/gui/builders/__init__.py +1 -0
- graphica/gui/builders/axis_panel.py +431 -0
- graphica/gui/builders/canvas_area.py +176 -0
- graphica/gui/builders/common.py +120 -0
- graphica/gui/builders/dataset_panel.py +433 -0
- graphica/gui/builders/property_sections.py +208 -0
- graphica/gui/canvas.py +519 -0
- graphica/gui/color_history.py +47 -0
- graphica/gui/color_picker_widget.py +198 -0
- graphica/gui/crash_handler.py +77 -0
- graphica/gui/cvd_preview.py +23 -0
- graphica/gui/data_editor.py +761 -0
- graphica/gui/data_import_flow.py +355 -0
- graphica/gui/dataset_bindings.py +107 -0
- graphica/gui/dataset_style_icon.py +80 -0
- graphica/gui/datasets/__init__.py +1 -0
- graphica/gui/datasets/actions_menu.py +114 -0
- graphica/gui/datasets/colors.py +218 -0
- graphica/gui/datasets/fitting.py +70 -0
- graphica/gui/datasets/host.py +162 -0
- graphica/gui/datasets/operations/__init__.py +1 -0
- graphica/gui/datasets/operations/fitting.py +468 -0
- graphica/gui/datasets/operations/peaks.py +109 -0
- graphica/gui/datasets/operations/processing.py +659 -0
- graphica/gui/datasets/operations/runner.py +148 -0
- graphica/gui/datasets/operations/transfer.py +227 -0
- graphica/gui/datasets/order.py +310 -0
- graphica/gui/datasets/overlays.py +74 -0
- graphica/gui/datasets/peaks.py +21 -0
- graphica/gui/datasets/plugin_runs.py +99 -0
- graphica/gui/datasets/processing.py +68 -0
- graphica/gui/datasets/property_panel.py +538 -0
- graphica/gui/datasets/transfer.py +36 -0
- graphica/gui/detached_canvas_window.py +22 -0
- graphica/gui/dialogs/__init__.py +137 -0
- graphica/gui/dialogs/analysis.py +1322 -0
- graphica/gui/dialogs/app.py +1015 -0
- graphica/gui/dialogs/appearance.py +851 -0
- graphica/gui/dialogs/data_edit.py +577 -0
- graphica/gui/dialogs/data_import.py +679 -0
- graphica/gui/dialogs/export.py +433 -0
- graphica/gui/dock_layout.py +176 -0
- graphica/gui/export_preview_panel.py +321 -0
- graphica/gui/export_settings.py +16 -0
- graphica/gui/file_association.py +97 -0
- graphica/gui/icon_utils.py +44 -0
- graphica/gui/main_app_window.py +210 -0
- graphica/gui/main_window.py +1151 -0
- graphica/gui/mathtext_preview.py +168 -0
- graphica/gui/menu_bar.py +320 -0
- graphica/gui/minimap_widget.py +151 -0
- graphica/gui/mixins/__init__.py +0 -0
- graphica/gui/mixins/export_mixin.py +520 -0
- graphica/gui/mixins/help_mixin.py +127 -0
- graphica/gui/mixins/project_io_mixin.py +289 -0
- graphica/gui/mixins/quick_access_mixin.py +194 -0
- graphica/gui/mixins/ui_setup_mixin.py +206 -0
- graphica/gui/notify.py +61 -0
- graphica/gui/panels/__init__.py +43 -0
- graphica/gui/panels/axis_settings.py +605 -0
- graphica/gui/panels/dataset_tree.py +424 -0
- graphica/gui/plot_type_drawers.py +131 -0
- graphica/gui/plugin_context.py +119 -0
- graphica/gui/project_files.py +361 -0
- graphica/gui/provenance_panel.py +65 -0
- graphica/gui/rendering/__init__.py +1 -0
- graphica/gui/rendering/annotations.py +177 -0
- graphica/gui/rendering/appearance.py +368 -0
- graphica/gui/rendering/common.py +316 -0
- graphica/gui/rendering/data_1d.py +376 -0
- graphica/gui/rendering/data_2d.py +66 -0
- graphica/gui/residual_panel.py +62 -0
- graphica/gui/resources.py +16 -0
- graphica/gui/single_instance.py +141 -0
- graphica/gui/splash.py +83 -0
- graphica/gui/task_runner.py +41 -0
- graphica/gui/theme.py +864 -0
- graphica/gui/tools/__init__.py +56 -0
- graphica/gui/tools/annotation.py +275 -0
- graphica/gui/tools/cursor.py +259 -0
- graphica/gui/tools/layout_edit.py +285 -0
- graphica/gui/tools/manager.py +78 -0
- graphica/gui/tools/peak_placement.py +132 -0
- graphica/gui/tools/range_select.py +191 -0
- graphica/gui/tools/region_highlight.py +222 -0
- graphica/gui/tools/slice_extraction.py +200 -0
- graphica/gui/widget_translation.py +46 -0
- graphica/gui/workers.py +280 -0
- graphica/models/__init__.py +0 -0
- graphica/models/project.py +197 -0
- graphica/plugin/__init__.py +20 -0
- graphica/plugin/testing.py +57 -0
- graphica/sample_data/__init__.py +0 -0
- graphica/sample_data/cooling_curve_sample.csv +42 -0
- graphica/ui_main_window.py +581 -0
- graphica_plot-2.0.0.dist-info/METADATA +317 -0
- graphica_plot-2.0.0.dist-info/RECORD +181 -0
- graphica_plot-2.0.0.dist-info/WHEEL +5 -0
- graphica_plot-2.0.0.dist-info/entry_points.txt +2 -0
- graphica_plot-2.0.0.dist-info/licenses/LICENSE +30 -0
- graphica_plot-2.0.0.dist-info/licenses/THIRD_PARTY_LICENSES.md +91 -0
- graphica_plot-2.0.0.dist-info/top_level.txt +1 -0
graphica/gui/splash.py
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"""起動画面。重いライブラリ(pandas・scipy・matplotlib)を読む前に出すので、ここでは PySide6 と軽いモジュールだけを使う。"""
|
|
2
|
+
from PySide6.QtCore import QRectF, Qt
|
|
3
|
+
from PySide6.QtGui import QColor, QFont, QIcon, QPainter, QPainterPath, QPixmap
|
|
4
|
+
from PySide6.QtWidgets import QApplication, QSplashScreen
|
|
5
|
+
|
|
6
|
+
from graphica.core.i18n import tr
|
|
7
|
+
from graphica.core.version import APP_NAME, __version__
|
|
8
|
+
from graphica.gui.resources import resource_path
|
|
9
|
+
from graphica.gui.theme import DARK_TOKENS, LIGHT_TOKENS
|
|
10
|
+
|
|
11
|
+
SPLASH_WIDTH = 440
|
|
12
|
+
SPLASH_HEIGHT = 220
|
|
13
|
+
_ICON_SIZE = 88
|
|
14
|
+
_CORNER_RADIUS = 14
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _render_background(dark, device_pixel_ratio):
|
|
18
|
+
colors = DARK_TOKENS if dark else LIGHT_TOKENS
|
|
19
|
+
pixmap = QPixmap(int(SPLASH_WIDTH * device_pixel_ratio), int(SPLASH_HEIGHT * device_pixel_ratio))
|
|
20
|
+
pixmap.setDevicePixelRatio(device_pixel_ratio)
|
|
21
|
+
pixmap.fill(Qt.GlobalColor.transparent)
|
|
22
|
+
|
|
23
|
+
painter = QPainter(pixmap)
|
|
24
|
+
painter.setRenderHint(QPainter.RenderHint.Antialiasing)
|
|
25
|
+
outline = QPainterPath()
|
|
26
|
+
outline.addRoundedRect(QRectF(0.5, 0.5, SPLASH_WIDTH - 1, SPLASH_HEIGHT - 1), _CORNER_RADIUS, _CORNER_RADIUS)
|
|
27
|
+
painter.fillPath(outline, QColor(colors["surface"]))
|
|
28
|
+
painter.setPen(QColor(colors["border"]))
|
|
29
|
+
painter.drawPath(outline)
|
|
30
|
+
|
|
31
|
+
icon_top = 40
|
|
32
|
+
icon = QIcon(resource_path("Graphica.ico")).pixmap(_ICON_SIZE, _ICON_SIZE)
|
|
33
|
+
painter.drawPixmap(32, icon_top, _ICON_SIZE, _ICON_SIZE, icon)
|
|
34
|
+
|
|
35
|
+
text_left = 32 + _ICON_SIZE + 24
|
|
36
|
+
name_font = QFont()
|
|
37
|
+
name_font.setPointSize(22)
|
|
38
|
+
name_font.setBold(True)
|
|
39
|
+
painter.setFont(name_font)
|
|
40
|
+
painter.setPen(QColor(colors["text_primary"]))
|
|
41
|
+
painter.drawText(QRectF(text_left, icon_top + 8, SPLASH_WIDTH - text_left - 24, 40),
|
|
42
|
+
Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignVCenter, APP_NAME)
|
|
43
|
+
|
|
44
|
+
version_font = QFont()
|
|
45
|
+
version_font.setPointSize(10)
|
|
46
|
+
painter.setFont(version_font)
|
|
47
|
+
painter.setPen(QColor(colors["text_secondary"]))
|
|
48
|
+
painter.drawText(QRectF(text_left, icon_top + 50, SPLASH_WIDTH - text_left - 24, 24),
|
|
49
|
+
Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignVCenter,
|
|
50
|
+
tr("バージョン {version}").format(version=__version__))
|
|
51
|
+
painter.end()
|
|
52
|
+
return pixmap
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class StartupSplash(QSplashScreen):
|
|
56
|
+
"""アイコン・名前・版と、下に今の段階の文字を出す。最初のウィンドウを出したら finish() で閉じる。"""
|
|
57
|
+
|
|
58
|
+
def __init__(self, dark=False):
|
|
59
|
+
app = QApplication.instance()
|
|
60
|
+
ratio = app.devicePixelRatio() if app is not None else 1.0
|
|
61
|
+
super().__init__(_render_background(dark, ratio))
|
|
62
|
+
self.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground)
|
|
63
|
+
self._text_color = QColor((DARK_TOKENS if dark else LIGHT_TOKENS)["text_secondary"])
|
|
64
|
+
|
|
65
|
+
def drawContents(self, painter):
|
|
66
|
+
# 既定は端から 5px で文字が枠に近すぎるので、下に余白を取る
|
|
67
|
+
painter.setPen(self._text_color)
|
|
68
|
+
painter.drawText(self.rect().adjusted(24, 0, -24, -22),
|
|
69
|
+
Qt.AlignmentFlag.AlignBottom | Qt.AlignmentFlag.AlignHCenter, self.message())
|
|
70
|
+
|
|
71
|
+
def show_progress(self, text):
|
|
72
|
+
"""文字を出して、すぐに描かせる(このあと重い処理でイベントループが止まるので)。"""
|
|
73
|
+
self.showMessage(text, Qt.AlignmentFlag.AlignBottom | Qt.AlignmentFlag.AlignHCenter, self._text_color)
|
|
74
|
+
app = QApplication.instance()
|
|
75
|
+
if app is not None:
|
|
76
|
+
app.processEvents()
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def show_startup_splash(dark=False):
|
|
80
|
+
splash = StartupSplash(dark)
|
|
81
|
+
splash.show()
|
|
82
|
+
splash.show_progress(tr("起動しています…"))
|
|
83
|
+
return splash
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"""時間のかかる関数を別スレッドで動かす。"""
|
|
2
|
+
import logging
|
|
3
|
+
from PySide6.QtCore import QThread, Signal
|
|
4
|
+
|
|
5
|
+
logger = logging.getLogger(__name__)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class TaskRunner(QThread):
|
|
9
|
+
"""fn(*args, report_progress, is_cancelled, **kwargs) を別スレッドで動かす。
|
|
10
|
+
|
|
11
|
+
report_progress(done, total, message="") と is_cancelled() は必ず渡る(使うかは fn の自由)。fn は Qt に依存させない。
|
|
12
|
+
fn が普通に戻れば、キャンセル中でも succeeded を出す(キャンセル時に途中までの結果を返す使い方のため。
|
|
13
|
+
抑えると succeeded も failed も出ず、呼び出し側が待ち続ける)。
|
|
14
|
+
"""
|
|
15
|
+
progress = Signal(int, int, str) # (done, total, message)
|
|
16
|
+
succeeded = Signal(object) # fn の戻り値
|
|
17
|
+
failed = Signal(str) # str(例外)
|
|
18
|
+
|
|
19
|
+
def __init__(self, fn, *args, parent=None, **kwargs):
|
|
20
|
+
super().__init__(parent)
|
|
21
|
+
self._fn = fn
|
|
22
|
+
self._args = args
|
|
23
|
+
self._kwargs = kwargs
|
|
24
|
+
|
|
25
|
+
def run(self):
|
|
26
|
+
def _report_progress(done, total, message=""):
|
|
27
|
+
self.progress.emit(done, total, message)
|
|
28
|
+
|
|
29
|
+
try:
|
|
30
|
+
result = self._fn(
|
|
31
|
+
*self._args,
|
|
32
|
+
report_progress=_report_progress,
|
|
33
|
+
is_cancelled=self.isInterruptionRequested,
|
|
34
|
+
**self._kwargs,
|
|
35
|
+
)
|
|
36
|
+
except Exception as e:
|
|
37
|
+
logger.exception("バックグラウンドタスクが失敗しました")
|
|
38
|
+
self.failed.emit(str(e))
|
|
39
|
+
return
|
|
40
|
+
|
|
41
|
+
self.succeeded.emit(result)
|