diff --git a/motorlib/motor.py b/motorlib/motor.py index e0688d1..12f1da7 100644 --- a/motorlib/motor.py +++ b/motorlib/motor.py @@ -5,7 +5,7 @@ from . import geometry from .simResult import SimulationResult, SimAlert, SimAlertLevel, SimAlertType from .grains import EndBurningGrain -from .properties import PropertyCollection, FloatProperty, IntProperty +from .properties import PropertyCollection, FloatProperty, IntProperty, BooleanProperty from .constants import gasConstant, atmosphericPressure from scipy.optimize import newton import numpy as np @@ -28,7 +28,7 @@ def __init__(self): self.props['ambPressure'] = FloatProperty('Ambient Pressure', 'Pa', 0.0001, 102000) self.props['mapDim'] = IntProperty('Grain Map Dimension', '', 250, 2000) self.props['sepPressureRatio'] = FloatProperty('Separation Pressure Ratio', '', 0.001, 1) - + self.props['dualAxis'] = BooleanProperty('Use Dual-Axis Plotting When Applicable') class Motor(): diff --git a/uilib/defaults.py b/uilib/defaults.py index ef2d89c..add9e02 100644 --- a/uilib/defaults.py +++ b/uilib/defaults.py @@ -13,7 +13,8 @@ 'igniterPressure': 150 * 6895, # Deprecated, but needed for migration 'mapDim': 750, 'sepPressureRatio' : 0.4, # This is a good default value known as the Summerfield Criteria https://ntrs.nasa.gov/api/citations/19840011402/downloads/19840011402.pdf - 'flowSeparationWarnPercent': 0.05 + 'flowSeparationWarnPercent': 0.05, + 'dualAxis': False }, 'units': { 'm': 'in', diff --git a/uilib/fileIO.py b/uilib/fileIO.py index 26fd75a..f28882d 100644 --- a/uilib/fileIO.py +++ b/uilib/fileIO.py @@ -8,7 +8,7 @@ from .defaults import DEFAULT_PREFERENCES, DEFAULT_PROPELLANTS, KNSU_PROPS from .logger import logger -appVersion = (0, 6, 1) +appVersion = (0, 6, 2) appVersionStr = '.'.join(map(str, appVersion)) class fileTypes(Enum): @@ -67,6 +67,11 @@ def getConfigPath(): def passthrough(data): return data +#0.6.1 to 0.6.2 +def migrateMotor_0_6_1_to_0_6_2(data): + data['config']['dualAxis'] = DEFAULT_PREFERENCES['general']['dualAxis'] + return data + #0.6.0 to 0.6.1 def migrateMotor_0_6_0_to_0_6_1(data): data['config']['maxMachNumber'] = DEFAULT_PREFERENCES['general']['maxMachNumber'] @@ -170,11 +175,18 @@ def migrateMotor_0_2_0_to_0_3_0(data): return data migrations = { + (0, 6, 1): { + 'to': (0, 6, 2), + fileTypes.PREFERENCES: passthrough, + fileTypes.PROPELLANTS: passthrough, + fileTypes.MOTOR: migrateMotor_0_6_1_to_0_6_2, + fileTypes.RECENT_FILES: passthrough + }, (0, 6, 0): { 'to': (0, 6, 1), fileTypes.PREFERENCES: passthrough, fileTypes.PROPELLANTS: passthrough, - fileTypes.MOTOR: migrateMotor_0_6_0_to_0_6_1, + fileTypes.MOTOR: migrateMotor_0_6_0_to_0_6_1, fileTypes.RECENT_FILES: passthrough }, (0, 5, 0): { diff --git a/uilib/widgets/graphWidget.py b/uilib/widgets/graphWidget.py index 2673c78..e8803e0 100644 --- a/uilib/widgets/graphWidget.py +++ b/uilib/widgets/graphWidget.py @@ -1,5 +1,7 @@ from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas from matplotlib.figure import Figure +from mpl_toolkits.axisartist import SubplotHost +from mpl_toolkits.axes_grid1.parasite_axes import ParasiteAxes def selectGrains(data, grains): # Returns the data corresponding to specific grains from data structured like [[G1, G2], [G1, G2], [G1, G2]...] @@ -27,7 +29,10 @@ def setupPlot(self): self.figure.tight_layout() def plotData(self, simResult, xChannel, yChannels, grains): - self.plot.clear() + self.figure.clear() + self.plot = SubplotHost(self.figure, 111) + self.figure.add_subplot(self.plot) + self.figure.tight_layout() xAxisUnit = self.preferences.getUnit(simResult.channels[xChannel].unit) @@ -41,14 +46,23 @@ def plotData(self, simResult, xChannel, yChannels, grains): else: xData = simResult.channels[xChannel].getData(xAxisUnit) - for channelName in yChannels: + for channelNum, channelName in enumerate(yChannels): + plotter = self.plot + if self.preferences.getDict()['general']['dualAxis'] and len(yChannels) == 2 and channelNum == 1: + self.figure.subplots_adjust(right=0.9, left=0.1) + plotter = ParasiteAxes(self.plot, sharex=self.plot) + self.plot.parasites.append(plotter) + plotter.axis['right'].set_visible(True) + plotter.axis['left'].set_visible(False) + self.figure.add_axes(plotter) + channel = simResult.channels[channelName] yUnit = self.preferences.getUnit(channel.unit) if channel.valueType in (list, tuple) and len(grains) > 0: yData = selectGrains(channel.getData(yUnit), grains) - self.plot.plot(xData, yData) + plotter.plot(xData, yData) elif channel.valueType in (int, float): - self.plot.plot(xData, channel.getData(yUnit)) + plotter.plot(xData, channel.getData(yUnit)) if channel.valueType in (int, float): if yUnit != '': legend.append('{} - {}'.format(channel.name, yUnit)) @@ -61,6 +75,14 @@ def plotData(self, simResult, xChannel, yChannels, grains): legend.append('{} - Grain {} - {}'.format(channel.name, i + 1, yUnit)) else: legend.append('{} - Grain {}'.format(channel.name, i + 1)) + + if self.preferences.getDict()['general']['dualAxis'] and len(yChannels) == 2: + plotter2 = self.plot if channelNum == 0 else plotter + if yUnit != '': + plotter2.set_ylabel('{} - {}'.format(channel.name, yUnit)) + else: + plotter2.set_ylabel(channel.name) + self.plot.legend(legend) self.plot.set_xlabel('{} - {}'.format(simResult.channels[xChannel].name, xAxisUnit)) self.plot.grid(True)