Update for plotting function.
This commit is contained in:
parent
c0b291f547
commit
cb1c9637d2
139
.idea/workspace.xml
generated
139
.idea/workspace.xml
generated
@ -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. Add selecting the effective area function in AbsorptionImaging.py. Optimaze plotting function.">
|
||||
<list default="true" id="68ddce6f-baaa-4bac-af24-443b9be545bf" name="Changes" comment="Debug for calculating atom number. Add background subtraction function. 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. Add background subtraction function. 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. Add selecting the effective area function in AbsorptionImaging.py. Optimaze plotting function." />
|
||||
<option name="LAST_COMMIT_MESSAGE" value="Debug for calculating atom number. Add selecting the effective area function in AbsorptionImaging.py. Optimaze plotting function." />
|
||||
<MESSAGE value="Debug for calculating atom number. Add background subtraction function. Correct the pixel size of the camera" />
|
||||
<option name="LAST_COMMIT_MESSAGE" value="Debug for calculating atom number. Add background subtraction function. 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>
|
@ -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
|
||||
|
@ -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():
|
@ -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
|
134
HelperClasses/Plotting/DataExtractorLyse.py
Normal file
134
HelperClasses/Plotting/DataExtractorLyse.py
Normal 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()
|
104
HelperClasses/Plotting/MainPlotPanel.py
Normal file
104
HelperClasses/Plotting/MainPlotPanel.py
Normal 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
|
172
HelperClasses/Plotting/PlottingData.py
Normal file
172
HelperClasses/Plotting/PlottingData.py
Normal 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
|
42
HelperClasses/Plotting/PlottingPanel.py
Normal file
42
HelperClasses/Plotting/PlottingPanel.py
Normal 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]
|
||||
|
128
HelperClasses/Plotting/Quick1DPlot.py
Normal file
128
HelperClasses/Plotting/Quick1DPlot.py
Normal 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])
|
188
HelperClasses/Plotting/Unknown.py
Normal file
188
HelperClasses/Plotting/Unknown.py
Normal 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(','))
|
131
HelperClasses/Plotting/WidgetDataSelector.py
Normal file
131
HelperClasses/Plotting/WidgetDataSelector.py
Normal 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),)
|
139
HelperClasses/Plotting/WidgetFakeColorPlot.py
Normal file
139
HelperClasses/Plotting/WidgetFakeColorPlot.py
Normal 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))
|
63
HelperClasses/Plotting/WidgetPlot.py
Normal file
63
HelperClasses/Plotting/WidgetPlot.py
Normal 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)
|
||||
|
166
HelperClasses/Plotting/WidgetQuick2DPlot.py
Normal file
166
HelperClasses/Plotting/WidgetQuick2DPlot.py
Normal 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))
|
55
HelperClasses/Plotting/WidgetQuickPlotGenerator.py
Normal file
55
HelperClasses/Plotting/WidgetQuickPlotGenerator.py
Normal 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)
|
197
HelperClasses/Plotting/WidgetQuickWaterFlowPlot.py
Normal file
197
HelperClasses/Plotting/WidgetQuickWaterFlowPlot.py
Normal 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))
|
0
HelperClasses/Plotting/__init__.py
Normal file
0
HelperClasses/Plotting/__init__.py
Normal file
@ -1 +1 @@
|
||||
name = "dylab"
|
||||
name = "HelperClasses"
|
@ -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
|
||||
|
@ -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():
|
||||
|
@ -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
|
||||
|
2
setup.py
2
setup.py
@ -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",
|
||||
|
@ -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()
|
||||
|
||||
|
@ -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
57
test_living_plot.py
Normal 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)
|
Loading…
Reference in New Issue
Block a user