Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update plotSpectra environment to allow addFragments returned list #348

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

guideflandre
Copy link

This PR is linked to this PSMatch issue and the discussed topics in #346

The motivation for this PR:

  1. addFragments used to throw an error when multiple spectra where called
  2. The new variable_modifications parameter necessitated a new addFragments function to distinguish annotations

The solution:
addFragments now returns a list of named elements (peptide sequence that includes modifications) containing a character() vector with the annotations. Each element of the list has an attribute linking the annotations to the spectrum it belonged to. In Spectra, the changes are located at the level of the presence of labels. It is assumed that most often than not, addFragments is called for labels. A quick check for variable modifications is also added (as plotSpectra doesn't support them yet). All three functions (plotSpectra, plotSpectraMirror and plotSpectraOverlay now support the version of addFragments in this PR).

This PR can only be accepted if the corresponding PR in PSMatch is accepted !! Otherwise, plotSpectra won't work.

Copy link
Member

@jorainer jorainer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR! I have however some questions.

Spectra.Rproj Outdated Show resolved Hide resolved
for (i in seq_len(nsp))
.plot_single_spectrum(x[i], xlab = xlab, ylab = ylab, type = type,
xlim = xlim, ylim = ylim, main = main[i],
col = col[[i]], labels = labels,
col = col[[i]], labels = labels[[i]],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if I understand it, labels can be either 1 or equal to the length of x - so, I guess above you would need to ensure that if labels is of length 1 it gets repeated length(x) times - otherwise you would get here an out-of-bound error.

Copy link
Author

@guideflandre guideflandre Jan 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs to be subject of discussion:

  1. labels could be of length 1 or equal to x, so if it is 1, repeat it length(x) times
  2. only accept labels as a function (= addFragments) that returns a list with unique attributes of length equal length(x), or accept labels as a list of length equal to length(x).

In the above, I used option 2) as I also used it for cases where variable modifications where used: which is also why there is an attribute to the elements of the returned list of addFragments. The attribute is an integer that corresponds to the spectrum that is called (if plotSpectra(sp[1:4], labels = addFragments is called, then addFragments returns a list of 4 elements. Each element can be matched to its corresponding spectrum thanks to the attribute)

if (is.function(labels)) {
labels <- labels(x)
}
mod_check <- sapply(labels, function(labels) attr(labels, "spectrumNumber"))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is this line? why does labels need attributes?

Copy link
Author

@guideflandre guideflandre Jan 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See the answer above. When variable modifications are called, the length of the returned list is longer than length(x). It is thus needed to match the annotation to its corresponding spectrum. This is in my personal use case and I can remove the attribute for this PR indeed.

The line checked and made sure the lengths are equal (actually just doing length(labels) == length(x) would suffice

@@ -217,10 +217,19 @@ plotSpectra <- function(x, xlab = "m/z", ylab = "intensity", type = "h",
main <- rep(main[1], nsp)
if (nsp > 1)
par(mfrow = n2mfrow(nsp, asp = asp))
if (length(labels)) {
if (is.function(labels)) {
labels <- labels(x)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you need to call a labels() function on the full Spectra object x? with the original code, the function would have been called on each spectrum individually (in the .plot_single_spectrum() function), so this would also avoid the need to support labels being a list.

In essence, the original plotSpectra() would call the labels() function on each individual spectrum, thus IMHO it would only require a labels() function that is able to extract whatever should be added/labeled from the spectra or peaks variables of that one spectrum. Would that not be possible in your case?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The essence of having labels return a list is twofold:

  1. addFragments used to throw an error when multiple Spectra were called when asking for a modification. This was because addFragments only accepted Spectra objects of length 1.
  2. In my personal use case of variable modifications, returning a list was the best option I had (including said attribute).

Thus this fixes a current Error, and it sets potential for variable modification.

@jorainer
Copy link
Member

General comment: I don't know your specific use case, but would it not be possible to add whatever information/annotation you have or calculate directly to the Spectra object (as peaks or spectra variables) before plotting and then have a labels() function that can extract that information (or that even calculates it on the fly)? that was also the initial idea of accepting a function with parameter labels.

@guideflandre
Copy link
Author

General comment: I don't know your specific use case, but would it not be possible to add whatever information/annotation you have or calculate directly to the Spectra object (as peaks or spectra variables) before plotting and then have a labels() function that can extract that information (or that even calculates it on the fly)? that was also the initial idea of accepting a function with parameter labels.

I believe we could if the number of annotations don't exceed length(x). In my use case, with variable modifications, I would have multiple annotations/spectrum which is not ideal.

@guideflandre
Copy link
Author

A discussion with Laurent led to a potential different idea: the creation of a package specifically for plotting spectra. I understand my use cases might not fit in well within the plotSpectra environment, and it might need its separate function/package. I believe this should be an option/discussed too.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants