#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# This file is part of the `lipyd` python module
#
# Copyright (c) 2015-2018 - EMBL
#
# File author(s): Dénes Türei (turei.denes@gmail.com)
#
# Distributed under the GNU GPLv3 License.
# See accompanying file LICENSE.txt or copy at
# http://www.gnu.org/licenses/gpl-3.0.html
#
# Website: http://www.ebi.ac.uk/~denes
#
#
# The spectrum plotting based on code by Martin Noehrer
# See original at https://github.com/matrixx567/MassSpectraPlot
#
import imp
import pandas as pd
import numpy as np
import math as mt
import matplotlib.pyplot as plt
from matplotlib import rcParams
[docs]class SpectrumPlot(object):
filetype = "pdf" # "png" or "pdf"
"""str: Filetype of the outputfile
Tested with "pdf" and "png"
"""
figdpi = 200
"""int: DPI of the image output file
"""
# correct DPI of figure if using pdf
if filetype.lower() == "pdf":
figdpi = 72
params = {'backend': 'pdf',
'figure.dpi': figdpi, # 72 for pdf
'axes.labelsize': 10,
'font.size': 10,
'legend.fontsize': 8,
'legend.frameon': True,
'xtick.labelsize': 8,
'ytick.labelsize': 8,
'font.family': 'serif',
'text.usetex': True,
'text.latex.unicode': True,
'axes.linewidth': 0.5,
'xtick.major.size': 4, # major tick size in points
'xtick.minor.size': 2, # minor tick size in points
'xtick.direction': 'out',
'ytick.major.size': 4, # major tick size in points
'ytick.minor.size': 2, # minor tick size in points
'ytick.direction': 'out',
}
plt.rcParams.update(params)
def __init__(
self,
mzs,
intensities,
annotations = None,
xmin = None,
xmax = None,
title = None,
):
self.mzs = mzs
self.intensities = intensities
self.annotations = annotations
self.xmin = xmin or int(min(self.mzs) / 10.0) * 10
self.xmax = xmax or int(max(self.mzs) / 10.0 + 1) * 10
self.title = title
[docs] def reload(self):
modname = self.__class__.__module__
mod = __import__(modname, fromlist=[modname.split('.')[0]])
imp.reload(mod)
new = getattr(mod, self.__class__.__name__)
setattr(self, '__class__', new)
[docs] def normalize_intensities(self):
self.inorm = self.intensities / np.max(self.intensities) * 100.0
@staticmethod
def __get_max_peak(x_value, raw_values):
"""
Search for the local peak next to the x-value.
The value searches in the near area of the given x-value for the maximum (local)
peak, which correspondends to the data.
Args:
x_value (float): m/z value (x-coordinate) of the point, to be annotated
raw_values (Pandas.DataFrame): Data values, which should be annotated
Returns:
y value of the peak, next to the given x value
"""
raw_values_index = raw_values[raw_values["m/z"] == x_value].index[0]
value, index = float(raw_values.loc[raw_values_index - 5, "intensity_normalized"]), raw_values_index - 5
for z in range(-5, 15):
if float(raw_values.loc[raw_values_index + z, "intensity_normalized"]) > value:
value, index = float(raw_values.loc[raw_values_index + z, "intensity_normalized"]), raw_values_index + z
return value
[docs] def annotate_point(x1, y_pos=0, text='', raw_values=None):
"""
Annotate a specific point.
Annotate a point with a label. The label will be placed vertically
with an additional line.
The function uses the data values and searches for the peak of the
value to be annotated. Therefore the ``raw_values`` parameter is used
Args:
-----
x1 (float):
m/z value (x-coordinate) of the point, to be annotated
y_pos (Optional[float]):
Position of the label beginning (y-coordinate).
The value uses the scale of the datapoints.
text (str):
Label text
raw_values (Pandas.DataFrame):
Data values, which should be annotated
"""
delta_point_annotate_line_pixel = 1
if raw_values is not None:
if __get_max_peak(x1, raw_values) < (y_pos - delta_point_annotate_line_pixel):
xy_text = (x1, y_pos)
else:
xy_text = (x1, __get_max_peak(x1, raw_values) + delta_point_annotate_line_pixel)
plt.annotate(
text, xy=(x1, __get_max_peak(x1, raw_values) + delta_point_annotate_line_pixel), xycoords='data',
xytext=xy_text, textcoords='data',
rotation=90, size=8, horizontalalignment='center', verticalalignment='bottom',
arrowprops=dict(arrowstyle='-', color="#808080", linewidth=0.4, shrinkA=0.05, shrinkB=1))
[docs] def annotate_distance(x1=0, x2=0, y_pos=0, text='', raw_values=None, rotate_text=0):
"""
Annotage the distance between two peaks
Annotate the distance between two given peaks. The text can be placed with a
given angle.
Args
----
x1 (float):
m/z value (x-coordinate) of the left point
x2 (float):
m/z value (x-coordinate) of the right point
y_pos (Optional[float]):
Position of the label beginning (y-coordinate).
The value uses the scale of the datapoints.
text (str):
Label text
raw_values (Pandas.DataFrame):
Data values, which should be annotated
rotate_text (Optional[int]):
Rotation of the label, should be 0 or 90
"""
delta_point_annotate_line_pixel = 1
if raw_values is not None:
if __get_max_peak(x1, raw_values) < (y_pos - delta_point_annotate_line_pixel):
plt.annotate(
'', xy=(x1, __get_max_peak(x1, raw_values) + delta_point_annotate_line_pixel), xycoords='data',
xytext=(x1, y_pos), textcoords='data',
arrowprops=dict(arrowstyle='-', color="#808080", linewidth=0.4, shrinkA=0.05, shrinkB=0.05))
if __get_max_peak(x2, raw_values) < (y_pos - delta_point_annotate_line_pixel):
plt.annotate(
'', xy=(x2, __get_max_peak(x2, raw_values) + delta_point_annotate_line_pixel), xycoords='data',
xytext=(x2, y_pos), textcoords='data',
arrowprops=dict(arrowstyle='-', color="#808080", linewidth=0.4, shrinkA=0.05, shrinkB=0.05))
plt.annotate(
'', xy=(x1, y_pos), xycoords='data',
xytext=(x2, y_pos), textcoords='data',
arrowprops=dict(arrowstyle='<|-|>,head_length=0.4,head_width=0.1',
color="black", linewidth=0.6, shrinkA=0.05, shrinkB=0.05))
plt.annotate(
text, xy=((x1 if x1 <= x2 else x2) + mt.fabs((x1 - x2)) / 2, y_pos), xycoords='data',
rotation=rotate_text, size=8,
horizontalalignment='center', verticalalignment='bottom',
xytext=(0, 2), textcoords='offset points')
# Helper functions
@staticmethod
def __figsize_and_margins(
plotsize,
subplots = (1, 1),
**absolute_margins,
):
"""Determine figure size and margins from plot size and absolute margins
Args:
plotsize: (width, height) of plot area in inch
subplots: (nrows, ncols) of subplots
left, right, top, bottom: absolute margins around plot area
wspace, hspace: width and height spacing between subplots
Returns:
size: figure size for figsize argument of figure()
margins: relative margins dict suitable for subplots_adjust()
Example: making 2x2 grid of 3" square plots with specific spacings:
sz, rm = figsize_and_margins((3,3), (2,2), left=1, right=.5,
top=.5, bottom=1,
wspace=.5, hspace=.5)
figure(figsize=sz)
subplots_adjust(**rm)
subplot(221); subplot(222)
subplot(223); subplot(224)
Source: http://scipy-central.org/item/65/1/absolute-plot-size-and-margins-in-matplotlib
"""
pw, ph = plotsize
nr, nc = subplots
amarg = absolute_margins
# dictionary for relative margins
# initialize from rcParams with margins not in amarg
rmarg = dict((m, rcParams['figure.subplot.' + m])
for m in ('left', 'right', 'top', 'bottom', 'wspace', 'hspace')
if m not in amarg
)
# subplots_adjust wants wspace and hspace relative to plotsize:
if 'wspace' in amarg:
rmarg['wspace'] = float(amarg['wspace']) / pw
if 'hspace' in amarg:
rmarg['hspace'] = float(amarg['hspace']) / ph
# in terms of the relative margins:
# width * (right - left)
# = ncols * plot_width + (ncols - 1) * wspace * plot_width
# height * (top - bottom)
# = nrows * plot_height + (nrows - 1) * hspace * plot_height
# solve for width and height, using absolute margins as necessary:
width = float((nc + (nc - 1) * rmarg['wspace']) * pw + amarg.get('left', 0) + amarg.get('right', 0)) / (
rmarg.get('right', 1) - rmarg.get('left', 0))
height = float((nr + (nr - 1) * rmarg['hspace']) * ph + amarg.get('top', 0) + amarg.get('bottom', 0)) / (
rmarg.get('top', 1) - rmarg.get('bottom', 0))
# now we can get any remaining relative margins
if 'left' in amarg:
rmarg['left'] = float(amarg['left']) / width
if 'right' in amarg:
rmarg['right'] = 1 - float(amarg['right']) / width
if 'top' in amarg:
rmarg['top'] = 1 - float(amarg['top']) / height
if 'bottom' in amarg:
rmarg['bottom'] = float(amarg['bottom']) / height
# return figure size and relative margins
return (width, height), rmarg
@staticmethod
def __get_ax_size(ax, fig):
"""
Source:
http://scipy-central.org/item/65/1/
absolute-plot-size-and-margins-in-matplotlib
"""
bbox = ax.get_window_extent().transformed(
fig.dpi_scale_trans.inverted()
)
width, height = bbox.width, bbox.height
width *= fig.dpi
height *= fig.dpi
return width, height
@staticmethod
def __conv_inch(length_mm):
"""Converts a length from millimeters to inch
Args:
-----
:param int,float length_mm :
Length in millimeters to be converted
Returns:
--------
float: The converted length in inch
"""
return length_mm / 25.4
[docs] def generate_massspectra_plot_automatic_labels(input_filename, output_filename):
print("Generate {0} mass spectra plot ({1}.{2}) from {3}.[xy/txt]".format(filetype.upper(), output_filename,
filetype, input_filename))
# min and max value of the x axis
min_xaxis = 50
max_xaxis = 425
# dimensions of the single plot
figwidth_mm = 141
left_margin_mm = 14
right_margin_mm = 2
top_margin_mm = 26
bottom_margin_mm = 13
plotwidth_mm = figwidth_mm - left_margin_mm - right_margin_mm
plotheight_mm = plotwidth_mm * 0.8
hspace_mm = 0.1 # horizontal space between two plots
# read xy input data
raw_values = pd.read_csv(input_filename + ".xy", sep=" ", names=["m/z", "intensity"],
dtype={"m/z": np.float64, "intensity": np.float64})
# normalize input data
max_val = np.max(raw_values['intensity'])
raw_values["intensity_normalized"] = raw_values['intensity'] / max_val * 100.0 # normalize intensity to percent
# read txt captions
caption_values = pd.read_csv(input_filename + ".txt", sep=";", names=["m/z", "caption"], dtype={"m/z": np.float64})
# find maximum value for each annotate peak - necessary for later calculation of annotation lines
for i in caption_values.index:
raw_values_index = raw_values[raw_values["m/z"] == caption_values.ix[i]["m/z"]].index[0]
value, index = float(raw_values.loc[raw_values_index - 5, "intensity_normalized"]), raw_values_index - 5
for z in range(-5, 15):
if float(raw_values.loc[raw_values_index + z, "intensity_normalized"]) > value:
value, index = float(raw_values.loc[raw_values_index + z, "intensity_normalized"]), raw_values_index + z
caption_values.loc[i, "m/z"] = float(raw_values.loc[index, "m/z"])
caption_values.loc[i, "intensity_normalized"] = value # add intensity to caption table
# dimension for the annotations in pixel
delta_x_text_labels_mm = 3.8
delta_point_annotate_line_mm = 1
label_annotate_arm_high_mm = 5.3
delta_y_diagonal_annotate_arm_mm = 3.5
delta_y_baseline_axistop_mm = 6.3
delta_label_mznumber_pixel_mm = 7
fsize, margins = __figsize_and_margins(plotsize=(__conv_inch(plotwidth_mm), __conv_inch(plotheight_mm)),
subplots=(1, 1),
left=__conv_inch(left_margin_mm), right=__conv_inch(right_margin_mm),
top=__conv_inch(top_margin_mm), bottom=__conv_inch(bottom_margin_mm),
wspace=0.01, hspace=__conv_inch(hspace_mm))
fig = plt.figure(figsize=fsize, )
plt.subplots_adjust(**margins)
ax = fig.add_subplot(111)
# delta_dimension in pixel calculate from mm
delta_x_text_labels_pixel = __conv_inch(delta_x_text_labels_mm) * fig.dpi
delta_point_annotate_line_pixel = __conv_inch(delta_point_annotate_line_mm) * fig.dpi
label_annotate_arm_high_pixel = __conv_inch(label_annotate_arm_high_mm) * fig.dpi
delta_y_diagonal_annotate_arm = __conv_inch(delta_y_diagonal_annotate_arm_mm) * fig.dpi
delta_y_baseline_axistop = __conv_inch(delta_y_baseline_axistop_mm) * fig.dpi
delta_label_mznumber_pixel = __conv_inch(delta_label_mznumber_pixel_mm) * fig.dpi
# plot spectra line
ax.plot(raw_values["m/z"], raw_values["intensity_normalized"], color="black", linewidth=0.8)
# set x axes range
if min_xaxis is not None and max_xaxis is not None:
ax.set_xlim([int(min_xaxis), int(max_xaxis)])
length_x_axis_pixel, length_y_axis_pixel = __get_ax_size(ax, fig)
x_axis_min, x_axis_max = ax.get_xlim()
y_axis_min, y_axis_max = ax.get_ylim()
list_text_pos = list()
if len(caption_values.index) > 0:
# annotate from basepeak
basepeak_index = caption_values[caption_values["intensity_normalized"] >= 100.0].index
if len(basepeak_index) == 0:
basepeak_index = [len(caption_values) / 2]
# annotate peaks left frome basepeak
for z in caption_values.loc[:basepeak_index[0], "m/z"].sort_index(ascending=False):
x_value_pixel = (z - x_axis_min) / (x_axis_max - x_axis_min) * length_x_axis_pixel
if len(list_text_pos) == 0:
list_text_pos.append(x_value_pixel)
else:
if x_value_pixel > list_text_pos[-1] + delta_x_text_labels_pixel:
list_text_pos.append(x_value_pixel)
else:
list_text_pos.append(list_text_pos[-1] + delta_x_text_labels_pixel)
# annotate peaks right from basepeak
if basepeak_index[0] + 1 in caption_values.index:
for z in caption_values.loc[basepeak_index[0] + 1:, "m/z"]:
x_value_pixel = (z - x_axis_min) / (x_axis_max - x_axis_min) * length_x_axis_pixel
if x_value_pixel < list_text_pos[0] - delta_x_text_labels_pixel:
list_text_pos.insert(0, x_value_pixel)
else:
list_text_pos.insert(0, list_text_pos[0] - delta_x_text_labels_pixel)
# move annotation to left, if the label is out of the axes range
if len(list_text_pos) > 0 and max(list_text_pos) >= length_x_axis_pixel:
print("move labels to left")
calc_delta = max(list_text_pos) - length_x_axis_pixel
for index in range(len(list_text_pos) - 1, 0, -1):
print("change", list_text_pos[index], calc_delta)
if index > 1 and list_text_pos[index] - calc_delta > list_text_pos[index - 1] + delta_x_text_labels_pixel:
list_text_pos[index] = list_text_pos[index] - calc_delta
break
else:
list_text_pos[index] = list_text_pos[index] - calc_delta
for i in caption_values.index:
label_x_pos = list_text_pos.pop()
x_value = float(caption_values.loc[i, "m/z"])
y_value = float(caption_values.loc[i, "intensity_normalized"])
label_text = str(caption_values.loc[i, "caption"])
x_value_pixel = (x_value - x_axis_min) / (x_axis_max - x_axis_min) * length_x_axis_pixel
y_value_pixel = (y_value - y_axis_min) / (y_axis_max - y_axis_min) * length_y_axis_pixel
label_y_pos_pixel = length_y_axis_pixel + delta_y_baseline_axistop
length_y_annotation_line = label_y_pos_pixel - y_value_pixel - delta_point_annotate_line_pixel
label_annotate_arm_low_pixel = length_y_annotation_line - label_annotate_arm_high_pixel - delta_y_diagonal_annotate_arm
if label_annotate_arm_low_pixel < 0:
label_annotate_arm_low_pixel = 0
ax.annotate("{:.0f}".format(x_value),
xy=(x_value_pixel, y_value_pixel + delta_point_annotate_line_pixel),
xycoords='axes pixels', rotation=90,
xytext=(label_x_pos, label_y_pos_pixel),
textcoords='axes pixels', size=8,
arrowprops=dict(arrowstyle="-",
connectionstyle="arc,angleA=-90,armA=" + str(label_annotate_arm_high_pixel) +
",angleB= 90,armB=" + str(label_annotate_arm_low_pixel) +
",rad=0", linewidth=0.5, color='#808080'),
horizontalalignment='center', verticalalignment='bottom')
ax.annotate(label_text,
xy=(x_value_pixel, y_value_pixel + delta_point_annotate_line_pixel),
xycoords='axes pixels', rotation=90,
xytext=(label_x_pos, label_y_pos_pixel + delta_label_mznumber_pixel),
textcoords='axes pixels', size=8,
horizontalalignment='center', verticalalignment='bottom'
)
# remove top and right axis
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.get_xaxis().tick_bottom()
ax.get_yaxis().tick_left()
# label axes
ax.set_xlabel(r"$m/z$")
ax.set_ylabel(r"$Intensity\,[\%]$")
# set x labels
plt.xticks(rotation='vertical')
start, end = ax.get_xlim()
ax.xaxis.set_ticks(np.arange(start, end + 1, 25))
# set y labels
ax.set_ylim(0, 100)
start, end = ax.get_ylim()
ax.yaxis.set_ticks(np.arange(start, end + 1, 10))
# set grid
plt.grid(True, axis="y", color='black', linestyle=':', linewidth=0.1)
plt.savefig(output_filename + "." + filetype, dpi=fig.dpi, format=filetype)
plt.close()
[docs] def annotate(self):
if self.annotations is None:
return
ann_idx = np.where(np.array([bool(a) for a in self.annotations]))
for i, annot in enumerate(self.annotations):
pass
self.annotate_point(403, 83, r'Peak II', raw_values)
self.annotate_point(253, 83, r'Peak I', raw_values)
annotate_distance(385, 403, 45, '$-18$', raw_values, rotate_text=90)
annotate_distance(367, 385, 45, '$-18$', raw_values, rotate_text=90)
annotate_distance(339, 367, 25, '$xy$', raw_values, rotate_text=90)
annotate_distance(321, 349, 35, '$xy$', raw_values, rotate_text=90)
annotate_distance(253, 349, 72, '$-96$', raw_values)
[docs] def build(self):
# dimensions of the single plot
figwidth_mm = 141
left_margin_mm = 14
right_margin_mm = 2
top_margin_mm = 5
bottom_margin_mm = 13
plotwidth_mm = figwidth_mm - left_margin_mm - right_margin_mm
plotheight_mm = plotwidth_mm * 0.8
hspace_mm = 0.1 # horizontal space between two plots
fsize, margins = self.__figsize_and_margins(
plotsize = (
self.__conv_inch(plotwidth_mm),
self.__conv_inch(plotheight_mm)
),
subplots = (1, 1),
left = self.__conv_inch(left_margin_mm),
right = self.__conv_inch(right_margin_mm),
top = self.__conv_inch(top_margin_mm),
bottom = self.__conv_inch(bottom_margin_mm),
wspace = 0.01,
hspace = self.__conv_inch(hspace_mm)
)
self.fig = plt.figure(figsize = fsize, )
plt.subplots_adjust(**margins)
self.ax = self.fig.add_subplot(111)
# plot spectra line
self.ax.plot(
self.mzs,
self.inorm,
color = "black",
linewidth = 0.8,
label = self.title,
)
# set x axes range
self.ax.set_xlim([self.xmin, self.xmax])
# annotations
# length in data value (in %)
self.annotate()
# remove top and right axis
self.ax.spines['top'].set_visible(False)
self.ax.spines['right'].set_visible(False)
self.ax.get_xaxis().tick_bottom()
self.ax.get_yaxis().tick_left()
# label axes
self.ax.set_xlabel(r"$m/z$")
self.ax.set_ylabel(r"$Intensity\,[\%]$")
# set x labels
plt.xticks(rotation = 'vertical')
start, end = self.ax.get_xlim()
self.ax.xaxis.set_ticks(np.arange(start, end + 1, 25))
# set y labels
self.ax.set_ylim(0, 100)
start, end = self.ax.get_ylim()
self.ax.yaxis.set_ticks(np.arange(start, end + 1, 10))
# set grid
plt.grid(
True,
axis = 'y',
color = 'black',
linestyle = ':',
linewidth = 0.1,
)
plt.savefig(self.outfile, dpi = self.fig.dpi, format = self.filetype)
plt.close()
[docs] def generate_massspectra_two_plot_manual_annotation(input_filename1, input_filename2, output_filename):
print("Generate {0} mass spectra plot ({1}.{2}) from {3}.xy and {4}.xy".format(filetype.upper(), output_filename,
filetype, input_filename1,
input_filename2))
# min and max value of the x axis
min_xaxis = 50
max_xaxis = 475
# labels
label1 = "Substance 1"
label2 = "Substance 2"
# dimensions of the single plot
figwidth_mm = 141
left_margin_mm = 14
right_margin_mm = 2
top_margin_mm = 5
bottom_margin_mm = 13
plotwidth_mm = figwidth_mm - left_margin_mm - right_margin_mm
plotheight_mm = plotwidth_mm * 0.8
hspace_mm = 25 # horizontal space between two plots
# read xy input data
raw_values1 = pd.read_csv(input_filename1 + ".xy", sep=" ", names=["m/z", "intensity"],
dtype={"m/z": np.float64, "intensity": np.float64})
# normalize input data
max_val = np.max(raw_values1['intensity'])
raw_values1["intensity_normalized"] = raw_values1['intensity'] / max_val * 100.0 # normalize intensity to percent
# read xy input data
raw_values2 = pd.read_csv(input_filename2 + ".xy", sep=" ", names=["m/z", "intensity"],
dtype={"m/z": np.float64, "intensity": np.float64})
# normalize input data
max_val = np.max(raw_values2['intensity'])
raw_values2["intensity_normalized"] = raw_values2['intensity'] / max_val * 100.0 # normalize intensity to percent
fsize, margins = __figsize_and_margins(plotsize=(__conv_inch(plotwidth_mm), __conv_inch(plotheight_mm)),
subplots=(1, 1),
left=__conv_inch(left_margin_mm), right=__conv_inch(right_margin_mm),
top=__conv_inch(top_margin_mm), bottom=__conv_inch(bottom_margin_mm),
wspace=0.01, hspace=__conv_inch(hspace_mm))
fig = plt.figure(figsize=fsize, )
plt.subplots_adjust(**margins)
ax = fig.add_subplot(211)
# plot spectra line
plt1, = ax.plot(raw_values1["m/z"], raw_values1["intensity_normalized"], color="black", linewidth=0.8, label=label1)
legend = plt.legend(handles=[plt1], loc=2)
legend.get_frame().set_linewidth(0)
# set x axes range
if min_xaxis is not None and max_xaxis is not None:
ax.set_xlim([int(min_xaxis), int(max_xaxis)])
# annotate plot1
annotate_point(253, 60, r'Peak 1', raw_values1)
annotate_distance(385, 403, 45, r'$-18$', raw_values1, rotate_text=90)
annotate_distance(367, 385, 45, r'$-18$', raw_values1, rotate_text=90)
annotate_distance(321, 349, 75, r'$xy$', raw_values1, rotate_text=0)
annotate_point(403, 60, r'Peak 2', raw_values1)
# remove top and right axis
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.get_xaxis().tick_bottom()
ax.get_yaxis().tick_left()
# label axes
ax.set_ylabel(r"$Intensity\,[\%]$")
# set x labels
plt.xticks(rotation='vertical')
start, end = ax.get_xlim()
ax.xaxis.set_ticks(np.arange(start, end + 1, 25))
# set y labels
ax.set_ylim(0, 100)
start, end = ax.get_ylim()
ax.yaxis.set_ticks(np.arange(start, end + 1, 10))
# set grid
plt.grid(True, axis="y", color='black', linestyle=':', linewidth=0.1)
# set x labels
plt.xticks(rotation='vertical')
start, end = ax.get_xlim()
ax.xaxis.set_ticks(np.arange(start, end + 1, 25))
# set y labels
ax.set_ylim(0, 100)
start, end = ax.get_ylim()
ax.yaxis.set_ticks(np.arange(start, end + 1, 10))
# set grid
plt.grid(True, axis="y", color='black', linestyle=':', linewidth=0.1)
# generate plot2
ax = fig.add_subplot(212)
plt2, = ax.plot(raw_values2["m/z"], raw_values2["intensity_normalized"], color="#606060", linewidth=0.8,
label=label2)
legend = plt.legend(handles=[plt2], loc=2)
legend.get_frame().set_linewidth(0)
# set x axes range
if min_xaxis is not None and max_xaxis is not None:
ax.set_xlim([int(min_xaxis), int(max_xaxis)])
# annotate
annotate_point(253, 60, r'Peak I', raw_values2)
annotate_point(189, 60, r'189', raw_values2)
annotate_point(215, 60, r'215', raw_values2)
annotate_distance(385, 445, 30, r'Multiple'"\n"r'line'"\n"'annotation', raw_values2)
annotate_distance(367, 385, 45, r' -18', raw_values2, rotate_text=90)
annotate_distance(349, 367, 45, r' -18', raw_values2, rotate_text=90)
annotate_distance(321, 349, 75, r'xy', raw_values2, rotate_text=0)
annotate_point(445, 60, r'Peak 2', raw_values2)
# remove top and right axis
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.get_xaxis().tick_bottom()
ax.get_yaxis().tick_left()
# label axes
ax.set_xlabel(r"$m/z$")
ax.set_ylabel(r"$Intensity\,[\%]$")
# set x labels
plt.xticks(rotation='vertical')
start, end = ax.get_xlim()
ax.xaxis.set_ticks(np.arange(start, end + 1, 25))
# set y labels
ax.set_ylim(0, 100)
start, end = ax.get_ylim()
ax.yaxis.set_ticks(np.arange(start, end + 1, 10))
# set grid
plt.grid(True, axis="y", color='black', linestyle=':', linewidth=0.1)
plt.savefig(output_filename + "." + filetype, dpi=fig.dpi, format=filetype)
plt.close()