I am trying to enter text in a GUI and make labels out of the entered text. I am creating buttons next to the created labels.
When these buttons are pressed, I want to delete the labels associated with those buttons. How can I do this?
Currently I have some code as follows:
import tkinter as tk
chosenvarlabel = []
cancelbutton = []
label_relyPlacement = 0.4 # these allow variables to be displayed one below the other after #confirmation
label_relyIncrement = 0.0
root = tk.Tk()
IntroCanvas = tk.Canvas(height = 300, width = 300)
IntroCanvas.pack()
def cancel():
pass
# chosenvarlabel[cancelbutton[]].place_forget() # unable to pass index here
def choose():
global label_relyIncrement, chosenvarlabel, cancelbutton
var1 = varentry1.get()
var2 = varentry2.get()
label_relyIncrement = label_relyIncrement + 0.1
chosenvarlabel.append(tk.Label(root, text = var1 + " " + var2))
chosenvarlabel[len(chosenvarlabel)-1].place(relx = 0.1, rely = label_relyPlacement + label_relyIncrement)
cancelbutton.append(tk.Button(root, text = ' X', command = cancel))
cancelbutton[len(chosenvarlabel)-1].place(relx = 0.6, rely = label_relyPlacement + label_relyIncrement)
varentry1 = tk.Entry(width = 6)
varentry1.place(relx = 0.2, rely = 0.2)
varentry2 = tk.Entry(width = 6)
varentry2.place(relx = 0.4, rely = 0.2)
myButton = tk.Button(root, text ='choose', command = choose)
myButton.place(relx = 0.6, rely = 0.2)
root.mainloop()
I am thinking since each button will be in the 'cancelbutton' list, if I pass the index of this button to the function 'cancel' somehow, the label of the same index in list chosenvarlabel will be deleted.
But I am unable to get the index using cancelbutton.index()
The cancelbutton list that is created is:
[<tkinter.Button object .!button2>,
<tkinter.Button object .!button3>,
<tkinter.Button object .!button4>]
But these elements cannot be accessed by 'index'. Why is that? How can I do this?
Thank you
R
If removing the associated label is the only task when the button is clicked, then the two lists are not necessary, you can just pass the label reference (and the button reference as well?) to cancel() function as below:
def cancel(btn, lbl):
# btn.destroy() # destroy the button as well???
lbl.destroy()
def choose():
global label_relyIncrement
var1 = varentry1.get()
var2 = varentry2.get()
label_relyIncrement += 0.1
lbl = tk.Label(root, text=var1+' '+var2)
lbl.place(relx=0.1, rely=label_relyPlacement+label_relyIncrement)
btn = tk.Button(root, text='X')
btn.place(relx=0.6, rely=label_relyPlacement+label_relyIncrement)
btn.config(command=lambda: cancel(btn, lbl))
Related
This is my first post so please tell me if I am breaking your rules! My problem is described in the comments of this simplified version of my code.
I want to plot an unrooted phylogenetic tree that neatly highlights selected clades.
I like the results of using geom_hilight() from ggtree with type = 'encircle', but I do not like having to individually edit the node and color values for every input. (see method 1)
method 2 is close to what I want, but with the wrong highlight type (roundrect)
method 3 uses the correct highlight type (encircle) but returns an error.
# I don't think all of these packages are needed to reproduce this problem
library(ape)
library(dplyr)
library(GGally)
library(ggalt)
library(ggforce)
library(ggplot2)
library(ggtree)
library(tidyr)
library(tidytree)
library(treeio)
#my pipeline uses the output of RAxML. I made this simpler tree for discussion purposes.
sink("test.tree")
cat("((((((t24:0.8024311261,t11:0.7828436729):0.3048173019,(t21:0.4867131179,t18:0.2167164627):0.7519672168):0.5776117099,t5:0.4223263576):0.5963104749,(t17:0.1558260066,t20:0.41109852):0.09447153704):0.2661841849,((((t6:0.009324073093,t12:0.2732205035):0.7790091021,t10:0.08588226303):0.3282297731,t9:0.2075715209):0.664191803,(((t15:0.5832811284,t14:0.8461383074):0.6081165755,t19:0.5950602938):0.7095833826,t8:0.7146228608):0.7801561591):0.6674923887):0.654328516,(((t13:0.6356930537,t3:0.8536336934):0.8644152461,t2:0.1784738901):0.7129137593,t23:0.8907998055):0.3618239218,((t16:0.1825823467,t7:0.8856151809):0.4720220205,(t22:0.672613536,(t1:0.9215354125,(t4:0.9248593273,t25:0.5937075356):0.3007316259):0.6941311779):0.6789765966):0.2112918347);")
sink()
#import tree
tree1 <- read.tree("test.tree")
#choose root nodes and colors for highlighting clades
group.roots <- c(34, 28, 44, 41)
group.colors <- c("#fd00fe", "#62ce75", "#9a1073", "#4ad9e1")
#write a data frame
g <- data.frame(gnode = group.roots, gfill = group.colors)
#
tree1unrooted <- ggtree(tree1,layout = 'unrooted')
#method 1: I want my plot to look like this, but I do not want to use so many instances of "geom_hilight()"
tree1unrooted + geom_label(aes(label = node)) +
geom_hilight(
node = 34,
alpha = 1,
fill = "#fd00fe",
type = "encircle",
to.bottom = TRUE
) +
geom_hilight(
node = 28,
alpha = 1,
fill = "#62ce75",
type = "encircle",
to.bottom = TRUE
) +
geom_hilight(
node = 44,
alpha = 1,
fill = "#9a1073",
type = "encircle",
to.bottom = TRUE
) +
geom_hilight(
node = 41,
alpha = 1,
fill = "#4ad9e1",
type = "encircle",
to.bottom = TRUE
)
#method 2: I have used this method to highlight multiple clades successfully with "type = 'roundrect'", but the highlighed regions overlap.
tree1unrooted +
geom_hilight(
data = g,
mapping = aes(node = gnode, fill = gfill),
alpha = 1,
type='roundrect',
to.bottom = TRUE
)
#method 3: I need "type = 'encircle'" for my plot. This gives the error: "Error in FUN(X[[i]], ...) : object 'x' not found"
tree1unrooted +
geom_hilight(
data = g,
mapping = aes(node = gnode, fill = gfill),
alpha = 1,
type='encircle',
to.bottom = TRUE
)
This seems like a bug to me, since one wouldn't think changing the fill shape should cause an error when a different shape works with the same syntax.
It appears that the data passed to the geom_hilight layer gets merged with the plot data, and for some reason this step goes with the "encircle" shape.
Anyway, one obvious solution is to program a list of single geom_hilight layers and add that to the plot:
tree1unrooted +
lapply(seq(nrow(g)), function(i) {
geom_hilight(
node = g$gnode[i],
alpha = 1,
fill = g$gfill[i],
type = "encircle",
to.bottom = TRUE
)
})
I'm trying to embed plot inside right panel of Splitter window, how to add plot inside splitter window. please find here the link for the dataset.
https://www.dropbox.com/s/ncy6dlpm79p578s/Dataset.zip?dl=0.
The file contains rows and columns of wavelength and reflectance.
import wx
from pylab import *
import asciitable
import matplotlib.pyplot as plt
import os
from wxmplot import ImageMatrixFrame
class RandomObj(object):
def __init__(self, name):
self.name = name
class SLI(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, -1, size=(820, 450))
splitter = wx.SplitterWindow(self, style = wx.SP_BORDER)
leftPanel = wx.Panel(splitter, size=(400,100))
rightPanel = wx.Panel(splitter, size=(400,100))
####Tree Widget#####
self.tree = wx.TreeCtrl(leftPanel)
leftSizer = wx.BoxSizer(wx.VERTICAL)
leftSizer.Add(self.tree, 1, wx.EXPAND | wx.ALIGN_CENTER)
leftPanel.SetSizer(leftSizer)
rightSizer = wx.BoxSizer(wx.VERTICAL)
self.display = wx.StaticText(rightPanel, -1, '', (10, 10),
style=wx.ALIGN_CENTRE)
rightSizer.Add(self.display, -1, wx.EXPAND)
rightPanel.SetSizer(rightSizer)
splitter.SplitVertically(leftPanel, rightPanel)
##### Splitter ends ####
root = self.tree.AddRoot('Database')
self.tree.AppendItem(root, 'USGS')
files = []
self.dname = []
self.test = []
for dirname, dirnames, filenames in os.walk('.\USGS'):
for filename in filenames:
files.append(os.path.join(dirname, filename))
self.test.append(filename)
self.tree.AppendItem(self.tree.GetLastChild(root), filename)
self.dname = files[:]
self.tree.AppendItem(root,'ASTER')
for dirname, dirnames, filenames in os.walk('.\ASTER'):
for filename in filenames:
files.append(os.path.join(dirname, filename))
self.test.append(filename)
self.tree.AppendItem(self.tree.GetLastChild(root), filename)
self.dname = files[:]
self.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.ASTER, self.tree)
def ASTER(self, event):
self.item = event.GetItem()
value1 = self.tree.GetItemText(self.item)
value2 = 0
value3 = 1
self.item=None
for k in self.test:
if value1 == k:
value2 +=1
break
else:
value2 +=1
for i in self.dname:
if value3 == value2:
array =[]
f=open(i, 'r')
for j in xrange(27):
f.next()
for line in f:
array.append(line)
data = asciitable.read(array)
plot(data.col1, data.col2)
title(value1)
show()
break
else:
value3 +=1
app = wx.App(None)
frame = ImageMatrixFrame()
SLI().Show()
app.MainLoop()
how to insert plot window inside right panel of splitter.
I am not 100% sure I understand your code - there are some formatting and indentation problems for sure. I also am not familiar with asciitable. But, that said, a wxmplot.PlotPanel or ImagePanel can be embedded in a wxPython Frame that uses a Splitter. An example might look like the code below. I tried to make it short, but also tried to make it complete and using plain wxPython. For a more complete application, you'd probably want to put the reading of the datafiles into a separate class, etc. Anyway, this uses your Dataset folder, and should mostly work to show the concepts:
#!/usr/bin/env python
import os
import wx
from wxmplot import PlotPanel
# see https://gist.github.com/newville/e805a6454c4e4c0e010bf0b3cc796d52
from asciifile import read_ascii
LEFTSTYLE = wx.ALIGN_LEFT|wx.GROW|wx.ALL
def pack(window, sizer, expand=1.1):
"simple wxPython pack function"
tsize = window.GetSize()
msize = window.GetMinSize()
window.SetSizer(sizer)
sizer.Fit(window)
nsize = (int(1.1*max(msize[0], tsize[0])),
int(1.1*max(msize[1], tsize[1])))
window.SetSize(nsize)
class SpectraPlotterFrame(wx.Frame):
def __init__(self, data_folder):
wx.Frame.__init__(self, None, size=(800, 450))
self.SetTitle("Data File Plotter: {:s}".format(data_folder))
self.data_folder = data_folder
self.current_filename = None
splitter = wx.SplitterWindow(self, style=wx.SP_LIVE_UPDATE)
splitter.SetMinimumPaneSize(200)
# left side: ListBox of File Names
l_panel = wx.Panel(splitter)
l_sizer = wx.BoxSizer(wx.VERTICAL)
self.filelist = wx.ListBox(l_panel)
self.filelist.Bind(wx.EVT_LISTBOX, self.onFileChoice)
l_sizer.Add(self.filelist, 1, LEFTSTYLE, 5)
pack(l_panel, l_sizer)
# right side: Panel to choose plot array labels, make plot
r_panel = wx.Panel(splitter)
r_sizer = wx.GridBagSizer(3, 3)
self.xarr = wx.Choice(r_panel, choices=[], size=(175, -1))
self.yarr = wx.Choice(r_panel, choices=[], size=(175, -1))
xlabel = wx.StaticText(r_panel, label='X:', style=LEFTSTYLE)
ylabel = wx.StaticText(r_panel, label='Y:', style=LEFTSTYLE)
plot_btn = wx.Button(r_panel, label='Show Plot', size=(125, -1))
plot_btn.Bind(wx.EVT_BUTTON, self.onPlot)
self.plotpanel = PlotPanel(r_panel, size=(650, 450))
r_sizer.Add(xlabel, (0, 0), (1, 1), LEFTSTYLE, 2)
r_sizer.Add(self.xarr, (0, 1), (1, 1), LEFTSTYLE, 2)
r_sizer.Add(ylabel, (0, 2), (1, 1), LEFTSTYLE, 2)
r_sizer.Add(self.yarr, (0, 3), (1, 1), LEFTSTYLE, 2)
r_sizer.Add(plot_btn, (0, 4), (1, 1), LEFTSTYLE, 2)
r_sizer.Add(self.plotpanel, (1, 0), (1, 6), LEFTSTYLE, 2)
pack(r_panel, r_sizer)
splitter.SplitVertically(l_panel, r_panel, 1)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(splitter, 1, LEFTSTYLE, 5)
pack(self, sizer)
wx.CallAfter(self.read_datafiles)
self.Show()
self.Raise()
def read_datafiles(self):
self.datasets = {}
dfolder = os.path.abspath(self.data_folder)
for fname in sorted(os.listdir(self.data_folder)):
try:
self.datasets[fname] = read_ascii(os.path.join(dfolder, fname))
except:
print("Could not read file {:s}".format(fname))
self.filelist.Append(fname)
def onFileChoice(self, event=None):
self.current_filename = fname = event.GetString()
for choice, default in ((self.xarr, 0), (self.yarr, 1)):
choice.Clear()
choice.AppendItems(self.datasets[fname].array_labels)
choice.SetSelection(default)
def onPlot(self, event=None):
x = self.xarr.GetSelection()
y = self.yarr.GetSelection()
xlab = self.xarr.GetStringSelection()
ylab = self.yarr.GetStringSelection()
if self.current_filename is not None:
dset = self.datasets[self.current_filename]
self.plotpanel.plot(dset.data[x], dset.data[y], xlabel=xlab,
ylabel=ylab, label=self.current_filename,
show_legend=True)
class SpectraPlotterApp(wx.App):
def __init__(self, data_folder='.', **kws):
self.data_folder = data_folder
wx.App.__init__(self, **kws)
def createApp(self):
frame = SpectraPlotterFrame(data_folder=self.data_folder)
self.SetTopWindow(frame)
def OnInit(self):
self.createApp()
return True
if __name__ == '__main__':
SpectraPlotterApp(data_folder='Dataset').MainLoop()
I tried to create a Gui with a grid like label, the label will randomly fill with number in random label with a click on the start button. I cannot get the code to recognize the random label and set text to it. The labels are create in a loop for the grid of '3 X 5'.
from tkinter import *
import random
lbl1 = {}
lbl2 = {}
lbl3 = {}
def fill_auto():
for i in range(1, 6):
rd_row = random.randrange(1, 6)
rd_col = random.randrange(1, 4)
rd_num = random.randrange(1, 16)
print(rd_row, rd_col, rd_num)
pos = str(rd_col) + str(rd_row)
box = 'lbl' + str(pos)
print(box)
box.config(text=rd_num)
root = Tk()
root.geometry('+0+0')
root.configure(bg='black')
for y in range(1, 6):
lbl1[str(y)] = Label(root, width=5, relief='solid')
lbl1[str(y)].grid(row=y, column=0)
lbl2[str(y)] = Label(root, width=5, relief='solid')
lbl2[str(y)].grid(row=y, column=1)
lbl3[str(y)] = Label(root, width=5, relief='solid')
lbl3[str(y)].grid(row=y, column=2)
btn = Button(root, text='start', command=fill_auto)
btn.grid(row=6, column=1)
root.mainloop()
If you want a grid of buttons, it would make sense to use a 2d list:
from tkinter import *
import random
# Create variables for these for the grid width/height
width = 3
height = 5
def fill_auto():
for i in range(1, 6):
rd_row = random.randrange(0, height)
rd_col = random.randrange(0, width)
rd_num = random.randrange(1, 16)
# Set the label text
matrix[rd_row][rd_col].config(text = str(rd_num))
root = Tk()
root.geometry('+0+0')
root.configure(bg='black')
# Helper function to create a label
def make_label(x, y):
l = Label(root, width=5, relief='solid')
l.grid(column=x, row=y)
return l;
# Using list comprehension to create 2d list
matrix = [[make_label(x,y) for x in range(width)] for y in range(height)]
btn = Button(root, text='start', command=fill_auto)
btn.grid(row=6, column=1)
root.mainloop()
When using chartSeries, by default it also shows on the top left of the plot the last value. Is there any way to prevent it from doing it?
When adding a new TA with addTA, you can avoid the last value on the plot by setting the argument legend = "", but only if you're making a new plot for the TA. If the TA is on a previously plotted graphic, it'll show the last value regardless of what you put in the legend argument.
getSymbols ("AAPL", src = "google")
chartSeries(AAPL)
What can I use here to prevent it from printing the last value on the plot?
addTA(EMA(Cl(AAPL)), on = 1, legend = "")
This still prints the last value on the top left of the plot. The weird part is that it doesn't do it if you're plotting on a new plot like this:
addTA(EMA(Cl(AAPL)), legend = "")
Is it like this by default, or is there something I can do to get around it?
The last value is shown by default (yes, annoyingly). You'll likely have to modify the source code to remove the last number showing in addTA.
I don't use addTA, but rather add_TA and chart_Series, because I think they look much better (second generation charts for quantmod). Here is a solution that removes the last number from showing for the add_TA version. But you must be willing to modify the source code.
In add_TA, you'll need to modify approximately lines 56-60 of the source:
Replace the text.exp, which is this:
# this is inside add_TA:
if (is.na(on)) {
plot_object$add_frame(ylim = c(0, 1), asp = 0.15)
plot_object$next_frame()
text.exp <- expression(text(x = c(1, 1 + strwidth(name)),
y = 0.3, labels = c(name, round(last(xdata[xsubset]),
5)), col = c(1, col), adj = c(0, 0), cex = 0.9,
offset = 0, pos = 4))
plot_object$add(text.exp, env = c(lenv, plot_object$Env),
with these modifications:
if (is.na(on)) {
plot_object$add_frame(ylim = c(0, 1), asp = 0.15)
plot_object$next_frame()
text.exp <- expression(text(x = c(strwidth(name)), # <- affects label on the subchart
y = 0.3, labels = name, col = c(col), adj = c(0), cex = 0.9,
offset = 1, pos = 4))
plot_object$add(text.exp, env = c(lenv, plot_object$Env),
expr = TRUE)
...
and assign this modified code to a new variable, called say add_TA.mine:
add_TA.mine <- function (x, order = NULL, on = NA, legend = "auto", yaxis = list(NULL,
NULL), col = 1, taType = NULL, ...)
{
lenv <- new.env()
lenv$name <- deparse(substitute(x))
lenv$plot_ta <- function(x, ta, on, taType, col = col, ...) {
xdata <- x$Env$xdata
....
[all the code for the rest of the function with modifications]....
}
}
plot_object
}
Now, just run the code with the modified function
library(quantmod)
getSymbols("AAPL")
environment(add_TA.mine) <- environment(get("add_TA", envir = asNamespace("quantmod")))
assignInNamespace(x = "add_TA", value = add_TA.mine, ns = "quantmod")
chart_Series(AAPL, subset = "2017")
add_TA(RSI(Cl(AAPL)))
quantmod:::add_TA(RSI(Cl(AAPL)))
You can see the last value is no longer printed:
(You could make the same kinds of changes in the old addTA code (perhaps via chartSeries if you really want to stick to the old plots)
If you're happy with the changes, and want to make them permament in add_TA, you can recompile the quantmod source code yourself with your modifications (i.e. you need to download the quantmod source code and recompile the package) . If you make a mess of things you can always redownload the original quandmod source code again.
How to make the edges of the plot created by gsn_csm_contour_map smooth instead of using those blue squares?
I have tried different fill mode, none of them helped.
Is there a active contour function in ncl? Is is possible to create a contour between null and non-null value?
load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl"
load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_csm.ncl"
load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/contributed.ncl"
;======================================================================
; The main code
;======================================================================
begin
;---Read desired data
sfile = addfile(f,"r")
var = sfile->var1
;---For zooming in on map
minlat = foo
maxlat = bar
minlon = foo1
maxlon = bar1
;---Get dimentions
dims = dimsizes(var)
nlev = dims(0)
time = var&time
date_str_i = getDate(time)
;---Set some resources
res = True
res#cnFillOn = True
;res#cnFillMode = "RasterFill"
;res#cnRasterSmoothingOn =True
res#cnLinesOn = False
res#cnLineLabelsOn = True
res#cnLevelSelectionMode = "ManualLevels"
res#cnMinLevelValF = -100
res#cnMaxLevelValF = 3000
res#cnLevelSpacingF = 200 ; 300 ; 50 ; 150
res#mpMinLatF = minlat
res#mpMaxLatF = maxlat
res#mpMinLonF = minlon
res#mpMaxLonF = maxlon
res#mpDataBaseVersion = "HighRes"
res#cnSmoothingOn = True
res#cnSmoothingDistanceF = 0.005
res#cnSmoothingTensionF = 0.001
res#mpCenterLonF = (minlon+maxlon)*0.5
res#mpCenterLatF = (minlat+maxlat)*0.5
res#pmTickMarkDisplayMode = "Always"
res#lbLabelFontHeightF = 0.01
res#gsnAddCyclic = False ; this is regional data
;---Loop across each level and plot to a different PNG file every time
do n=4,nlev-1
wks_type = "png"
wks_type#wkWidth = 2000
wks_type#wkHeight = 2000
wks = gsn_open_wks(wks_type,fname(0)+sprinti("%03i",n)) ;
res#gsnRightString = "Time:" + date_str_i(n)
res#gsnStringFontHeightF = 0.010
plot = gsn_csm_contour_map_ce(wks,var(n,:,:),res)
delete(wks)
end do
end
But I kind of doubt it is code related.
You have to use:
res#cnFillMode = "AreaFill"
res#cnFillOn = True