Update for plotting function.

This commit is contained in:
gao 2022-07-30 21:50:53 +02:00
parent c0b291f547
commit cb1c9637d2
29 changed files with 1733 additions and 34 deletions

139
.idea/workspace.xml generated
View File

@ -1,13 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ChangeListManager">
<list default="true" id="68ddce6f-baaa-4bac-af24-443b9be545bf" name="Changes" comment="Debug for calculating atom number.&#10;&#10;Add selecting the effective area function in AbsorptionImaging.py.&#10;&#10;Optimaze plotting function.">
<list default="true" id="68ddce6f-baaa-4bac-af24-443b9be545bf" name="Changes" comment="Debug for calculating atom number.&#10;&#10;Add background subtraction function.&#10;&#10;Correct the pixel size of the camera">
<change afterPath="$PROJECT_DIR$/HelperClasses/Plotting/DataExtractorLyse.py" afterDir="false" />
<change afterPath="$PROJECT_DIR$/HelperClasses/Plotting/MainPlotPanel.py" afterDir="false" />
<change afterPath="$PROJECT_DIR$/HelperClasses/Plotting/PlottingData.py" afterDir="false" />
<change afterPath="$PROJECT_DIR$/HelperClasses/Plotting/PlottingPanel.py" afterDir="false" />
<change afterPath="$PROJECT_DIR$/HelperClasses/Plotting/Quick1DPlot.py" afterDir="false" />
<change afterPath="$PROJECT_DIR$/HelperClasses/Plotting/Unknown.py" afterDir="false" />
<change afterPath="$PROJECT_DIR$/HelperClasses/Plotting/WidgetDataSelector.py" afterDir="false" />
<change afterPath="$PROJECT_DIR$/HelperClasses/Plotting/WidgetFakeColorPlot.py" afterDir="false" />
<change afterPath="$PROJECT_DIR$/HelperClasses/Plotting/WidgetPlot.py" afterDir="false" />
<change afterPath="$PROJECT_DIR$/HelperClasses/Plotting/WidgetQuick2DPlot.py" afterDir="false" />
<change afterPath="$PROJECT_DIR$/HelperClasses/Plotting/WidgetQuickPlotGenerator.py" afterDir="false" />
<change afterPath="$PROJECT_DIR$/HelperClasses/Plotting/WidgetQuickWaterFlowPlot.py" afterDir="false" />
<change afterPath="$PROJECT_DIR$/HelperClasses/Plotting/__init__.py" afterDir="false" />
<change afterPath="$PROJECT_DIR$/test_living_plot.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/__init__.py" beforeDir="false" afterPath="$PROJECT_DIR$/__init__.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/build/lib/dylab/AbsorptionImaging.py" beforeDir="false" afterPath="$PROJECT_DIR$/build/lib/dylab/AbsorptionImaging.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/dylab/AbsorptionImaging.py" beforeDir="false" afterPath="$PROJECT_DIR$/dylab/AbsorptionImaging.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/dylab/Camera.py" beforeDir="false" afterPath="$PROJECT_DIR$/dylab/Camera.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/build/lib/dylab/DyTransition.py" beforeDir="false" afterPath="$PROJECT_DIR$/build/lib/dylab/DyTransition.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/build/lib/dylab/Fitting.py" beforeDir="false" afterPath="$PROJECT_DIR$/build/lib/dylab/Fitting.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/dylab/AbsorptionImaging.py" beforeDir="false" afterPath="$PROJECT_DIR$/HelperClasses/AbsorptionImaging.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/dylab/Camera.py" beforeDir="false" afterPath="$PROJECT_DIR$/HelperClasses/Camera.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/dylab/DyTransition.py" beforeDir="false" afterPath="$PROJECT_DIR$/HelperClasses/DyTransition.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/dylab/Fitting.py" beforeDir="false" afterPath="$PROJECT_DIR$/HelperClasses/Fitting.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/dylab/FittingFunction.py" beforeDir="false" afterPath="$PROJECT_DIR$/HelperClasses/FittingFunction.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/dylab/TransitionClass.py" beforeDir="false" afterPath="$PROJECT_DIR$/HelperClasses/TransitionClass.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/dylab/__init__.py" beforeDir="false" afterPath="$PROJECT_DIR$/HelperClasses/__init__.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/setup.py" beforeDir="false" afterPath="$PROJECT_DIR$/setup.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/test_absorption_imaging.py" beforeDir="false" afterPath="$PROJECT_DIR$/test_absorption_imaging.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/test_fitting.py" beforeDir="false" afterPath="$PROJECT_DIR$/test_fitting.py" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
@ -33,10 +56,59 @@
<property name="RunOnceActivity.OpenProjectViewOnStart" value="true" />
<property name="RunOnceActivity.ShowReadmeOnStart" value="true" />
<property name="WebServerToolWindowFactoryState" value="false" />
<property name="last_opened_file_path" value="$PROJECT_DIR$/../dylab_test" />
<property name="last_opened_file_path" value="$PROJECT_DIR$" />
<property name="settings.editor.selected.configurable" value="preferences.keymap" />
</component>
<component name="RunManager">
<component name="RecentsManager">
<key name="MoveFile.RECENT_KEYS">
<recent name="D:\Jianshun Gao\Simulations\DyLab\publishedPackage\dylab\HelperClasses\Plotting" />
</key>
</component>
<component name="RunManager" selected="Python.test_living_plot">
<configuration name="Plotting" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
<module name="dylab" />
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
<envs>
<env name="PYTHONUNBUFFERED" value="1" />
</envs>
<option name="SDK_HOME" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/HelperClasses" />
<option name="IS_MODULE_SDK" value="true" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/HelperClasses/Plotting.py" />
<option name="PARAMETERS" value="" />
<option name="SHOW_COMMAND_LINE" value="false" />
<option name="EMULATE_TERMINAL" value="false" />
<option name="MODULE_MODE" value="false" />
<option name="REDIRECT_INPUT" value="false" />
<option name="INPUT_FILE" value="" />
<method v="2" />
</configuration>
<configuration name="test" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
<module name="dylab" />
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
<envs>
<env name="PYTHONUNBUFFERED" value="1" />
</envs>
<option name="SDK_HOME" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/HelperClasses" />
<option name="IS_MODULE_SDK" value="true" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/HelperClasses/test.py" />
<option name="PARAMETERS" value="" />
<option name="SHOW_COMMAND_LINE" value="false" />
<option name="EMULATE_TERMINAL" value="false" />
<option name="MODULE_MODE" value="false" />
<option name="REDIRECT_INPUT" value="false" />
<option name="INPUT_FILE" value="" />
<method v="2" />
</configuration>
<configuration name="test_fitting" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
<module name="dylab" />
<option name="INTERPRETER_OPTIONS" value="" />
@ -59,8 +131,33 @@
<option name="INPUT_FILE" value="" />
<method v="2" />
</configuration>
<configuration name="test_living_plot" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
<module name="dylab" />
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
<envs>
<env name="PYTHONUNBUFFERED" value="1" />
</envs>
<option name="SDK_HOME" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
<option name="IS_MODULE_SDK" value="true" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/test_living_plot.py" />
<option name="PARAMETERS" value="" />
<option name="SHOW_COMMAND_LINE" value="false" />
<option name="EMULATE_TERMINAL" value="false" />
<option name="MODULE_MODE" value="false" />
<option name="REDIRECT_INPUT" value="false" />
<option name="INPUT_FILE" value="" />
<method v="2" />
</configuration>
<recent_temporary>
<list>
<item itemvalue="Python.test_living_plot" />
<item itemvalue="Python.test" />
<item itemvalue="Python.Plotting" />
<item itemvalue="Python.test_fitting" />
</list>
</recent_temporary>
@ -75,7 +172,12 @@
<updated>1658317648754</updated>
<workItem from="1658317653047" duration="53940000" />
<workItem from="1658490102584" duration="2917000" />
<workItem from="1658494814456" duration="18815000" />
<workItem from="1658494814456" duration="19705000" />
<workItem from="1658838353120" duration="58000" />
<workItem from="1658844297242" duration="39201000" />
<workItem from="1659027245256" duration="8511000" />
<workItem from="1659078820495" duration="69000" />
<workItem from="1659078901335" duration="36607000" />
</task>
<task id="LOCAL-00001" summary="First working version. Need introductions">
<created>1658494877565</created>
@ -91,7 +193,14 @@
<option name="project" value="LOCAL" />
<updated>1658744594836</updated>
</task>
<option name="localTasksCounter" value="3" />
<task id="LOCAL-00003" summary="Debug for calculating atom number.&#10;&#10;Add background subtraction function.&#10;&#10;Correct the pixel size of the camera">
<created>1658822265357</created>
<option name="number" value="00003" />
<option name="presentableId" value="LOCAL-00003" />
<option name="project" value="LOCAL" />
<updated>1658822265357</updated>
</task>
<option name="localTasksCounter" value="4" />
<servers />
</component>
<component name="TypeScriptGeneratedFilesManager">
@ -107,11 +216,13 @@
</entry>
</map>
</option>
<option name="oldMeFiltersMigrated" value="true" />
</component>
<component name="VcsManagerConfiguration">
<MESSAGE value="First working version. Need introductions" />
<MESSAGE value="Debug for calculating atom number.&#10;&#10;Add selecting the effective area function in AbsorptionImaging.py.&#10;&#10;Optimaze plotting function." />
<option name="LAST_COMMIT_MESSAGE" value="Debug for calculating atom number.&#10;&#10;Add selecting the effective area function in AbsorptionImaging.py.&#10;&#10;Optimaze plotting function." />
<MESSAGE value="Debug for calculating atom number.&#10;&#10;Add background subtraction function.&#10;&#10;Correct the pixel size of the camera" />
<option name="LAST_COMMIT_MESSAGE" value="Debug for calculating atom number.&#10;&#10;Add background subtraction function.&#10;&#10;Correct the pixel size of the camera" />
</component>
<component name="XDebuggerManager">
<breakpoint-manager>
@ -127,13 +238,14 @@
<option name="timeStamp" value="54" />
</line-breakpoint>
<line-breakpoint enabled="true" suspend="THREAD" type="python-line">
<url>file://$USER_HOME$/labscript-suite/userlib/analysislib/example_apparatus/analysis_plot_panel/src/analysis_plot_panel/user_data_extractors.py</url>
<url>file://$USER_HOME$/labscript-suite/userlib/analysislib/example_apparatus/analysis_plot_panel/src/analysis_plot_panel/data_extractors.py</url>
<line>7</line>
<option name="timeStamp" value="55" />
<option name="timeStamp" value="56" />
</line-breakpoint>
<line-breakpoint enabled="true" suspend="THREAD" type="python-line">
<url>file://$PROJECT_DIR$/test_absorption_imaging.py</url>
<option name="timeStamp" value="56" />
<url>file://$USER_HOME$/labscript-suite/userlib/analysislib/example_apparatus/analysis_plot_panel/src/analysis_plot_panel/user_plots.py</url>
<line>7</line>
<option name="timeStamp" value="57" />
</line-breakpoint>
</breakpoints>
<default-breakpoints>
@ -146,6 +258,9 @@
</breakpoint-manager>
</component>
<component name="com.intellij.coverage.CoverageDataManagerImpl">
<SUITE FILE_PATH="coverage/dylab$test_living_plot.coverage" NAME="test_living_plot Coverage Results" MODIFIED="1659127460208" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
<SUITE FILE_PATH="coverage/dylab$Plotting.coverage" NAME="Plotting Coverage Results" MODIFIED="1659081506380" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/HelperClasses" />
<SUITE FILE_PATH="coverage/dylab$test_fitting.coverage" NAME="test_fitting Coverage Results" MODIFIED="1658416885056" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
<SUITE FILE_PATH="coverage/dylab$test.coverage" NAME="test Coverage Results" MODIFIED="1659126746245" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/HelperClasses" />
</component>
</project>

View File

@ -2,7 +2,7 @@ from lyse import *
from pylab import *
import numpy as np
import scipy.constants as constant
from dylab import DyTransition, Camera
from HelperClasses import DyTransition, Camera
import matplotlib.pyplot as plt
from matplotlib import colors as mcolors
import colorsys
@ -54,6 +54,7 @@ class absorption_imaging:
# select effective region
self.image_absorption_cut = None
self.image_absorption_remove_background = None
self.x_start = None
self.y_start = None
self.x_end = None
@ -134,6 +135,10 @@ class absorption_imaging:
self.image_absorption_cut = self.image_absorption[self.y_start:self.y_end, self.x_start:self.x_end]
back_ground = self.corner_subtract(self.image_absorption_cut, 0.1, 0.1)
self.image_absorption_cut = self.image_absorption_cut - back_ground
self.image_absorption_remove_background = self.image_absorption - back_ground
return self.image_absorption_cut
# The function do the analyzation for absorption imaging
@ -184,19 +189,11 @@ class absorption_imaging:
if self.atom_number is not None and not force_to_run:
return self.atom_number
if self.image_absorption is None or not force_to_run:
if self.image_absorption is None:
self.image_absorption = self.get_image_absorption()
if self.image_absorption_cut is None:
self.image_absorption_cut = self.image_absorption
self.x_start = 0
self.x_end = self.image_absorption.shape[1]
self.y_start = 0
self.y_end = self.image_absorption.shape[0]
back_ground = self.corner_subtract(self.image_absorption_cut, 0.1, 0.1)
self.image_absorption_cut = self.image_absorption_cut - back_ground
self.image_absorption = self.image_absorption - back_ground
self.select_effective_data((0, 0), np.shape(self.image_absorption))
OD_act = self.image_absorption_cut

View File

@ -1,7 +1,7 @@
# Functions create constant dictionary storing transition information of Dy.
import scipy.constants as constant
from dylab import TransitionClass
from HelperClasses import TransitionClass
def creat_Dy421():

View File

@ -1,5 +1,5 @@
import numpy as np
from dylab import FittingFunction
from HelperClasses import FittingFunction
import laserbeamsize as lbs
import lmfit
from lmfit.minimizer import MinimizerResult

View File

@ -0,0 +1,134 @@
# -*- coding: utf-8 -*-
"""
Created on Mon Mar 15 15:08:46 2021
@author: Nick Sauerwein
"""
import lyse
import numpy as np
import os.path
import time
import h5py
def get_mtime(filename):
return time.ctime(os.path.getmtime(filename))
class DataExtractorManager:
def __init__(self, data_path=None):
self.data_extractors = {}
self.h5_file = None
self.data_path = data_path
self.local_data_changed = False
def update_local_data(self, h5_path):
with h5py.File(h5_path, 'r') as h5_file:
self.local_data_changed = False
for key in self.data_extractors:
self.data_extractors[key].update_local_data(h5_path, h5_file=h5_file)
if self.data_extractors[key].local_data_changed:
self.local_data_changed = True
def clean_memory(self, h5_paths):
for key in self.data_extractors:
self.data_extractors[key].clean_memory(h5_paths)
def __getitem__(self, key):
return self.data_extractors[key]
def __setitem__(self, key, de):
self.data_extractors[key] = de
def add_data_extractor(self, label, type, data_path):
result = DataExtractor(label, type, data_path)
self.data_extractors[label] = result
return result
def get_data(self, h5_path, h5_file=None):
result = {}
for key in self.data_extractors:
result[key] = self.data_extractors[key].get_data(h5_path, h5_file=h5_file)
return result
class DataExtractor:
def __init__(self, label, type, data_path, load_to_ram=True):
self.load_to_ram = load_to_ram
self.local_datas = {}
self.local_mtimes = {}
if self.load_to_ram:
self.local_data_changed = True
# The path of data in hdf5 file
self.data_path = data_path
self.data_type = type
self.data_label = label
def extract_data(self, h5_path, h5_file=None):
result = None
data_handle = lyse.Run(h5_path, no_write=True)
if self.data_type == 'array':
try:
result = data_handle.get_result_array(self.data_path[0], self.data_path[1],
h5_file=h5_file)
result = np.array(result)
except:
result = None
elif self.data_type == 'single':
try:
if len(self.data_path) == 1:
result = data_handle.get_globals(self.data_path[0], h5_file=h5_file)
else:
result = data_handle.get_result(self.data_path[0], self.data_path[1],
h5_file=h5_file)
except:
result = None
return result
def update_local_data(self, h5_path, h5_file=None):
if h5_path in self.local_datas and self.local_mtimes[h5_path] == get_mtime(h5_path):
self.local_data_changed = False
elif self.load_to_ram:
self.local_datas[h5_path] = self.extract_data(h5_path, h5_file=h5_file)
self.local_mtimes[h5_path] = get_mtime(h5_path)
self.local_data_changed = True
def update_local_datas(self):
for key in self.local_datas:
self.update_local_data(key)
def get_data(self, h5_path, h5_file=None):
if self.load_to_ram:
self.update_local_data(h5_path)
return self.local_datas[h5_path]
else:
return self.extract_data(h5_path, h5_file=h5_file)
def clean_memory(self, h5_paths):
for key in list(self.local_datas):
if key not in h5_paths.to_list():
del self.local_datas[key]
del self.local_mtimes[key]
self.local_data_changed = True
self.update_local_datas()

View File

@ -0,0 +1,104 @@
import pyqtgraph as pg
from pyqtgraph.Qt import QtCore, QtGui
import numpy as np
from pyqtgraph.dockarea import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
import lyse
from .WidgetDataSelector import ShotSelector
class MainPlotPanel(QtGui.QMainWindow):
def __init__(self, h5_paths, n_rows=3, **kwargs):
self.h5_paths = h5_paths
super().__init__(**kwargs)
pg.mkQApp()
self.n_rows = n_rows
self.setWindowFlag(QtCore.Qt.WindowCloseButtonHint, False)
self.area = DockArea()
self.setCentralWidget(self.area)
self.resize(1000, 500)
self.dshotselector = Dock("Shot selector")
self.shotselector = ShotSelector()
self.dshotselector.addWidget(self.shotselector)
self.area.addDock(self.dshotselector, 'bottom')
# self.qpg_dock = Dock("Quick Plot Generator")
# self.qpg_dock.addWidget(QuickPlotGenerator(self))
# self.qpg_dock.setMinimumSize(self.qpg_dock.minimumSizeHint())
# self.area.addDock(self.qpg_dock)
self.show()
self.plots = {}
self.shotselector.valueChanged.connect(self.refresh)
self.shotselector.selectionChanged.connect(self.refresh)
self.df = lyse.data()
def add_plot_dock(self, plot_name, plot_widget, **kwargs):
if plot_name not in self.plots:
plot_widget.plot_name = plot_name
dock = Dock(plot_name, **kwargs)
dock.sigClosed.connect(self.remove_plot)
dock.addWidget(plot_widget)
if len(self.plots):
if len(self.plots) % self.n_rows == 2:
position = 'right'
self.area.addDock(dock, position)
if len(self.plots) % (self.n_rows * 2) in [0, 1]:
position = 'bottom'
self.area.addDock(dock, position, relativeTo=self.area.docks[list(self.plots.keys())[-1]])
if len(self.plots) % (self.n_rows * 2) in [3, 4]:
position = 'top'
self.area.addDock(dock, position, relativeTo=self.area.docks[list(self.plots.keys())[-1]])
print(len(self.plots) % (self.n_rows * 2), len(self.plots) % self.n_rows)
else:
self.area.addDock(dock, 'right')
self.plots[plot_name] = plot_widget
else:
print(f'Plot {plot_name} already exists. Please choose different name.')
def remove_plot(self, dock):
del self.plots[dock.title()]
def update_h5_paths(self, h5_paths):
self.h5_paths = h5_paths
self.shotselector.update_nshots(len(h5_paths))
for plot_name in self.plots:
self.plots[plot_name].data_extractor_manager.clean_memory(h5_paths)
def refresh(self, h5_path=None):
if len(self.h5_paths):
self.h5_paths_selected = self.h5_paths.iloc[self.shotselector.get_selected_indices()]
if h5_path == None:
i = self.shotselector.get_current_index()
h5_path = self.h5_paths.iloc[i]
for plot_name in self.plots:
self.plots[plot_name].data_extractor_manager.update_local_data(h5_path)
# self.data_extractor_manager.update_local_data(h5_path)
for plot_name, plot in self.plots.items():
plot.update_from_h5(h5_path)
else:
pass

View File

@ -0,0 +1,172 @@
# -*- coding: utf-8 -*-
"""
Created on Mon Mar 15 15:08:46 2021
@author: Nick Sauerwein
"""
import lyse
import numpy as np
import os.path
import time
import h5py
def get_mtime(filename):
return time.ctime(os.path.getmtime(filename))
class DataExtractorManager:
def __init__(self):
self.data_extractors = {}
def update_local_data(self, h5_path):
with h5py.File(h5_path, 'r') as h5_file:
for key in self.data_extractors:
self.data_extractors[key].update_local_data(h5_path, h5_file=h5_file)
def clean_memory(self, h5_paths):
for key in self.data_extractors:
self.data_extractors[key].clean_memory(h5_paths)
def __getitem__(self, key):
return self.data_extractors[key]
def __setitem__(self, key, de):
self.data_extractors[key] = de
class DataExtractor:
def __init__(self, load_to_ram=True):
self.load_to_ram = load_to_ram
self.local_datas = {}
self.local_mtimes = {}
if self.load_to_ram:
self.local_data_changed = True
def update_local_data(self, h5_path, h5_file=None):
if h5_path in self.local_datas and self.local_mtimes[h5_path] == get_mtime(h5_path):
self.local_data_changed = False
elif self.load_to_ram:
self.local_datas[h5_path] = self.extract_data(h5_path, h5_file=h5_file)
self.local_mtimes[h5_path] = get_mtime(h5_path)
self.local_data_changed = True
def update_local_datas(self):
for key in self.local_datas:
self.update_local_data(key)
def get_data(self, h5_path, h5_file=None):
if self.load_to_ram:
self.update_local_data(h5_path)
return self.local_datas[h5_path]
else:
return self.extract_data(h5_path, h5_file=h5_file)
def clean_memory(self, h5_paths):
for key in list(self.local_datas):
if key not in h5_paths.to_list():
del self.local_datas[key]
del self.local_mtimes[key]
self.local_data_changed = True
self.update_local_datas()
class MultiDataExtractor(DataExtractor):
def __init__(self, **kwargs):
super().__init__(load_to_ram=False, **kwargs)
self.data_extractors = {}
self.children_changed = False
def extract_data(self, h5_path, h5_file=None):
data = {}
for key in self.data_extractors:
data[key] = self.data_extractors[key].get_data(h5_path, h5_file=h5_file)
self.children_changed = False
return [data]
def clean_children(self, keys):
self.children_changed = False
for key in list(self.data_extractors):
if key not in keys:
del self.data_extractors[key]
self.children_changed = True
def clean_memory(self, h5_paths):
for key in self.data_extractors:
self.data_extractors[key].clean_memory(h5_paths)
def __getitem__(self, key):
return self.data_extractors[key]
def __setitem__(self, key, de):
self.children_changed = True
self.data_extractors[key] = de
@property
def local_data_changed(self):
return any(
[self.data_extractors[key].local_data_changed for key in self.data_extractors]) or self.children_changed
class EmptyDataExtractor(DataExtractor):
def __init__(self, **kwargs):
super().__init__(**kwargs)
def extract_data(self, h5_path, h5_file=None):
return []
class ArrayDataExtractor(DataExtractor):
def __init__(self, idx, **kwargs):
super().__init__(**kwargs)
self.idx = idx
def extract_data(self, h5_path, h5_file=None):
run = lyse.Run(h5_path, no_write=True)
try:
res = run.get_result_array(self.idx[0], self.idx[1], h5_file=h5_file)
except:
res = None
return res
class SingleDataExtractor(DataExtractor):
def __init__(self, idx, **kwargs):
super().__init__(**kwargs)
self.idx = idx
print(len(idx))
def extract_data(self, h5_path, h5_file=None):
run = lyse.Run(h5_path, no_write=True)
try:
if len(self.idx) == 1:
res = run.get_global(self.idx[0], h5_file=h5_file)
else:
res = run.get_result(self.idx[0], self.idx[1], h5_file=h5_file)
except:
raise
res = None
return res

View File

@ -0,0 +1,42 @@
# -*- coding: utf-8 -*-
"""
Created on Wed Mar 10 15:35:59 2021
@author: nicks
"""
import pyqtgraph as pg
from pyqtgraph.Qt import QtCore, QtGui
import numpy as np
from pyqtgraph.dockarea import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PIL import ImageColor
import lyse
import collections
import h5py
from pandas.api.types import is_numeric_dtype
from sortedcontainers import SortedSet
from scipy.interpolate import griddata
# from data_extractors import MultiDataExtractor, SingleDataExtractor, ArrayDataExtractor, EmptyDataExtractor, \
# DataExtractorManager
color_palette_html = ['#1f77b4',
'#ff7f0e',
'#2ca02c',
'#d62728',
'#9467bd',
'#8c564b',
'#e377c2',
'#7f7f7f',
'#bcbd22',
'#17becf']
color_palette = [ImageColor.getcolor(color, "RGB") for color in color_palette_html]

View File

@ -0,0 +1,128 @@
class Quick1DPlot(QuickDataPlot):
def __init__(self, ap, **kwargs):
super().__init__(ap, **kwargs)
self.nplots = 0
self.table.setColumnCount(5)
self.table.setRowCount(1)
self.table.setColumnWidth(0, 200)
self.table.setColumnWidth(1, 200)
self.table.setColumnWidth(2, 30)
self.table.setColumnWidth(3, 30)
self.table.setColumnWidth(4, 40)
self.table.setHorizontalHeaderLabels(['xvalue', 'yvalue', 'color', 'show', 'scatter'])
self.combos = []
self.curves = []
self.show_cbs = []
self.scatter_cbs = []
self.mk_buttons()
def mk_buttons(self):
self.bt_add_plot = QPushButton('Add plot', self)
self.bt_add_plot.clicked.connect(self.add_plot)
self.table.setCellWidget(self.nplots, 0, self.bt_add_plot)
self.bt_update = QPushButton('Update', self)
self.bt_update.clicked.connect(self.update_from_h5)
self.table.setCellWidget(self.nplots, 1, self.bt_update)
def add_plot(self):
self.nplots += 1
self.table.setRowCount(self.nplots + 1)
combox = NumericDataCombo(self.ap.df)
comboy = NumericDataCombo(self.ap.df)
self.combos += [[combox, comboy]]
self.table.setCellWidget(self.nplots - 1, 0, combox)
self.table.setCellWidget(self.nplots - 1, 1, comboy)
self.table.setItem(self.nplots - 1, 2, QtGui.QTableWidgetItem())
self.table.item(self.nplots - 1, 2).setBackground(QtGui.QColor(*color_palette[self.nplots - 1]))
# self.table.setFixedSize(self.table.sizeHint())
self.curves += [
self.plot.plot(pen=pg.mkPen(color=color_palette[self.nplots - 1], width=1.5), symbol='x', symbolPen=None,
symbolBrush=None)]
self.show_cbs += [QCheckBox()]
self.show_cbs[self.nplots - 1].setChecked(True)
self.table.setCellWidget(self.nplots - 1, 3, self.show_cbs[self.nplots - 1])
self.show_cbs[self.nplots - 1].stateChanged.connect(self.update_shows)
self.scatter_cbs += [QCheckBox()]
self.scatter_cbs[self.nplots - 1].setChecked(False)
self.table.setCellWidget(self.nplots - 1, 4, self.scatter_cbs[self.nplots - 1])
self.scatter_cbs[self.nplots - 1].stateChanged.connect(self.update_scatters)
self.mk_buttons()
def update_shows(self):
for k, cb in enumerate(self.show_cbs):
if cb.isChecked():
self.curves[k].show()
else:
self.curves[k].hide()
def update_scatters(self):
for k, cb in enumerate(self.scatter_cbs):
pen = pg.mkPen(color=color_palette[k], width=1.5)
brush = pg.mkBrush(color=color_palette[k])
if cb.isChecked():
self.curves[k].setSymbolBrush(brush)
self.curves[k].setPen(None)
else:
self.curves[k].setSymbolBrush(None)
self.curves[k].setPen(pen)
def update_data_extractor(self):
idxxs = [combo[0].get_idx() for combo in self.combos]
idxys = [combo[1].get_idx() for combo in self.combos]
for idxx in idxxs:
if idxx not in self.data_extractor.data_extractors:
if idxx[0] == 'shot number':
self.data_extractor[idxx] = EmptyDataExtractor()
else:
self.data_extractor[idxx] = SingleDataExtractor(idxx)
for idxy in idxys:
if idxy not in self.data_extractor.data_extractors:
if idxy[0] == 'shot number':
self.data_extractor[idxy] = EmptyDataExtractor()
else:
self.data_extractor[idxy] = SingleDataExtractor(idxy)
self.data_extractor.clean_children(idxxs + idxys)
self.data_extractor.clean_memory(self.ap.h5_paths)
def update(self, data=None):
Xs = np.zeros((self.nplots, len(self.ap.h5_paths_selected)))
Ys = np.zeros((self.nplots, len(self.ap.h5_paths_selected)))
for i, h5_path in enumerate(self.ap.h5_paths_selected):
data = self.data_extractor.get_data(h5_path)[0]
for k in range(self.nplots):
idxx = self.combos[k][0].get_idx()
idxy = self.combos[k][1].get_idx()
if idxx[0] == 'shot number':
Xs[k, i] = self.ap.shotselector.get_selected_indices()[0][i]
else:
Xs[k, i] = data[idxx]
if idxy[0] == 'shot number':
Ys[k, i] = self.ap.shotselector.get_selected_indices()[0][i]
else:
Ys[k, i] = data[idxy]
for k in range(self.nplots):
self.curves[k].setData(Xs[k], Ys[k])

View File

@ -0,0 +1,188 @@
class DataPlot(QSplitter):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.setOrientation(Qt.Vertical)
self.plots = pg.GraphicsLayoutWidget()
self.addWidget(self.plots)
self.bottom = QSplitter()
self.bottom.setOrientation(Qt.Horizontal)
self.addWidget(self.bottom)
self.h5_path_shown = None
def update_from_h5(self, h5_path):
if self.h5_path_shown != h5_path or self.data_extractor.local_data_changed:
self.h5_path_shown = h5_path
self.update(*self.data_extractor.extract_data(h5_path))
class QuickDataPlot(DataPlot):
def __init__(self, ap, **kwargs):
super().__init__(**kwargs)
self.plot = self.plots.addPlot()
for key in self.plot.axes:
ax = self.plot.getAxis(key)
# Fix Z value making the grid on top of the image
ax.setZValue(1)
self.ap = ap
self.h5_paths_shown = []
self.table = QTableWidget()
self.table.setSizeAdjustPolicy(QAbstractScrollArea.AdjustToContents)
self.bottom.addWidget(self.table)
self.plot_setting = PlotSettings(self.plot)
self.bottom.addWidget(self.plot_setting)
def update_from_h5(self, h5_path=None):
self.update_data_extractor()
if self.data_extractor.local_data_changed or collections.Counter(self.h5_paths_shown) != collections.Counter(
self.ap.h5_paths_selected):
self.h5_paths_shown = self.ap.h5_paths_selected
self.update()
class ExtendedCombo(QComboBox):
def __init__(self, parent=None):
super().__init__(parent)
self.setFocusPolicy(Qt.StrongFocus)
self.setEditable(True)
self.completer = QCompleter(self)
# always show all completions
self.completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion)
self.pFilterModel = QSortFilterProxyModel(self)
self.pFilterModel.setFilterCaseSensitivity(Qt.CaseInsensitive)
self.completer.setPopup(self.view())
self.setCompleter(self.completer)
self.lineEdit().textEdited[str].connect(self.pFilterModel.setFilterFixedString)
self.completer.activated.connect(self.setTextIfCompleterIsClicked)
def setModel(self, model):
super().setModel(model)
self.pFilterModel.setSourceModel(model)
self.completer.setModel(self.pFilterModel)
def setModelColumn(self, column):
self.completer.setCompletionColumn(column)
self.pFilterModel.setFilterKeyColumn(column)
super().setModelColumn(column)
def view(self):
return self.completer.popup()
def index(self):
return self.currentIndex()
def setTextIfCompleterIsClicked(self, text):
if text:
index = self.findText(text)
self.setCurrentIndex(index)
class PlotSettings(QTableWidget):
def __init__(self, plot, **kwargs):
super().__init__(**kwargs)
self.plot = plot
self.setColumnCount(3)
self.setColumnWidth(0, 100)
self.setColumnWidth(1, 100)
self.setHorizontalHeaderLabels(['parameter', 'setting', 'units'])
self.setRowCount(4)
# title
i = 0
self.le_title = QLineEdit()
self.setCellWidget(i, 0, QLabel('title'))
self.setCellWidget(i, 1, self.le_title)
self.le_title.textChanged[str].connect(self.set_title)
# xlabel
i += 1
self.le_xlabel = QLineEdit()
self.le_xlabel_unit = QLineEdit()
self.setCellWidget(i, 0, QLabel('xlabel'))
self.setCellWidget(i, 1, self.le_xlabel)
self.setCellWidget(i, 2, self.le_xlabel_unit)
self.le_xlabel.textChanged[str].connect(self.set_xlabel)
self.le_xlabel_unit.textChanged[str].connect(self.set_xlabel)
# ylabel
i += 1
self.le_ylabel = QLineEdit()
self.le_ylabel_unit = QLineEdit()
self.setCellWidget(i, 0, QLabel('ylabel'))
self.setCellWidget(i, 1, self.le_ylabel)
self.setCellWidget(i, 2, self.le_ylabel_unit)
self.le_ylabel.textChanged[str].connect(self.set_ylabel)
self.le_ylabel_unit.textChanged[str].connect(self.set_ylabel)
# grid
i += 1
self.cb_grid = QCheckBox()
self.setCellWidget(i, 0, QLabel('grid'))
self.setCellWidget(i, 1, self.cb_grid)
self.cb_grid.stateChanged.connect(self.set_grid)
def set_title(self):
self.plot.setTitle(self.le_title.text())
def set_xlabel(self):
self.plot.setLabel('bottom', self.le_xlabel.text(), units=self.le_xlabel_unit.text())
def set_ylabel(self):
self.plot.setLabel('left', self.le_ylabel.text(), units=self.le_ylabel_unit.text())
def set_grid(self):
self.plot.showGrid(x=self.cb_grid.isChecked(), y=self.cb_grid.isChecked(), alpha=0.3)
class NumericDataCombo(ExtendedCombo):
def __init__(self, df, **kwargs):
super().__init__(**kwargs)
self.update_model(df)
def update_model(self, df):
model = QtGui.QStandardItemModel()
item = QtGui.QStandardItem('shot number')
model.setItem(0, 0, item)
i = 1
for midx in df.columns:
if is_numeric_dtype(df.dtypes[midx]):
column_name = ','.join([x for x in midx if x])
item = QtGui.QStandardItem(column_name)
model.setItem(i, 0, item)
i += 1
self.setModel(model)
def get_idx(self):
return tuple(str(self.currentText()).split(','))

View File

@ -0,0 +1,131 @@
import pyqtgraph as pg
from pyqtgraph.Qt import QtGui
import numpy as np
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from sortedcontainers import SortedSet
# ShotSelector class for choosing which the hdf5 files are import for plotting
class ShotSelector(pg.LayoutWidget):
valueChanged = pyqtSignal()
selectionChanged = pyqtSignal()
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.nshots = 1
self.setFixedHeight(100)
self.current_idx_le = QLineEdit(self)
self.current_idx_le.setMaximumWidth(30)
self.current_idx_le.setValidator(QtGui.QIntValidator())
self.current_idx_le.setText(str(-1))
self.addWidget(self.current_idx_le)
self.slider = QSlider(self)
self.slider.setPageStep(1)
self.slider.setOrientation(Qt.Horizontal)
self.addWidget(self.slider, colspan=2)
self.nextRow()
self.addWidget(QLabel('index selector'))
self.idx_select_le = QLineEdit(self)
self.idx_select_le.setText(':')
self.addWidget(self.idx_select_le)
self.warning = QLabel()
self.warning.setMargin(5)
self.update_warning()
self.addWidget(self.warning)
self.update_nshots(self.nshots)
self.idx_select_le.editingFinished.connect(self.update_selection)
self.current_idx_le.editingFinished.connect(self.setSliderValue)
self.slider.valueChanged.connect(self.setLabelValue)
def update_nshots(self, nshots):
self.nshots = nshots
self.idx = np.arange(self.nshots)
self.slider.setRange(0, self.nshots - 1)
self.update_selection()
self.setSliderValue()
def update_warning(self, warning=''):
if warning == '':
self.warning.setStyleSheet("background-color: lightgreen")
warning = 'all good'
else:
self.warning.setStyleSheet("background-color: red")
self.warning.setText(warning)
def update_selection(self):
self.update_warning()
slice_text = self.idx_select_le.text()
slices = slice_text.split(',')
self.idx_selected = SortedSet([])
for s in slices:
try:
scope = locals()
select = eval('self.idx[' + s + ']', scope)
if isinstance(select, np.ndarray):
for idx in select:
self.idx_selected.add(idx)
else:
self.idx_selected.add(select)
except:
self.update_warning('problem in selected indeces')
return 0
self.slider.setRange(0, len(self.idx_selected) - 1)
if int(self.current_idx_le.text()) % self.nshots not in self.idx_selected:
self.current_idx_le.setText(self.idx_selected[-1])
self.update_warning('last index not in selection <br> -> setting last selected')
self.selectionChanged.emit()
def setLabelValue(self, value):
newval = self.idx_selected[value]
if newval != self.get_current_index():
self.current_idx_le.setText(str(newval))
self.valueChanged.emit()
def setSliderValue(self):
self.update_warning()
value = int(self.current_idx_le.text())
try:
value_sl = self.idx_selected.index(value % len(self.idx))
self.slider.setValue(value_sl)
except ValueError:
self.update_warning('set index not in selection <br> ignore')
def get_current_index(self):
return int(self.current_idx_le.text()) % self.nshots
def get_selected_indices(self):
return (np.array(self.idx_selected),)

View File

@ -0,0 +1,139 @@
import pyqtgraph as pg
from pyqtgraph import Qt
from pyqtgraph.Qt import QtCore, QtGui
import numpy as np
from pyqtgraph.dockarea import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from .DataExtractorLyse import DataExtractorManager
# import DataExtractorLyse
from .WidgetPlot import DataPlot
# import WidgetPlot
from PIL import ImageColor
color_palette_html = ['#1f77b4',
'#ff7f0e',
'#2ca02c',
'#d62728',
'#9467bd',
'#8c564b',
'#e377c2',
'#7f7f7f',
'#bcbd22',
'#17becf']
color_palette = [ImageColor.getcolor(color, "RGB") for color in color_palette_html]
class FakeColorPlot(DataPlot):
def __init__(self, title, data_path=None, **kwargs):
super().__init__(title, **kwargs)
# set data extractor
self.data_extractor_manager = DataExtractorManager(data_path)
self.data_extractor_manager.add_data_extractor('data_img', 'array', data_path)
self.data_extractor_manager.add_data_extractor('x', 'array', (data_path[0], 'x'))
self.data_extractor_manager.add_data_extractor('y', 'array', (data_path[0], 'y'))
self.data_extractor_manager.add_data_extractor('warning', 'single', (data_path[0], 'warning'))
self.setMinimumHeight(550)
self.setMinimumWidth(550)
# Add imaging
self.img = pg.ImageItem()
self.aximg = self.plots.addPlot(title="")
self.aximg.addItem(self.img)
# Isocurve draplotsg
self.iso = pg.IsocurveItem(level=1000, pen=color_palette[2])
self.iso.setParentItem(self.img)
self.iso.setZValue(5)
# Contrast/color control
self.hist = pg.HistogramLUTItem()
self.hist.setImageItem(self.img)
self.plots.addItem(self.hist)
# Draggable line for setting isocurve level
self.isoLine = pg.InfiniteLine(angle=0, movable=True, pen=color_palette[2])
self.hist.vb.addItem(self.isoLine)
self.hist.vb.setMouseEnabled(y=False) # makes user interaction a little easier
self.isoLine.setValue(1000)
self.isoLine.setZValue(1000) # bring iso line above contrast controls
self.isoLine.sigDragged.connect(self.updateIsocurve)
# Monkey-patch the image to use our custom hover function.
# This is generally discouraged (you should subclass ImageItem instead),
# but it works for a very simple use like this.
self.img.hoverEvent = self.imageHoverEvent
self.plots.nextRow()
self.plots.nextColumn()
self.img.translate(-0.5, -0.5)
self.scalex = 1
self.scaley = 1
self.cx = 0
self.cy = 0
self.data_image = None
def update(self, h5_path):
data = self.data_extractor_manager.get_data(h5_path)
data_img = data['data_img']
x = data['x']
y = data['y']
if x is None:
x = np.linspace(0, data_img.shape[0], data_img.shape[0])
if y is None:
y = np.linspace(0, data_img.shape[1], data_img.shape[1])
warning = data['warning']
# update plots
self.img.setImage(data_img.T)
self.iso.setData(data_img.T)
self.data_img = data_img
# set position and scale of image
newscalex = x[1] - x[0]
newscaley = y[1] - y[0]
transx = (x[0] - (self.cx - 0.5 * self.scalex)) / newscalex - 0.5
transy = (y[0] - (self.cy - 0.5 * self.scaley)) / newscaley - 0.5
self.img.scale(newscalex / self.scalex, newscaley / self.scaley)
self.img.translate(transx, transy)
self.scalex = newscalex
self.scaley = newscaley
self.cx = x[0]
self.cy = y[0]
# update table and warning
self.update_warning(warning)
def updateIsocurve(self):
self.iso.setLevel(self.isoLine.value())
def imageHoverEvent(self, event):
"""Show the position, pixel, and value under the mouse cursor.
"""
if event.isExit():
self.aximg.setTitle("")
return
pos = event.pos()
i, j = pos.y(), pos.x()
i = int(np.clip(i, 0, self.data_img.shape[0] - 1))
j = int(np.clip(j, 0, self.data_img.shape[1] - 1))
val = self.data_img[i, j]
ppos = self.img.mapToParent(pos)
x, y = ppos.x(), ppos.y()
self.aximg.setTitle("pos: (%0.1f, %0.1f) value: %g" % (x, y, val))

View File

@ -0,0 +1,63 @@
import pyqtgraph as pg
from pyqtgraph import Qt
from pyqtgraph.Qt import QtCore, QtGui
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from .DataExtractorLyse import DataExtractorManager
class DataPlot(QSplitter):
def __init__(self, title, **kwargs):
super().__init__(**kwargs)
# Orientation of plot and title (and other information)
self.setOrientation(Qt.Vertical)
# Add plot
self.plots = pg.GraphicsLayoutWidget()
self.addWidget(self.plots)
# Claim bottom part (title)
self.bottom = QSplitter()
self.bottom.setOrientation(Qt.Horizontal)
self.addWidget(self.bottom)
# Add title
self.title = QtGui.QLabel()
self.title.setAlignment(QtCore.Qt.AlignCenter)
self.title.setText('<h2>' + title + ' <\h2>')
self.desciption = pg.LayoutWidget()
self.desciption.addWidget(self.title)
# Add warning information
self.warning = QtGui.QLabel()
self.warning.setAlignment(QtCore.Qt.AlignCenter)
self.desciption.nextRow()
self.desciption.addWidget(self.warning)
self.bottom.addWidget(self.desciption)
# Add a table for fitting information
self.table = pg.TableWidget()
self.bottom.addWidget(self.table)
# Current hdf5 file path
self.h5_path_shown = None
# data extractor
self.data_extractor_manager = DataExtractorManager()
def update_from_h5(self, h5_path):
if self.h5_path_shown != h5_path or self.data_extractor_manager.local_data_changed:
self.h5_path_shown = h5_path
self.update(h5_path)
def update_warning(self, warning):
if warning == '':
self.warning.setStyleSheet("background-color: lightgreen")
warning = 'all good'
else:
self.warning.setStyleSheet("background-color: red")
self.warning.setText(warning)

View File

@ -0,0 +1,166 @@
class Quick2DPlot(QuickDataPlot):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.img = pg.ImageItem()
self.plot.addItem(self.img)
# Isocurve draplotsg
self.iso = pg.IsocurveItem(level=1000, pen=color_palette[2])
self.iso.setParentItem(self.img)
self.iso.setZValue(5)
# Contrast/color control
self.hist = pg.HistogramLUTItem()
self.hist.setImageItem(self.img)
self.plots.addItem(self.hist)
# Draggable line for setting isocurve level
self.isoLine = pg.InfiniteLine(angle=0, movable=True, pen=color_palette[2])
self.hist.vb.addItem(self.isoLine)
self.hist.vb.setMouseEnabled(y=False) # makes user interaction a little easier
self.isoLine.setValue(1000)
self.isoLine.setZValue(1000) # bring iso line above contrast controls
self.isoLine.sigDragged.connect(self.updateIsocurve)
# Monkey-patch the image to use our custom hover function.
# This is generally discouraged (you should subclass ImageItem instead),
# but it works for a very simple use like this.
self.img.hoverEvent = self.imageHoverEvent
self.img.translate(-0.5, -0.5)
self.scalex = 1
self.scaley = 1
self.cx = 0
self.cy = 0
self.nplots = 0
self.table.setColumnCount(3)
self.table.setRowCount(2)
self.table.setColumnWidth(0, 200)
self.table.setColumnWidth(1, 150)
self.table.setColumnWidth(2, 150)
self.table.setHorizontalHeaderLabels(['xvalue', 'yarray', 'zarray'])
self.combox = NumericDataCombo(self.ap.df)
self.comboy = NumericDataCombo(self.ap.df)
self.comboz = NumericDataCombo(self.ap.df)
self.table.setCellWidget(0, 0, self.combox)
self.table.setCellWidget(0, 1, self.comboy)
self.table.setCellWidget(0, 2, self.comboz)
self.mk_buttons()
def mk_buttons(self):
self.bt_update = QPushButton('Update', self)
self.bt_update.clicked.connect(self.update_from_h5)
self.table.setCellWidget(1, 1, self.bt_update)
def update_data_extractor(self):
idxx = self.combox.get_idx()
idxy = self.comboy.get_idx()
idxz = self.comboz.get_idx()
if idxx not in self.data_extractor.data_extractors:
if idxx[0] == 'shot number':
self.data_extractor[idxx] = EmptyDataExtractor()
else:
self.data_extractor[idxx] = SingleDataExtractor(idxx)
if idxy not in self.data_extractor.data_extractors:
if idxy[0] == 'shot number':
self.data_extractor[idxy] = EmptyDataExtractor()
else:
self.data_extractor[idxy] = SingleDataExtractor(idxy)
if idxz not in self.data_extractor.data_extractors:
if idxz[0] == 'shot number':
self.data_extractor[idxz] = EmptyDataExtractor()
else:
self.data_extractor[idxz] = SingleDataExtractor(idxz)
self.data_extractor.clean_children([idxx, idxy, idxz])
self.data_extractor.clean_memory(self.ap.h5_paths)
def update(self, murks=None):
xs = np.array([])
ys = np.array([])
zs = np.array([])
idxx = self.combox.get_idx()
idxy = self.comboy.get_idx()
idxz = self.comboz.get_idx()
for i, h5_path in enumerate(self.ap.h5_paths_selected):
data = self.data_extractor.get_data(h5_path)[0]
if idxx[0] == 'shot number':
xs = np.append(xs, self.ap.shotselector.get_selected_indices()[0][i])
else:
xs = np.append(xs, data[idxx])
if idxy[0] == 'shot number':
ys = np.append(ys, self.ap.shotselector.get_selected_indices()[0][i])
else:
ys = np.append(ys, data[idxy])
if idxz[0] == 'shot number':
zs = np.append(zs, self.ap.shotselector.get_selected_indices()[0][i])
else:
zs = np.append(zs, data[idxz])
# here we don't want to assume that the data is on a grid
# this can happen if the parameters where changed between two sweeps
xi = np.linspace(xs.min(), xs.max(), 200)
yi = np.linspace(ys.min(), ys.max(), 200)
Xi, Yi = np.meshgrid(xi, yi)
Zi = griddata((xs, ys), zs, (Xi, Yi), 'nearest')
self.img.setImage(Zi.T)
self.iso.setData(Zi.T)
self.data_img = Zi
# set position and scale of image
newscalex = xi[1] - xi[0]
newscaley = yi[1] - yi[0]
transx = (xi[0] - (self.cx - 0.5 * self.scalex)) / newscalex - 0.5
transy = (yi[0] - (self.cy - 0.5 * self.scaley)) / newscaley - 0.5
self.img.scale(newscalex / self.scalex, newscaley / self.scaley)
self.img.translate(transx, transy)
self.scalex = newscalex
self.scaley = newscaley
self.cx = xi[0]
self.cy = yi[0]
def updateIsocurve(self):
self.iso.setLevel(self.isoLine.value())
def imageHoverEvent(self, event):
"""Show the position, pixel, and value under the mouse cursor.
"""
if event.isExit():
self.plot.setTitle("")
return
pos = event.pos()
i, j = pos.y(), pos.x()
i = int(np.clip(i, 0, self.data_img.shape[0] - 1))
j = int(np.clip(j, 0, self.data_img.shape[1] - 1))
val = self.data_img[i, j]
ppos = self.img.mapToParent(pos)
x, y = ppos.x(), ppos.y()
self.plot.setTitle("pos: (%0.1f, %0.1f) value: %g" % (x, y, val))

View File

@ -0,0 +1,55 @@
import pyqtgraph as pg
from PyQt5.QtWidgets import *
class QuickPlotGenerator(pg.LayoutWidget):
def __init__(self, ap, **kwargs):
super().__init__(**kwargs)
self.ap = ap
self.title = QLabel('<h2> Quick Plot Generator <\h2>')
self.addWidget(self.title, colspan=2)
self.nextRow()
self.newlayout = pg.LayoutWidget()
self.newlayout.addWidget(QLabel('Make new plot'))
self.newlayout.nextRow()
self.newlayout.addWidget(QLabel('Title: '))
self.title_le = QLineEdit('murks')
self.newlayout.addWidget(self.title_le)
self.newlayout.nextRow()
self.bt1d = QPushButton('make 1D plot', self)
self.newlayout.addWidget(self.bt1d)
self.bt1d.clicked.connect(self.mk1dplot)
self.btwaterfall = QPushButton('make waterfall plot', self)
self.newlayout.addWidget(self.btwaterfall)
self.btwaterfall.clicked.connect(self.mkwaterfallplot)
self.bt2d = QPushButton('make 2d plot', self)
self.newlayout.addWidget(self.bt2d)
self.bt2d.clicked.connect(self.mk2dplot)
self.addWidget(self.newlayout)
def mk1dplot(self):
title = self.title_le.text()
self.ap.add_plot_dock(title, Quick1DPlot(self.ap), MultiDataExtractor(), closable=True)
def mkwaterfallplot(self):
title = self.title_le.text()
self.ap.add_plot_dock(title, QuickWaterfallPlot(self.ap), MultiDataExtractor(), closable=True)
def mk2dplot(self):
title = self.title_le.text()
self.ap.add_plot_dock(title, Quick2DPlot(self.ap), MultiDataExtractor(), closable=True)

View File

@ -0,0 +1,197 @@
class ArrayDataCombo(ExtendedCombo):
def __init__(self, h5_paths, **kwargs):
super().__init__(**kwargs)
self.update_model(h5_paths)
def update_model(self, h5_paths):
results_array_labels = set([])
for h5_path in h5_paths:
with h5py.File(h5_path, 'r') as h5_file:
analysis_names = h5_file['results'].keys()
for analysis_name in analysis_names:
for key in h5_file['results'][analysis_name].keys():
results_array_labels.add(analysis_name + ',' + key)
model = QtGui.QStandardItemModel()
item = QtGui.QStandardItem('shot number')
model.setItem(0, 0, item)
for i, idx in enumerate(results_array_labels):
item = QtGui.QStandardItem(idx)
model.setItem(i, 0, item)
self.setModel(model)
def get_idx(self):
return tuple(str(self.currentText()).split(','))
class QuickWaterfallPlot(QuickDataPlot):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.img = pg.ImageItem()
self.plot.addItem(self.img)
# Isocurve draplotsg
self.iso = pg.IsocurveItem(level=1000, pen=color_palette[2])
self.iso.setParentItem(self.img)
self.iso.setZValue(5)
# Contrast/color control
self.hist = pg.HistogramLUTItem()
self.hist.setImageItem(self.img)
self.plots.addItem(self.hist)
# Draggable line for setting isocurve level
self.isoLine = pg.InfiniteLine(angle=0, movable=True, pen=color_palette[2])
self.hist.vb.addItem(self.isoLine)
self.hist.vb.setMouseEnabled(y=False) # makes user interaction a little easier
self.isoLine.setValue(1000)
self.isoLine.setZValue(1000) # bring iso line above contrast controls
self.isoLine.sigDragged.connect(self.updateIsocurve)
# Monkey-patch the image to use our custom hover function.
# This is generally discouraged (you should subclass ImageItem instead),
# but it works for a very simple use like this.
self.img.hoverEvent = self.imageHoverEvent
self.img.translate(-0.5, -0.5)
self.scalex = 1
self.scaley = 1
self.cx = 0
self.cy = 0
self.nplots = 0
self.table.setColumnCount(3)
self.table.setRowCount(2)
self.table.setColumnWidth(0, 200)
self.table.setColumnWidth(1, 150)
self.table.setColumnWidth(2, 150)
self.table.setHorizontalHeaderLabels(['xvalue', 'yarray', 'zarray'])
self.combox = NumericDataCombo(self.ap.df)
self.comboy = ArrayDataCombo(self.ap.h5_paths)
self.comboz = ArrayDataCombo(self.ap.h5_paths)
self.table.setCellWidget(0, 0, self.combox)
self.table.setCellWidget(0, 1, self.comboy)
self.table.setCellWidget(0, 2, self.comboz)
self.mk_buttons()
def mk_buttons(self):
self.bt_update = QPushButton('Update', self)
self.bt_update.clicked.connect(self.update_from_h5)
self.table.setCellWidget(1, 1, self.bt_update)
def update_data_extractor(self):
idxx = self.combox.get_idx()
idxy = self.comboy.get_idx()
idxz = self.comboz.get_idx()
if idxx not in self.data_extractor.data_extractors:
if idxx[0] == 'shot number':
self.data_extractor[idxx] = EmptyDataExtractor()
else:
self.data_extractor[idxx] = SingleDataExtractor(idxx)
if idxy not in self.data_extractor.data_extractors:
self.data_extractor[idxy] = ArrayDataExtractor(idxy)
if idxz not in self.data_extractor.data_extractors:
self.data_extractor[idxz] = ArrayDataExtractor(idxz)
self.data_extractor.clean_children([idxx, idxy, idxz])
self.data_extractor.clean_memory(self.ap.h5_paths)
def update(self, data=None):
xs = np.array([])
ys = np.array([])
zs = np.array([])
idxx = self.combox.get_idx()
idxy = self.comboy.get_idx()
idxz = self.comboz.get_idx()
for i, h5_path in enumerate(self.ap.h5_paths_selected):
data = self.data_extractor.get_data(h5_path)[0]
if idxx[0] == 'shot number':
x = self.ap.shotselector.get_selected_indices()[0][i]
else:
x = data[idxx]
y = data[idxy]
z = data[idxz]
if y is not None and z is not None:
xs = np.append(xs, x * np.ones_like(y))
ys = np.append(ys, y)
zs = np.append(zs, z)
elif y is not None:
xs = np.append(xs, x * np.ones_like(y))
ys = np.append(ys, y)
zs = np.append(zs, y * np.nan)
elif z is not None:
xs = np.append(xs, x * np.ones_like(z))
ys = np.append(ys, z * np.nan)
zs = np.append(zs, z)
# here we don't want to assume that the data is on a grid
# this can happen if the parameters where changed between two sweeps
xi = np.linspace(xs.min(), xs.max(), 200)
yi = np.linspace(ys.min(), ys.max(), 200)
Xi, Yi = np.meshgrid(xi, yi)
Zi = griddata((xs, ys), zs, (Xi, Yi), 'nearest')
self.img.setImage(Zi.T)
self.iso.setData(Zi.T)
self.data_img = Zi
# set position and scale of image
newscalex = xi[1] - xi[0]
newscaley = yi[1] - yi[0]
transx = (xi[0] - (self.cx - 0.5 * self.scalex)) / newscalex - 0.5
transy = (yi[0] - (self.cy - 0.5 * self.scaley)) / newscaley - 0.5
self.img.scale(newscalex / self.scalex, newscaley / self.scaley)
self.img.translate(transx, transy)
self.scalex = newscalex
self.scaley = newscaley
self.cx = xi[0]
self.cy = yi[0]
def updateIsocurve(self):
self.iso.setLevel(self.isoLine.value())
def imageHoverEvent(self, event):
"""Show the position, pixel, and value under the mouse cursor.
"""
if event.isExit():
self.plot.setTitle("")
return
pos = event.pos()
i, j = pos.y(), pos.x()
i = int(np.clip(i, 0, self.data_img.shape[0] - 1))
j = int(np.clip(j, 0, self.data_img.shape[1] - 1))
val = self.data_img[i, j]
ppos = self.img.mapToParent(pos)
x, y = ppos.x(), ppos.y()
self.plot.setTitle("pos: (%0.1f, %0.1f) value: %g" % (x, y, val))

View File

View File

@ -1 +1 @@
name = "dylab"
name = "HelperClasses"

View File

@ -2,7 +2,7 @@ from lyse import *
from pylab import *
import numpy as np
import scipy.constants as constant
from dylab import DyTransition, Camera
from HelperClasses import DyTransition, Camera
import matplotlib.pyplot as plt
from matplotlib import colors as mcolors
import colorsys

View File

@ -1,7 +1,7 @@
# Functions create constant dictionary storing transition information of Dy.
import scipy.constants as constant
from dylab import TransitionClass
from HelperClasses import TransitionClass
def creat_Dy421():

View File

@ -1,5 +1,5 @@
import numpy as np
from dylab import FittingFunction
from HelperClasses import FittingFunction
import laserbeamsize as lbs
import lmfit
from lmfit.minimizer import MinimizerResult

View File

@ -4,7 +4,7 @@ with open("README.md", "r") as fh:
long_description = fh.read()
setuptools.setup(
name="dylab",
name="HelperClasses",
version="0.0.2",
author="QF-group (AG Chomaz), Heidelberg university",
author_email="gao@physi.uni-heidelberg.de",

View File

@ -1,6 +1,12 @@
from lyse import *
from dylab import DyTransition, Camera, AbsorptionImaging
from HelperClasses import DyTransition, Camera, AbsorptionImaging, Plotting
import matplotlib.pyplot as plt
import matplotlib.style as mplstyle
import matplotlib
matplotlib.use("qt5agg")
mplstyle.use('fast')
absorption_imaging_transition = DyTransition.creat_Dy421()
mot_3D_camera = Camera.c11440_36u(absorption_imaging_transition['wavelength'])
@ -10,6 +16,11 @@ with AbsorptionImaging.absorption_imaging(path, 'MOT_3D_Camera', 'in_situ_absorp
absorption_image.select_effective_data((800, 500), (1000, 700))
absorption_image.get_atom_number()
absorption_image.plot_result(-0.05, 0.05)
print(absorption_image.atom_number)
plotting = Plotting.plotting_absorption_imaging(absorption_image)
plotting.four_plots()
# plotting.absorption_plots()

View File

@ -1,10 +1,10 @@
import laserbeamsize as lbs
from dylab import Fitting
from HelperClasses import Fitting
import numpy as np
import lmfit
import matplotlib.pyplot as plt
from dylab.FittingFunction import twoD_Gaussian
from HelperClasses.FittingFunction import twoD_Gaussian
xc = 300
yc = 200

57
test_living_plot.py Normal file
View File

@ -0,0 +1,57 @@
# -*- coding: utf-8 -*-
"""
Created on Thu Mar 11 14:58:18 2021
@author: Nick Sauerwein
"""
import lyse
import numpy as np
from HelperClasses.Plotting import WidgetFakeColorPlot, MainPlotPanel
import cProfile
import pstats
profile = cProfile.Profile()
profile.enable()
fm = lyse.figure_manager
h5_paths = lyse.h5_paths()
if lyse.spinning_top:
# If so, use the filepath of the current shot
h5_path = lyse.path
else:
# If not, get the filepath of the last shot of the lyse DataFrame
h5_path = lyse.h5_paths().iloc[-1]
print(h5_path)
if len(h5_paths):
last_globals = run = lyse.Run(h5_paths.iloc[-1]).get_globals()
if not hasattr(fm, 'ap'):
fm.ap = MainPlotPanel.MainPlotPanel(h5_paths)
# Imaging Methods
imagings = ['absorption_imaging']
cams = {'absorption_imaging': ['Cam_absorption']}
imaging = 'absorption_imaging'
for cam in cams[imaging]:
plot_name = imaging + ' ' + cam
if not plot_name in fm.ap.plots:
ip = WidgetFakeColorPlot.FakeColorPlot(plot_name, ('absorption_imaging', 'absorption_imaging'))
fm.ap.add_plot_dock(plot_name, ip)
fm.ap.update_h5_paths(h5_paths)
fm.ap.refresh(h5_path)
profile.disable()
ps = pstats.Stats(profile)
ps.sort_stats('cumtime')
ps.print_stats(10)