简体   繁体   中英

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.

在此输入图像描述

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")

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()

在此输入图像描述

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()

在此输入图像描述

对我来说,看起来你想要vlines方法而不是plot方法。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM