Skip to content

Commit

Permalink
updated plotIntensity and associated unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
carolinesands committed Feb 27, 2024
1 parent 8d2b220 commit 4068f23
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 52 deletions.
20 changes: 10 additions & 10 deletions Tests/test_plotting.py
Original file line number Diff line number Diff line change
Expand Up @@ -299,19 +299,19 @@ def test_plottic(self):

with tempfile.TemporaryDirectory() as tmpdirname:
outputPath = os.path.join(tmpdirname, 'basic')
nPYc.plotting.plotTIC(msData, savePath=outputPath)
nPYc.plotting.plotIntensity(msData, savePath=outputPath)
self.assertTrue(os.path.exists(outputPath))

outputPath = os.path.join(tmpdirname, 'noViolinByDetector')
nPYc.plotting.plotTIC(msData, addViolin=False, addBatchShading=True, savePath=outputPath)
nPYc.plotting.plotIntensity(msData, addViolin=False, addBatchShading=True, savePath=outputPath)
self.assertTrue(os.path.exists(outputPath))

outputPath = os.path.join(tmpdirname, 'withBatches')
nPYc.plotting.plotTIC(msData, addBatchShading=True, savePath=outputPath)
nPYc.plotting.plotIntensity(msData, addBatchShading=True, savePath=outputPath)
self.assertTrue(os.path.exists(outputPath))

outputPath = os.path.join(tmpdirname, 'logY')
nPYc.plotting.plotTIC(msData, logy= True, addViolin=False, savePath=outputPath)
nPYc.plotting.plotIntensity(msData, logy= True, addViolin=False, savePath=outputPath)
self.assertTrue(os.path.exists(outputPath))


Expand All @@ -324,7 +324,7 @@ def test_plottic_raises(self):
#print("all columns %s" % msData.sampleMetadata.columns.values)

#'Assay Role' is not a column and should trigger a ValueError
self.assertRaises(ValueError, nPYc.plotting.plotTIC, msData, colourBy='Assay Role')
self.assertRaises(ValueError, nPYc.plotting.plotIntensity, msData, colourBy='Assay Role')


def test_jointplotRSDvCorrelation(self):
Expand Down Expand Up @@ -887,27 +887,27 @@ def test_plotTICinteractive(self):
# Not checking output for correctness, just that we don't crash
##
with self.subTest(msg='Default'):
data = nPYc.plotting.plotTICinteractive(self.dataset)
data = nPYc.plotting.plotIntensityInteractive(self.dataset)
self.assertIsNotNone(data)


def test_plotTICinteractive_raises(self):

# Test y is valid
with self.subTest(msg="y must be either a value in dataset.featureMetadata['Feature Name'] or 'TIC'"):
self.assertRaises(ValueError, nPYc.plotting.plotTICinteractive, self.dataset, y='failstest')
self.assertRaises(ValueError, nPYc.plotting.plotIntensityInteractive, self.dataset, y='failstest')

# Test x is valid
with self.subTest(msg="x must be \'Run Order\' or \'Acquired Time\', and must be present as a column in dataset.sampleMetadata"):
self.assertRaises(ValueError, nPYc.plotting.plotTICinteractive, self.dataset, x='failstest')
self.assertRaises(ValueError, nPYc.plotting.plotIntensityInteractive, self.dataset, x='failstest')

# Test labelBy is valid
with self.subTest(msg='labelBy must be a column in dataset.sampleMetadata'):
self.assertRaises(ValueError, nPYc.plotting.plotTICinteractive, self.dataset, labelBy='failstest')
self.assertRaises(ValueError, nPYc.plotting.plotIntensityInteractive, self.dataset, labelBy='failstest')

# Test colourBy is valid
with self.subTest(msg='labelBy must be a column in dataset.sampleMetadata'):
self.assertRaises(ValueError, nPYc.plotting.plotTICinteractive, self.dataset, colourBy='failstest')
self.assertRaises(ValueError, nPYc.plotting.plotIntensityInteractive, self.dataset, colourBy='failstest')

def test_plotSolventResonaceInteractive(self):
dataset = generateTestDataset(10, 1000, dtype='NMRDataset',
Expand Down
4 changes: 2 additions & 2 deletions nPYc/plotting/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
from ._plotNMRsolvent import plotSolventResonance, plotSolventResonanceInteractive
from ._jointplotRSDvCorrelation import jointplotRSDvCorrelation
from ._plotRSDs import plotRSDs, plotRSDsInteractive
from ._plotTIC import plotTIC, plotTICinteractive
from ._plotTIC import plotIntensity, plotIntensityInteractive
from ._plotIonMap import plotIonMap
from ._plotBatchAndROCorrection import plotBatchAndROCorrection
from ._multivariatePlotting import plotScree, plotScores, plotOutliers, plotLoadings, plotScoresInteractive, plotLoadingsInteractive, plotMetadataDistribution
Expand All @@ -38,7 +38,7 @@
from ._correlationSpectroscopy import correlationSpectroscopyInteractive
from ._plotTargetedFeatureDistribution import plotTargetedFeatureDistribution

__all__ = ['histogram', 'checkAndSetPlotAttributes','plotBatchAndROCorrection', 'plotTIC', 'plotTICinteractive', 'plotLRTIC', 'jointplotRSDvCorrelation', 'plotCorrelationToLRbyFeature',
__all__ = ['histogram', 'checkAndSetPlotAttributes','plotBatchAndROCorrection', 'plotIntensity', 'plotIntensityInteractive', 'plotLRTIC', 'jointplotRSDvCorrelation', 'plotCorrelationToLRbyFeature',
'plotIonMap', 'plotRSDs', 'plotRSDsInteractive', 'plotScree', 'plotOutliers', 'plotSpectralVariance', 'plotScores', 'plotScoresInteractive',
'plotLoadings', 'plotLoadingsInteractive', 'plotDiscreteLoadings', 'plotFeatureRanges', 'plotMetadataDistribution', 'plotLOQRunOrder',
'plotFeatureLOQ', 'plotVariableScatter', 'plotAccuracyPrecision', 'plotCalibrationInteractive', 'plotLineWidth', 'plotLineWidthInteractive',
Expand Down
68 changes: 38 additions & 30 deletions nPYc/plotting/_plotTIC.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import plotly
import plotly.graph_objs as go
import matplotlib.pyplot as plt
import seaborn as sns
import numpy
import pandas
import copy
Expand All @@ -10,9 +9,7 @@
from ..enumerations import AssayRole, SampleType
from ..utilities.generic import createDestinationPath
from ..objects import Dataset
from ..plotting._multivariatePlotting import _shiftedColorMap
from matplotlib.colors import Normalize
import matplotlib.cm as cm
from matplotlib.colors import rgb2hex
import matplotlib.dates as mdates
from matplotlib.dates import MO, TU, WE, TH, FR, SA, SU
from matplotlib.dates import WeekdayLocator
Expand All @@ -22,7 +19,7 @@
import os
import datetime

def plotTIC(dataset, addViolin=True, addBatchShading=False,
def plotIntensity(dataset, addViolin=True, addBatchShading=False,
colourBy='SampleClass', colourType='categorical',
colourDict=None, markerDict=None, abbrDict=None,
logy=False, title='',
Expand Down Expand Up @@ -52,13 +49,12 @@ def plotTIC(dataset, addViolin=True, addBatchShading=False,
:param figureSize: Dimensions of the figure
:type figureSize: tuple(float, float)
"""
#print("plotTIC colourBy = %s" % colourBy)

# Check inputs
if not isinstance(dataset, Dataset):
raise TypeError('dataset must be an instance of nPYc.Dataset')

if colourBy not in dataset.sampleMetadata.columns:
#print(dataset.sampleMetadata.columns.values)
raise ValueError('colourBy must be a column in dataset.sampleMetadata')

if not (('Acquired Time' in dataset.sampleMetadata.columns) or ('Run Order' in dataset.sampleMetadata.columns)):
Expand All @@ -85,8 +81,9 @@ def plotTIC(dataset, addViolin=True, addBatchShading=False,
# Otherwise create colour dict
else:
colourDict = {}
colors = iter(plt.cm.rainbow(numpy.linspace(0, 1, len(uniq))))
for u in uniq:
colourDict[u] = 'blue' # TODO CAZ iterate through colours
colourDict[u] = rgb2hex(next(colors))

# If markerDict check colour defined for every unique entry in class
if markerDict is not None:
Expand Down Expand Up @@ -147,13 +144,11 @@ def plotTIC(dataset, addViolin=True, addBatchShading=False,
acqTime = msData.sampleMetadata['Run Order']

tic = numpy.sum(msData.intensityData[:, tempFeatureMask == True], axis=1)
#tic = numpy.sum(msData.intensityData, axis=1)

# Colour by categorical class
if colourType == 'categorical':
#uniq = msData.sampleMetadata[colourBy].unique() defined above
palette = {}
sampleMasks = [] # sampleMasks = list()
sampleMasks = []
for u in uniq:
sc = ax.scatter(acqTime[msData.sampleMetadata[colourBy] == u],
tic[msData.sampleMetadata[colourBy] == u],
Expand Down Expand Up @@ -232,7 +227,7 @@ def plotTIC(dataset, addViolin=True, addBatchShading=False,
colIX = colIX + 1

# Annotate figure
ax.set_ylabel('Sum of all Feature Intensities')
ax.set_ylabel('Sum of Feature Intensities')
ax.set_xticklabels(ax.xaxis.get_majorticklabels(), rotation=45)
if ('Acquired Time' in msData.sampleMetadata.columns):
ax.set_xlabel('Acquisition Date')
Expand All @@ -247,7 +242,7 @@ def plotTIC(dataset, addViolin=True, addBatchShading=False,
pass
if logy:
ax.set_yscale('log', nonpositive='clip')
ax.set_ylabel('TIC (log scale)')
ax.set_ylabel('Sum of Feature Intensities (log scale)')
else:
ax.ticklabel_format(style='sci', axis='y', scilimits=(0,0))

Expand All @@ -263,7 +258,6 @@ def plotTIC(dataset, addViolin=True, addBatchShading=False,
# Save or output
if savePath:
try:
#plt.savefig(savePath, bbox_extra_artists=(leg, ), bbox_inches='tight', format=figureFormat, dpi=dpi)
plt.savefig(savePath, bbox_inches='tight', format=figureFormat, dpi=dpi)

except UnboundLocalError:
Expand All @@ -274,22 +268,27 @@ def plotTIC(dataset, addViolin=True, addBatchShading=False,
plt.show()


def plotTICinteractive(dataset, x='Run Order', y='TIC', labelBy='Run Order',
colourBy='Correction Batch',
colourDict=None, markerDict=None, abbrDict=None,
withExclusions=True,
destinationPath=None, autoOpen=True, opacity=.6):
def plotIntensityInteractive(dataset,
x='Run Order',
y='Sum of Feature Intensities',
labelBy='Run Order',
colourBy='Correction Batch',
colourDict=None,
markerDict=None,
withExclusions=True,
destinationPath=None,
autoOpen=True,
opacity=.6):
"""
Interactively visualise TIC or intensity for a given feature with plotly, provides tooltips to allow identification of samples.
Interactively visualise sum of all feature intensities, or intensity for a given feature with plotly, provides tooltips to allow identification of samples.
:param MSDataset dataset: Dataset object
:param str x: X-axis of plot, either ``Run Order`` or ``Acquired Time``
:param str y: Y-axis of plot, either ``TIC`` for sum of all features, or a specific feature name
:param str y: Y-axis of plot, either ``Sum of Feature Intensities`` for sum of all features, or a specific feature name
:param str labelBy: dataset.sampleMetadata column entry to display in tooltips
:param str colourBy: dataset.sampleMetadata column entry to colour data points by
:param dict colourDict:
:param dict markerDict:
:param dict abbrDict:
:param bool withExclusions: If ``True``, only report on features and samples not masked by the sample and feature masks
:param str destinationPath: file path to save html version of plot
:param bool autoOpen: If ``True``, opens html version of plot
Expand All @@ -302,8 +301,8 @@ def plotTICinteractive(dataset, x='Run Order', y='TIC', labelBy='Run Order',
msData.applyMasks()

# Checks
if not (y in msData.featureMetadata['Feature Name'].values) | (y == 'TIC'):
raise ValueError("y must be either a value in dataset.featureMetadata['Feature Name'] or 'TIC'")
if not (y in msData.featureMetadata['Feature Name'].values) | (y == 'Sum of Feature Intensities'):
raise ValueError("y must be either a value in dataset.featureMetadata['Feature Name'] or 'Sum of Feature Intensities'")

if not ((x in msData.sampleMetadata.columns) & (x in {'Run Order', 'Acquired Time'})):
raise ValueError("x must be \'Run Order\' or \'Acquired Time\', and must be present as a column in dataset.sampleMetadata")
Expand All @@ -326,7 +325,7 @@ def plotTICinteractive(dataset, x='Run Order', y='TIC', labelBy='Run Order',
data = []

# Extract y values
if y == 'TIC':
if y == 'Sum of Feature Intensities':
tempFeatureMask = numpy.sum(numpy.isfinite(msData.intensityData), axis=0)
tempFeatureMask = tempFeatureMask < msData.intensityData.shape[0]
values = numpy.sum(msData.intensityData[:, tempFeatureMask == False], axis=1)
Expand All @@ -349,6 +348,11 @@ def plotTICinteractive(dataset, x='Run Order', y='TIC', labelBy='Run Order',
elif len(myset) > 1:
classes = classes.astype(str)

# If colourBy=='SampleClass' - NPC derived classes, then use default colours and markers
if colourBy=='SampleClass':
colourDict = msData.Attributes['sampleTypeColours']
markerDict = msData.Attributes['sampleTypeMarkers']

# Plot NaN values in gray
if sum(plotnans != 0):
NaNplot = go.Scatter(
Expand Down Expand Up @@ -386,13 +390,19 @@ def plotTICinteractive(dataset, x='Run Order', y='TIC', labelBy='Run Order',
data.append(CLASSplot)

# Plot categorical values by unique groups
# add colour/marker dictionaries here?
else:
uniq = numpy.unique(classes[plotnans == False])
if colourDict is None:

colourDict = {}
colors = iter(plt.cm.rainbow(numpy.linspace(0, 1, len(uniq))))
for u in uniq:
colourDict[u] = 'magenta'
colourDict[u] = rgb2hex(next(colors))

#colourDict = {}
#for u in uniq:
# colourDict[u] = 'magenta'

markerDict = {}
for u in uniq:
markerDict[u] = 'diamond-dot'
Expand All @@ -403,8 +413,6 @@ def plotTICinteractive(dataset, x='Run Order', y='TIC', labelBy='Run Order',
y=values[classes == i],
mode='markers',
marker=dict(
#colorscale='Portland',
#symbol='circle',
color=colourDict[i],
symbol=markerDict[i]
),
Expand All @@ -416,7 +424,7 @@ def plotTICinteractive(dataset, x='Run Order', y='TIC', labelBy='Run Order',
data.append(CLASSplot)

# Overlay SR and LTR if columns present
if ('SampleType' in msData.sampleMetadata.columns) & ('AssayRole' in msData.sampleMetadata.columns):
if (colourBy != 'SampleClass') & ('SampleType' in msData.sampleMetadata.columns) & ('AssayRole' in msData.sampleMetadata.columns):
SRmask = ((msData.sampleMetadata['SampleType'].values == SampleType.StudyPool) &
(msData.sampleMetadata['AssayRole'].values == AssayRole.PrecisionReference)) #SPmask
LTRmask = ((msData.sampleMetadata['SampleType'].values == SampleType.ExternalReference) &
Expand Down
2 changes: 1 addition & 1 deletion nPYc/reports/_finalReportPeakPantheR.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from .._toolboxPath import toolboxPath
from ..objects import MSDataset
from pyChemometrics.ChemometricsPCA import ChemometricsPCA
from ..plotting import plotTIC, histogram, plotLRTIC, jointplotRSDvCorrelation, plotRSDs, plotIonMap, plotBatchAndROCorrection, plotScores, plotLoadings, plotTargetedFeatureDistribution
from ..plotting import plotIntensity, histogram, plotLRTIC, jointplotRSDvCorrelation, plotRSDs, plotIonMap, plotBatchAndROCorrection, plotScores, plotLoadings, plotTargetedFeatureDistribution
from ._generateSampleReport import _generateSampleReport
from ..utilities import generateLRmask, rsd
from ..utilities._internal import _vcorrcoef
Expand Down
16 changes: 8 additions & 8 deletions nPYc/reports/_generateReportMS.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from .._toolboxPath import toolboxPath
from ..objects import MSDataset
from pyChemometrics.ChemometricsPCA import ChemometricsPCA
from ..plotting import plotTIC, histogram, plotLRTIC, jointplotRSDvCorrelation, plotRSDs, plotIonMap, plotBatchAndROCorrection, plotScores, plotLoadings, plotTargetedFeatureDistribution
from ..plotting import plotIntensity, histogram, plotLRTIC, jointplotRSDvCorrelation, plotRSDs, plotIonMap, plotBatchAndROCorrection, plotScores, plotLoadings, plotTargetedFeatureDistribution
from ._generateSampleReport import _generateSampleReport
from ..utilities import generateLRmask, rsd
from ..utilities._internal import _vcorrcoef
Expand Down Expand Up @@ -282,7 +282,7 @@ def _finalReport(dataset, destinationPath=None, pcaModel=None, reportType='final
print('Figure ' + str(figNo) + ': Acquisition Structure')
figNo = figNo + 1

plotTIC(dataset,
plotIntensity(dataset,
addViolin=True,
addBatchShading=True,
colourBy='SampleClass',
Expand All @@ -303,7 +303,7 @@ def _finalReport(dataset, destinationPath=None, pcaModel=None, reportType='final
print('Figure ' + str(figNo) + ': Total Ion Count (TIC) for all samples and all features in final dataset.')
figNo = figNo + 1

plotTIC(dataset,
plotIntensity(dataset,
addViolin=True,
title='',
colourBy='SampleClass',
Expand Down Expand Up @@ -564,7 +564,7 @@ def _featureReport(dataset, destinationPath=None):
print('Figure 2: Sample Total Ion Count (TIC) and distribution (coloured by sample type).')

# TIC all samples
plotTIC(dataset,
plotIntensity(dataset,
addViolin=True,
title='',
colourBy='SampleClass',
Expand Down Expand Up @@ -596,7 +596,7 @@ def _featureReport(dataset, destinationPath=None):
dataset.sampleMetadata['Change in Detector Voltage'] = detectorDiff

# TIC all samples
plotTIC(dataset,
plotIntensity(dataset,
addViolin=False,
addBatchShading=True,
colourBy='Change in Detector Voltage',
Expand Down Expand Up @@ -1036,7 +1036,7 @@ def _batchCorrectionAssessmentReport(dataset, destinationPath=None, batch_correc
else:
print('Overall Total Ion Count (TIC) for all samples and features, coloured by batch.')

plotTIC(dataset,
plotIntensity(dataset,
addViolin=True,
addBatchShading=True,
logy=logy,
Expand Down Expand Up @@ -1212,7 +1212,7 @@ def _batchCorrectionSummaryReport(dataset, correctedDataset, destinationPath=Non
print('Figure 2: Sample Total Ion Count (TIC) and distribution (coloured by sample type).')
print('Pre-correction.')

plotTIC(dataset,
plotIntensity(dataset,
addViolin=True,
title='TIC Pre Batch-Correction',
addBatchShading=False,
Expand All @@ -1233,7 +1233,7 @@ def _batchCorrectionSummaryReport(dataset, correctedDataset, destinationPath=Non
else:
print('Post-correction.')

plotTIC(correctedDataset,
plotIntensity(correctedDataset,
addViolin=True,
title='TIC Post Batch-Correction',
addBatchShading=False,
Expand Down
2 changes: 1 addition & 1 deletion nPYc/reports/_generateReportTargeted.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from matplotlib import gridspec
from .._toolboxPath import toolboxPath
from ..objects import TargetedDataset
from ..plotting import plotFeatureLOQ, plotLOQRunOrder, plotAccuracyPrecision, plotTIC, histogram, plotLRTIC, \
from ..plotting import plotFeatureLOQ, plotLOQRunOrder, plotAccuracyPrecision, plotIntensity, histogram, plotLRTIC, \
jointplotRSDvCorrelation, plotRSDs, plotIonMap, plotBatchAndROCorrection, \
plotScores, plotLoadings, plotTargetedFeatureDistribution
from ._generateSampleReport import _generateSampleReport
Expand Down

0 comments on commit 4068f23

Please sign in to comment.