Dynamically changing trait - traits

Is it possible to have two classes
class SimulationDigitizer(HasTraits):
width = Int(1920)
height = Int(1080)
name = 'Simulation'
class FileDigitizer(HasTraits):
Filename = File
name = 'File'
and another class 'Digitizer' having an attribute (or trait) UserDigitizer whose edition dialog will propose a drop-down list with 'Simulation' and 'File' and, depending on the choice, the instance edition of either FileDigitizer or SimulationDigitizer and get the result in UserDigitizer ?
Thanks

Thanks Jonathan, you are right, the problem is to select the appropriate subcomponent among many possible.
I ended with the following code, I guess it can be improved in many ways. I am new both to Python and Traits.
# -*- coding: utf-8 -*-
from traits.api import HasTraits, Int, File, Enum, Instance
from traitsui.api import View, Item, Handler, HGroup, InstanceEditor
class UserComponent ( HasTraits ):
""" An empty class from which all user component classes are
derived.
"""
pass
class SimulationDigitizer(UserComponent):
width = Int(1920)
height = Int(1080)
nature = 'Simulation'
class FileDigitizer(UserComponent):
filename = File
nature = 'Reading a file'
UserDigitizers = [FileDigitizer, SimulationDigitizer]
class UserComponentHandler(Handler):
def __init__(self,_user_components_dict):
Handler.__init__(self)
self._user_components_dict = _user_components_dict
def object_user_component_nature_changed ( self, info ):
# Find new UserComponent class from string in user_component_nature
new_user_component = self._user_components_dict[info.object.user_component_nature]
# If different, change user_component value
if info.object.user_component is not new_user_component:
info.object.user_component = new_user_component
class Digitizer(HasTraits):
user_component_nature = Enum([x().nature for x in UserDigitizers])
_user_file_digitizer = FileDigitizer()
_user_simulation_digitizer = SimulationDigitizer()
# Dictionary with keys = nature and values = user digitizers
_user_digitizers_dict = {x.nature: x for x in [_user_file_digitizer,_user_simulation_digitizer]}
user_component = Enum(_user_file_digitizer,_user_simulation_digitizer)
view = View(HGroup(Item('user_component_nature',
label = 'Nature'),
Item('user_component',
show_label = False,
editor = InstanceEditor(label = 'Edit',
kind = 'modal'))),
handler = UserComponentHandler(_user_digitizers_dict))
d = Digitizer()
if __name__ == '__main__':
d.configure_traits()

Related

How to add a second dataset to a plotly annotated heatmap?

I'm trying to create an annotated heatmap with a dropdown menu to switch between two different sets of data. The datasets have the same format and I have added a working dropdown menu. But I can only add one dataset at a time. I am using
fig = ff.create_annotated_heatmap(data, annotation_text=numbers, showscale=True, colorscale=colorscale, text=hover, hoverinfo='text')
to create the annotated heatmap. Is there a way to add a second dataset to switch between with the dropdown menu?
Resolved. Had to add the second data set to the args of the dropdown menu object
along with any other changes needed (such as hover text)
I just realized how easy it is to switch between two plots with a menu. You can just get the data from each figure to create a list of traces to swithc between
from plotly.offline import init_notebook_mode, iplot
import plotly.figure_factory as ff
init_notebook_mode(connected=True)
fig_1 = ff.create_annotated_heatmap(...)
fig_2 = ff.create_annotated_heatmap(...)
menu_items = ["Heatmap 1", "Heatmap 2"]
trace1 = fig_1.to_dict()["data"][0]
trace2 = fig_2.to_dict()["data"][0]
buttons = []
for i, menu_item in enumerate(menu_items):
visibility = [i==j for j in range(len(menu_items))]
button = dict(
label = menu_item,
method = 'update',
args = [{'visible': visibility},
{ 'title' : menu_item }])
buttons.append(button)
updatemenus = list([
dict(buttons = buttons)
])
layout = dict(updatemenus = updatemenus, title=menu_items[0])
fig = dict(data=[trace1, trace2], layout=layout)
iplot(fig)

How to define an instance depending on some variable?

I'll give code on Python, but it's doesn't matter.
I have a module argument_parser with dictionary and class:
FORMATS = {
'JSON': 'json',
'XML': 'xml',
}
class ArgumentParser:
# some methods
def parse():
"""returns 'XML' or 'JSON' string"""
return fomat
and a module with presenters -- presenter
class JSONPresenter:
# some magic
class XMLPresenter:
# some magic
The problem is in dependency injection:
argument_parser = ArgumentParser()
format = argument_parser.parse()
if format == argument_parser.FORMATS['JSON']:
presenter = JSONFilePresenter()
elif format == argument_parser.FORMATS['XML']:
presenter = XMLFilePresenter()
if-elif construction is ugly. If I want to add some other formats I'll must add more elif.
I could define the type of presenter in ArgumentParser class but I think semantically it is wrong -- it is not a filed of responsibility of this class. What should I do to do it right?
PRESENTERS = {
'json': JSONPresenter(),
'xml': XMLPresenter(),
}
argument_parser = ArgumentParser()
fmt = argument_parser.parse()
presenter = PRESENTERS[fmt]
Or, if you need a new presenter every time:
PRESENTERS = {
'json': lambda: JSONPresenter(),
'xml': lambda: XMLPresenter(),
}
argument_parser = ArgumentParser()
fmt = argument_parser.parse()
presenter = PRESENTERS[fmt]()

Flask App Builder url_for views

I am struggling on how to connect URL_for links in my app.
I have a the basic skeleton app set up.
I wish to make a link to a function (that runs code) that is built in a view (MyView).
I essentially want to pass a variable (var1) to the view 'myview/method2/var1' and have that link showing in the ContactModelView.
Thanks
class MyView(BaseView):
route_base = "/myview"
#expose('/method2/<string:var1>')
#has_access
def fun_var(self, var1):
# go to function_file and run function with var1
param1, param2 = func_file.function(var1)
self.update_redirect()
return self.render_template('method3.html',
param1=param1,param2=param2, param3=prospects)
My models.py file has the following:
class Contact(Model):
id = Column(Integer, primary_key=True)
name = Column(String(150), unique = True, nullable=False)
var1 = Column(String(150))
contact_group_id = Column(Integer, ForeignKey('contact_group.id'))
contact_group = relationship("ContactGroup")
def prospect(self):
return Markup(
'prospect')
def __repr__(self):
return self.name
I then have in views:
class ContactModelView(ModelView):
datamodel = SQLAInterface(Contact)
label_columns = {'contact_group':'Contacts Group'}
list_columns = ['name','var1','contact_group', 'action']
show_fieldsets = [
(
'Summary',
{'fields':['name','var1','contact_group', 'prospect']}
)
]
In the documentation regarding BaseView, we see that
Its constructor will register your exposed urls on flask as a Blueprint
So make sure you add the view you created, in order to 'register the blueprint'. Use something like
appbuilder.add_view_no_menu(MyView())
You can run fabmanager list-views on the console to make sure your view was registered.
As your endpoint requires a var1 parameter, you have to provide that to url_for. Something like this will work:
class Contact(Model):
var1 = Column(String(150))
...
def prospect(self):
return Markup(
'prospect')

tkinter variable for drop down selection empty

I tried to program an app in tkinter that would load random lines from a file you select from a pull down menu and display the selected line in a text window.
It seems like the variable "var" in insert_text does not return the selected "option" but rather an "empty" string resulting in a the following error:
"File not found error" (FileNotFoundError: [Errno2] No such file or
directory: '').
Please help!
#!/usr/bin/env python
# Python 3
import tkinter
from tkinter import ttk
import random
class Application:
def __init__(self, root):
self.root = root
self.root.title('Random Stuff')
ttk.Frame(self.root, width=450, height=185).pack()
self.init_widgets()
var = tkinter.StringVar(root)
script = var.get()
choices = ['option1', 'option2', 'option3']
option = tkinter.OptionMenu(root, var, *choices)
option.pack(side='right', padx=10, pady=10)
def init_widgets(self):
ttk.Button(self.root, command=self.insert_txt, text='Button', width='10').place(x=10, y=10)
self.txt = tkinter.Text(self.root, width='45', height='5')
self.txt.place(x=10, y=50)
def insert_txt(self):
var = tkinter.StringVar(root)
name = var.get()
line = random.choice(open(str(name)).readlines())
self.txt.insert(tkinter.INSERT, line)
if __name__ == '__main__':
root = tkinter.Tk()
Application(root)
root.mainloop()
That's because you're just creating an empty StringVar that isn't modified later, thus returning an empty string.
The OptionMenu takes the command parameter that calls the specified method every time another option is selected. Now, you can call a method like this, replacing you insert_txt:
def __init__(self):
# ...
self.var = tkinter.StringVar()
self.options = tkinter.OptionMenu(root, var, *choices, command=self.option_selected)
# ...
def option_selected(self, event):
name = self.var.get()
# The stuff you already had
Additionally, you have to empty the Text widget, otherwise the previous text would stay. I think the Entry widget is better for that, too.

Override window close behavior

I want to catch all tries to close some specific existing Cocoa window and add some own handler (which might indeed really close it or do something different).
I had different solutions in mind to do this. One was:
I want to replace the window close button of an existing Cocoa window at runtime with an own close widget where I can add some own code.
Right now, I have this code:
import objc
_NSThemeCloseWidget = objc.lookUpClass("_NSThemeCloseWidget")
def find_close_widget(window):
contentView = window.contentView()
grayFrame = contentView.superview()
for i in range(len(grayFrame.subviews())):
v = grayFrame.subviews()[i]
if isinstance(v, _NSThemeCloseWidget):
return v, i, grayFrame
class CustomCloseWidget(_NSThemeCloseWidget):
pass
def replace_close_widget(window, clazz=CustomCloseWidget):
v, i, grayFrame = find_close_widget(window)
newv = clazz.alloc().init()
grayFrame.subviews()[i] = newv
However, this doesn't seem quite right. (It crashes.)
The close widget isn't the only way to close the window. There's a public API to obtain the widget, so you don't need to go rifling through the frame view's subviews, but that's the wrong path anyway.
The right way is to make an object to be the window's delegate, and interfere with the window's closure there. Ideally, you should set the window's delegate in between creating the window and ordering it in.
I am going another route now. This is partly Chrome related but it can easily be adopted elsewhere. I wanted to catch several actions for closing the window as early as possible to avoid any other cleanups or so which resulted in the window being in a strange state.
def check_close_callback(obj):
# check ...
return True # or:
return False
import objc
BrowserWindowController = objc.lookUpClass("BrowserWindowController")
# copied from objc.signature to avoid warning
def my_signature(signature, **kw):
from objc._objc import selector
kw['signature'] = signature
def makeSignature(func):
return selector(func, **kw)
return makeSignature
windowWillCloseSig = "c12#0:4#8" # BrowserWindowController.windowWillClose_.signature
commandDispatchSig = "v12#0:4#8"
class BrowserWindowController(objc.Category(BrowserWindowController)):
#my_signature(windowWillCloseSig)
def myWindowShouldClose_(self, sender):
print "myWindowShouldClose", self, sender
if not check_close_callback(self): return objc.NO
return self.myWindowShouldClose_(sender) # this is no recursion when we exchanged the methods
#my_signature(commandDispatchSig)
def myCommandDispatch_(self, cmd):
try: print "myCommandDispatch_", self, cmd
except: pass # like <type 'exceptions.UnicodeEncodeError'>: 'ascii' codec can't encode character u'\u2026' in position 37: ordinal not in range(128)
if cmd.tag() == 34015: # IDC_CLOSE_TAB
if not check_close_callback(self): return
self.myCommandDispatch_(cmd)
from ctypes import *
capi = pythonapi
# id objc_getClass(const char *name)
capi.objc_getClass.restype = c_void_p
capi.objc_getClass.argtypes = [c_char_p]
# SEL sel_registerName(const char *str)
capi.sel_registerName.restype = c_void_p
capi.sel_registerName.argtypes = [c_char_p]
def capi_get_selector(name):
return c_void_p(capi.sel_registerName(name))
# Method class_getInstanceMethod(Class aClass, SEL aSelector)
# Will also search superclass for implementations.
capi.class_getInstanceMethod.restype = c_void_p
capi.class_getInstanceMethod.argtypes = [c_void_p, c_void_p]
# void method_exchangeImplementations(Method m1, Method m2)
capi.method_exchangeImplementations.restype = None
capi.method_exchangeImplementations.argtypes = [c_void_p, c_void_p]
def method_exchange(className, origSelName, newSelName):
clazz = capi.objc_getClass(className)
origMethod = capi.class_getInstanceMethod(clazz, capi_get_selector(origSelName))
newMethod = capi.class_getInstanceMethod(clazz, capi_get_selector(newSelName))
capi.method_exchangeImplementations(origMethod, newMethod)
def hook_into_windowShouldClose():
method_exchange("BrowserWindowController", "windowShouldClose:", "myWindowShouldClose:")
def hook_into_commandDispatch():
method_exchange("BrowserWindowController", "commandDispatch:", "myCommandDispatch:")
This code is from here and here.