Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Matplotlib: Vertical lines in scatter plot

I have posted a fair amount of code here and it's at the bottom of this post. The code opens a tkinter GUI with various buttons and fields etc. It also displays a graph at the very bottom using matplotlib. I understand that this isn't the best library to use but I have no idea how the others work with tkinter. So I would ideally like to stick with matplotlib for the time being.

For the chart I want each of the data points be a vertical lines from the [x, y] coordinate down to [x, 0]. The obvious answer is to use a bar chart with bar thinknesses of 1, I've tried this but the plotting speed is a lot slower than that of a scatter plot.

What I have been trying to figure out is whether it is possible to just use the scatter plot method used here with vertical lines draw to y=0. Is this possible?

Or should I scrap trying to use matplotlib and use pandas or PyQtGraph. If this is the case are there any tutorials that with show how this is done? I've tried to find some but have had no luck.

Any help would be much appreciated. I'm using pyzo package that uses python 3.3.

enter image description here

import numpy
from decimal import *
import tkinter as tk
import numpy as np
from tkinter import *
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
from tkinter import ttk
import tkinter.scrolledtext as tkst
import spectrum_plot_2 as specplot
import sequencer as seq

class Plot:
    def __init__(self, master, data):

        self.x = np.array(data.spectrum[0])
        self.y = np.array(data.spectrum[1])

        # Create a container
        self.frame = tk.Frame(master)

        self.fig = Figure()
        self.ax = self.fig.add_subplot(111)
        self.line = self.ax.plot(self.x, self.y, '|')


        self.canvas = FigureCanvasTkAgg(self.fig,master=master)
#         self.canvas.show()
        self.canvas.get_tk_widget().pack(side='top', fill='both', expand=1)
        self.frame.pack()

    def update(self, data):
        """Updates the plot with new data"""

        self.x = np.array(data.spectrum[0])
        self.y = np.array(data.spectrum[1])

        self.line[0].set_xdata(self.x)
        self.line[0].set_ydata(self.y)

        self.canvas.show()
        self.frame.pack()


class Spectrum:
    """(Spectrum, String, Decimal, int) -> None
       Import a spectrum from a text file
    """

    def __init__(self, file, precision = 4, charge_state = None, sensetivity = 50, name='Unknown'):

        self.precision = precision
        self.name = name
        self.file = file
        self.charge_state = charge_state
        self.spectrum = self.load_spec(file, precision)



    def load_spec(self, file, precision):
        """(Spectrum, String) -> list
           manipulate spectrum file and return a list of lists:
           list[0] = [mz]
           list[1] = [intensity]
        """

        raw_spectrum = numpy.loadtxt(file)

        # assign the spectrum to a dictionary
        intensity = ['%.0f' % elem for elem in raw_spectrum[:,1]]
        mz = ['%.4f' % elem for elem in raw_spectrum[:,0]]

        spectrum = [mz, intensity]

        for i in spectrum:
            for j, elem in enumerate(i):
                i[j] = round(Decimal(elem), precision)
            j = 0

        return [mz, intensity]


class View(ttk.Frame):
    """Main GUI class"""

    def __init__(self, master = None):

        self.WIDTH = 450
        self.HEIGHT = 500

        self.spectrum = seq.Spectrum(r'C:\MyPyProgs\Sequencer\data\s1c4b1.txt')
        self.spectra = {}
        self.spectra_names = []
        self.filenames = []

        ###############################
        ### User editable variables ###

        self.precision = IntVar(value=4, name='precision')
        self.sensitivity = IntVar(value = 50, name='sensitivity')

        ### User editable variables ###
        ###############################

        # Set up the main window
        ttk.Frame.__init__(self, master, borderwidth=5, width=self.WIDTH, height=self.WIDTH)
        self.master.resizable(FALSE, FALSE)
        self.grid(column=0, row=0, sticky=(N, S, E, W))
        self.columnconfigure(0, weight=1)

        # Create the upper control frame
        self.control_frame = ttk.Frame(self, width=self.WIDTH // 2, height=300, relief='sunken')
        self.control_label = ttk.Label(self.control_frame, text="Controls", font='arial', justify='center')

        # Precision controls definitions
        self.precision_label = ttk.Label(self.control_frame, text="Precision: ")
        self.precision_entry = ttk.Entry(self.control_frame, textvariable=self.precision)
        self.precision_help_button = ttk.Button(self.control_frame, text="Help")

        # Sensitivity controls definitions
        self.sensitivity_label = ttk.Label(self.control_frame, text="Sensitivity")
        self.sensitivity_entry = ttk.Entry(self.control_frame, textvariable=self.sensitivity)
        self.sensitivity_reload = ttk.Button(self.control_frame, text="Reload")
        self.sensitivity_help_button = ttk.Button(self.control_frame, text="Help")

        self.analyse_known_button = ttk.Button(self.control_frame, text="Analyse From Known")

        self.control_frame.grid(row=0, column=1, sticky=(N, E, S))
        self.control_label.grid(column=0, row=0, columnspan=4, sticky=(N), pady=5, padx=self.WIDTH // 5)

        ### Grid layouts ###
        # Precision controls grid
        self.precision_label.grid(column=0, row=1, padx=2)
        self.precision_entry.grid(column=1, row=1, padx=2)
        self.precision_help_button.grid(column=3, row=1, padx=2)

        # Sensitivity controls grid
        self.sensitivity_label.grid(column=0, row=2, padx=2)
        self.sensitivity_entry.grid(column=1, row=2, padx=2)
        self.sensitivity_reload.grid(column=2, row=2, padx=2)
        self.sensitivity_help_button.grid(column=3, row=2, padx=2)

        self.analyse_known_button.grid(column=1, row=3, columnspan=2)


        ### Output frame using ScrolledText ###
        self.output_frame = ttk.Frame(self, relief='sunken')
        self.output_frame.grid(row=0, column=0)

        self.output = tkst.ScrolledText(self.output_frame, width=45, height=20, wrap=WORD)
        self.output.grid(row=0, column=0, sticky=(N, S, E, W))
        self.output.see(END)

        self.output.insert(END, "Welcome, before you start make sure that the backbone and sugar structures are correct.  To analyse your spectra follow the steps below: \n 1. Type the known sequence into the text box from 5' to 3' and click assign.  \n 2. Load your spectra in order of charge, File -> Open Spectra... . \n 3. Finally click the Analyse From Known button.  \n")
        self.output['state']='disabled'

        ### Creates a sunken frame to get the sequence and choose loaded spectra ###
        self.input_frame = ttk.Frame(self, relief='sunken', borderwidth=5, width=self.winfo_width())
        self.input_frame.grid(row=1, column=0, columnspan=2, sticky=(E, W))

        self.spec_label = ttk.Label(self.input_frame, text="Spectrum:")
        self.selected_spec = StringVar()
        self.spec_select = ttk.Combobox(self.input_frame, values=self.spectra_names)

        self.spec_label.grid(row=0, column=6, padx=10)
        self.spec_select.grid(row=0, column=7)

        seq_entry_label = ttk.Label(self.input_frame, text="Sequence: ")
        label_5p = ttk.Label(self.input_frame, text="5'-")
        self.sequence_entry = ttk.Entry(self.input_frame, width=40)
        label_3p = ttk.Label(self.input_frame, text="-3'")
        assign_seq = ttk.Button(self.input_frame, text="Calculate", command=lambda : self.assign(self.sequence_entry))

        seq_entry_label.grid(row=0, column=0)
        label_5p.grid(row=0, column=1)
        self.sequence_entry.grid(row=0, column=2)
        label_3p.grid(row=0, column=3)
        assign_seq.grid(row=0, column=4)

        ### Creates a sunken frame to plot the current spectrum ###
        self.spec_frame = ttk.Frame(self, relief='sunken', borderwidth=1, width=self.winfo_width(), height=250)
        self.spec_frame.grid(row=2, column=0, columnspan=2, sticky=(S, E, W))

        self.plot = specplot.Plot(self.spec_frame, self.spectrum)

precision = 4
charge = -1
file = r'C:\MyPyProgs\sequencer\data\s1c4b1.txt'
spectrum = Spectrum(file, precision, charge)


if __name__ == "__main__":
    root = Tk()
    root.title("Sequencer_help")
    view = View(root)
    root.mainloop()
    print("End")
like image 667
Primigenia Avatar asked Jan 17 '14 17:01

Primigenia


2 Answers

In addition to @mgilson's suggestion of vlines (which does what you want but requires that you specify the bottom location), you should also have a look at stem.

For example:

import matplotlib.pyplot as plt
import numpy as np

x, y = np.random.random((2, 20))

fig, ax = plt.subplots()
ax.stem(x, y)
plt.show()

enter image description here

Or to leave out the dots:

import matplotlib.pyplot as plt
import numpy as np

x, y = np.random.random((2, 20))

fig, ax = plt.subplots()
ax.stem(x, y, markerfmt=' ')
plt.show()

enter image description here

like image 67
Joe Kington Avatar answered Oct 29 '22 06:10

Joe Kington


To me, it looks like you want the vlines method rather than the plot method.

like image 21
mgilson Avatar answered Oct 29 '22 08:10

mgilson