How to display an image using wxpython and rpy2? - python

so i'm trying to display an R generated image while using wxpython and rpy2...
The full 131 line code is here... https://gist.github.com/ACollectionOfAtoms/4286c0fc32838b03f2ea
So within the program, the user comes to a point where they are a window genereated by lst_view, which has two buttons "Ok" and "Visualize". Once Visualize is pressed this code is executed..
def graph(self,event):
f = open('results.csv', 'wb')
csvwriter = csv.writer(f)
for i in self.res:
for j in range(1,len(i)):
row = [i[0] ,str(i[j])]
csvwriter.writerow(row)
f.close()
r = robjects.r
r('''
source('vis.r')
''')
r_main = robjects.globalenv['main']
r_main()
return True
Where in vis.r we have:
graph <- function() {
res = read.csv("results.csv", header=FALSE)
res = mutate(res, Percent = 100*(V2/(sum(res$V2))))
ggplot(data=res, aes(x=V1, y=V2, fill=Percent)) + geom_bar(stat="identity") + coord_flip() + xlab('Facility') + ylab('Number Of Violations')
}
main <- function(){
print(graph())
}
This doesn't immediately generate the graph, instead it causes a new menu to appear and the graphic only displays if I go to "Page Setup"....
Anyone ideas?!

Alright, thanks to unutbu I was able to figure this out!
Basically I initially wanted to save the image and then visualize it with wx, but i had problems using dev.off() and such through rpy2!
BUT! unutbu provided a link and saved me a ton of trouble. you can use ggsave() to completely circumvent the whole jpeg('this.jpg'); dev.off(); business!
Thanks again, unutbu. Now i'll just render it with wx no problem!

Related

Read labels separately from a function that generates a set of buttons

I have the following development that I am working on with the Tkinter, ElementTree and Pandas modules in Python:
from tkinter import *
import xml.etree.ElementTree as ET
import pandas as pd
file_xml = ET.parse('example1.xml')
rootXML = file_xml.getroot()
root = Tk()
root.title("Graphical Analysis of Signals of a XML")
root.geometry("1024x820")
root.pack_propagate(False)
root.config(bd=15)
# Functions to open xml file
def open_file():
try:
global temxml, xml_Name
xml_Name = str(easygui.fileopenbox(title='Select xml file', default='*.xml'))
if str(os.path.abspath(xml_Name)) != os.path.join(os.path.abspath(os.getcwd()), os.path.basename(xml_Name)):
menssage.set("Opened xml file: ", xml_Name)
child_4_separate(os.path.basename(str(tempxml)))
else:
child_4_separate(os.path.basename(str(xml_Name)))
except FileNotFoundError:
print('XML file was not loaded.')
# Function to display buttons and choose the Child_4 to be plotted
def child_4_separate(xml_Name):
print("File: ", xml_Name)
file_xml = ET.parse(xml_Name)
data_xml = [
{
"Name": signal.attrib["Name"],
"Id": signal.attrib["Id"],
} for signal in file_xml.findall(".//Child_4")
]
# print(data_xml)
for i in data_xml:
print(i)
id_tc = i.get('Id')
dict_tc = str(i.values()).replace('dict_values([\'', '')
name_tc = dict_tc.replace('\'])', '')
Button(root, text=f"TC> {name_tc}", command=transfor_data_atri_child_4(xml_Name, id_tc)).pack()
# Function to transform xml file to DataFrame
def transfor_data_atri_child_4(rootXML, id_tc):
print("File: ", rootXML)
print("id_tc: ", id_tc)
What I'm trying to do is that every time I click a button, the child_4_separate (xml_Name) function it goes to the transform_data_atri_child_4 (rootXML, id_tc) function with a single id number and does not fetch me everything like it does in the last print that I show below, this is to be able to manipulate them separately.
I share the XML file in this link example1.xml because of how long it is.
I don't know if I need another for inside or what I need, because when trying another for inside the already existing for in the child_4_separate (xml_Name) function it is repeating it many times and it is not what I want, but simply that redirect to the following function with the two parameters that I am indicating, but separately; help me please! Beforehand, thank you very much!
Just for possible searches or related problems later, I share the solution:
Take the value command = lambda x = xml_Name, y = id_tc: transform_data_atri_child_4 (x, y) in the button attributes and it worked, my function is like this:
# Function to display buttons and choose the Child_4 to be plotted
def child_4_separate(xml_Name):
# print("File: ", xml_Name)
file_xml = ET.parse(xml_Name)
data_xml = [
{
"Name": signal.attrib["Name"],
"Id": signal.attrib["Id"],
} for signal in file_xml.findall(".//Child_4")
]
# print(data_xml)
for i in data_xml:
id_tc = i.get('Id')
dict_tc = str(i.values()).replace('dict_values([\'', '')
name_tc = dict_tc.replace('\'])', '')
Button(root, text=f"TC> {name_tc}", command=lambda x=xml_Name, y=id_tc: transfor_data_atri_child_4(x, y)).pack()
I appreciate the solution to #Sujay. Happy codification everyone!!

How do you simulate completing a QFileDialog using PyQt and QTest?

I want to automate the testing of a GUI. In particular I want to test the "save" option from the file menu. I.e. when the save button is clicked the data from the fields in the UI are collected and then written to a json file.
The problem is, when the QFileDialog pops up asking for the user to enter the name of the file to save to, I cant get a handle on the dialog to continue testing. How do you automate this bit? I am not sure how to get a handle on the QFileDialog.
def hdl_save_report_as(self):
try:
self.dialog.setDefaultSuffix('json')
save_file, _ = self.dialog.getSaveFileName(caption="Save Report", filter="JSON Files (*.json)")
if save_file:
score = self.parent.main_tab_view.get_fields()
self.ui_model.report_path = save_file
with open(save_file, 'w') as f:
json.dump(score, f, indent=4)
except Exception as e:
result = dlg.message_dialog("Exception", "We ran into an error!", QMessageBox.Warning, e)
print(e)
def test_save_report(self):
self.main_window.menu.bt_save_file.trigger()
self.main_window.menu.dialog.selectFile('a_test_report.json')
## save_dialog = QApplication.activeModalWidget()
# save_dialog = QApplication.activeWindow()
# children = save_dialog.findChildren()
# active_line_edit = None
# confirm_button = None
# for c in children:
# if type(c) is QLineEdit:
# if c.hasFocus():
# active_line_edit = QLineEdit(c)
# # if type(c) is QPushButton:
# # if
# active_line_edit.setText("a_test_report")
self.assertTrue(os.path.exists(os.path.join(os.getcwd(), 'a_test_report.json')))
I have tried a few different approaches, is there a standard way to do this? Hopefully I have missed something obvious.
From what I can see and as explained in another post it is not possible to simulate interaction with the special QFileDialogs like getSaveFileName or getOpenFileName.
My approach is now managing the files in setup function like
def setUp(self):
self.test_report = "a_test_report.json"
# Remove an existing test report
if os.path.exists(self.test_report):
os.remove(self.test_report)
self.assertFalse(os.path.exists(os.path.join(os.getcwd(), self.test_report)))
# Create a file to test reading / writing
with open(self.test_report, 'w') as f:
f.write("")
self.assertTrue(os.path.exists(os.path.join(os.getcwd(), self.test_report)))
self.assertTrue(os.stat(self.test_report).st_size == 0)
self.main_window = MainWindow()
And testing like
def test_save_action(self):
# Trigger the save button - check if the file was overwritten with new info
self.main_window.menu.bt_save_file.trigger()
self.assertTrue(os.stat(self.test_report).st_size > 0)
Although it seems it is not possible to test a "Save As" function.

Display Streaming DataFrame in Jupyter from Redis Subcription

I have a Redis pub-sub channel 'price-updates' in redis for which a publisher sets updates for a stock price. I want to display a streaming grid that keeps appending the price updates as they come at the end of the grid.
So far, I have created a non-working version of what I want to do.
from streamz import Stream
from streamz.dataframe import DataFrame
source = Stream()
data = []
def handler(message):
json_data = json.loads(message['data'])
df = pd.DataFrame.from_dict([json_data]).set_index('sym')
source.map(handler).sink(data.append)
sdf = DataFrame(source)
## Run this in a different thread
p.subscribe('price-updates')
while True:
message = p.get_message()
if message:
source.emit(message)
time.sleep(0.001)
## end of thread block
#displayStreamingDataGrid(sdf)
I would appreciate if someone with more experience with the sdf could help me do this.
I was able to do this without streams. However, I am not getting a the streaming grid that gets updated in-place but rather displaying and clearing the output which is very annoying.
Here is the output widget in one jupyter cell
import ipywidgets as iw
from IPython.display import display
o = iw.Output()
def output_to_widget(df, output_widget):
output_widget.clear_output()
with output_widget:
display(df)
o
Here is the code to subscribe to redis and get handle the message
import redis, json, time
r = redis.StrictRedis(host = HOST, password = PASS, port = PORT, db = DB)
p = r.pubsub(ignore_subscribe_messages=True)
p.subscribe('QUOTES')
mdf = pd.DataFrame()
while True:
message = p.get_message()
if message:
json_msg = json.loads(message['data'])
df = pd.DataFrame([json_msg]).set_index('sym')
mdf = mdf.append(df)
output_to_widget(mdf, o)
time.sleep(0.001)
You can use https://github.com/AaronWatters/jp_proxy_widget to create an html
table which you can update in place without visibly clearing the table between updates.
I put an example notebook here: https://github.com/AaronWatters/jp_doodle/blob/master/notebooks/misc/In%20place%20html%20table%20update%20demo.ipynb
The trick is to create a widget that displays a table and attaches
an update operation which modifies the table:
# Create a proxy widget with a table update method
import jp_proxy_widget
def updateable_table(headers, rows):
w = jp_proxy_widget.JSProxyWidget()
w.js_init("""
# injected javascript for the widget:
element.update_table = function(headers, rows) {
element.empty();
var table = $("<table border style='text-align:center'/>");
table.appendTo(element);
var header_row = $("<tr/>");
for (var i=0; i<headers.length; i++) {
$("<th style='text-align:center'>" + headers[i] + "</th>")
.width(50)
.appendTo(header_row);
}
header_row.appendTo(table);
for (var j=0; j<rows.length; j++) {
var table_row = $("<tr/>").appendTo(table);
var data_row = rows[j];
for (var i=0; i<data_row.length; i++) {
$("<td>" + data_row[i] + "</td>").appendTo(table_row);
}
}
}
element.update_table(headers, rows);
""", headers=headers, rows=rows)
return w
# show the widget
w = updateable_table(headers, rows)
w
The code to update the widget
# Update the widget 20 times
import time
count = -20
for i in range(21):
time.sleep(1)
rows = [rows[-1]] + rows[:-1] # rotate the rows
rows[0][0] = count # change the upper left entry.
count += 1
w.element.update_table(headers, rows)
updates the table in place with no visible erasure. The example
notebook linked above also shows how to do the same thing using a
pandas dataframe.

wxPython Clipboard GetData not maintaining tabs or linefeeds on Mac

Hi I am new to python and I am self taught programmer otherwise.
I am trying to get the copy and paste methods working for the clipboard in wxpython.
I have found and implemented what I have found on the topic, but there is an issue when used on my mac computer (OS X 10.10.5).
The attached code is a sample application that works fine within itself (given limits of grid). It also works fine for copying from the grid cells and pasting to an external notepad or spreadsheet. Meaning to me that the SetData is getting and maintaining the tab delimiters and new lines when building the clipboard data.
However, if I select tab delimited and multiline data from the same notepad or spreadsheet and proceed to paste into the grid, I get a single column of data. This means to me that the tab delimiters and newline characters are lost in the GetData.
With a data selection of
1 2 3
4 5 6
in a spreadsheet.
Using print repr(data) to get what the clipboard is holding, as suggested,
When copying and pasting within application results in
pasting data - print repr(data) = u'1\t2\t3\n4\t5\t6\n'
When data is copied from an external source and pasting seems to only have \r return characters and ufeff ?? which I don't know about? Perhaps thats a key? (on the mac)
print repr(data) = u'\ufeff\r1\r2\r3\r4\r5\r6\r\r'
Now this works fine on my Windows machine, but not on my Mac.
Is this a known issue? Is there a workaround, or is there a setting that I am missing or that I don't understand?
Much appreciate any help or direction.
Thanks
Frank
import wx
import wx.grid as dg
class cp(wx.Panel):
def __init__(self, parent):
wx.Panel.__init__(self, parent, wx.ID_ANY, size = (600,600))
self.dgGrid = dg.Grid(self, size = (500,500))
self.dgGrid.CreateGrid(10,5)
self.dgGrid.Bind(wx.EVT_KEY_DOWN, self.OnKeyPress)
def OnKeyPress(self, event):
# If Ctrl+V is pressed...
if event.ControlDown() and event.GetKeyCode() == 86:
print "Ctrl+V"
# Call paste method
self.Paste()
if event.ControlDown() and event.GetKeyCode() == 67:
print "Ctrl+C"
# Call copy method
self.copy()
event.Skip()
def copy(self):
print "Copy method"
# Number of rows and cols
rows = self.dgGrid.GetSelectionBlockBottomRight()[0][0] - self.dgGrid.GetSelectionBlockTopLeft()[0][0] + 1
cols = self.dgGrid.GetSelectionBlockBottomRight()[0][1] - self.dgGrid.GetSelectionBlockTopLeft()[0][1] + 1
# data variable contain text that must be set in the clipboard
data = ''
# For each cell in selected range append the cell value in the data variable
# Tabs '\t' for cols and '\r' for rows
for r in range(rows):
for c in range(cols):
data = data + str(self.dgGrid.GetCellValue(self.dgGrid.GetSelectionBlockTopLeft()[0][0] + r, self.dgGrid.GetSelectionBlockTopLeft()[0][1] + c))
if c < cols - 1:
data = data + '\t'
data = data + '\n'
# Create text data object
clipboard = wx.TextDataObject()
# Set data object value
clipboard.SetText(data)
# Put the data in the clipboard
if wx.TheClipboard.Open():
wx.TheClipboard.SetData(clipboard)
wx.TheClipboard.Close()
else:
wx.MessageBox("Can't open the clipboard", "Error")
def Paste(self):
print "Paste method"
clipboard = wx.TextDataObject()
if wx.TheClipboard.Open():
wx.TheClipboard.GetData(clipboard)
wx.TheClipboard.Close()
else:
wx.MessageBox("Can't open the clipboard", "Error")
return
data = clipboard.GetText()
y = -1
# Convert text in a array of lines
for r in data.splitlines():
y = y +1
x = -1
print r
# Convert c in a array of text separated by tab
for c in r.split('\t'):
x = x +1
print c
self.dgGrid.SetCellValue(self.dgGrid.GetGridCursorRow() + y, self.dgGrid.GetGridCursorCol() + x, c)
if __name__ == '__main__':
print ' running locally not imported '
app = wx.App(False)
MainFrame = wx.Frame(None, title = "TestingCopy and Paste", size = (600,600))
cppanel = cp(MainFrame)
MainFrame.Refresh()
MainFrame.Show()
app.MainLoop()

file.open with "w" not overwriting file in Python tKinter button method

So I'm writing a tKinter GUI for this project I'm working on, and I've run into a problem with one of my button methods. In the method for this button, the code prints a list of coordinates to a text file. It works great the first time, but if I press the button again before closing the root tKinter window, it doesn't truncate the file - it just adds the next set off coordinates to the end. Here is my code:
#print to file
reportFile = open('gridCenters.txt','w')
reportFile.write('In movement order:\n')
for x in xrange(0,len(coordinates)):
reportFile.write('%s\n' % str(coordinates[x]))
reportFile.close()
Now, this is within a button method, so to my understanding it should execute every time the button is pressed. The really strange part is that in the output after pressing the button again, it prints JUST the loop values. For some reason it skips over the "In movement order" part.
It won't let me upload images but here's an idea of how it looks:
In movement order:
(0,1)
(0,2.5)
(0.3.5)
(0,4.5)
Then if I press the button again before closing the root window:
In movement order:
(0,1)
(0,2.5)
(0.3.5)
(0,4.5)
(0,1)
(0,2.5)
(0.3.5)
(0,4.5)
(Those blocks aren't code, just text output)
I'm just really confused. My understanding is that every time I press the button, it should overwrite the file, then close it.
Thanks for the help.
In when your button re-opens the file it doesn't print the "In movement order:" a second time.
This looks like you aren't clearing your variable coordinates. You should make sure that you are starting with a clean variable before adding to it to get the data you are looking for.
You could reset it after the file closes unless you need to retain it for use un the GUI at that point.
I am not shure why it doesnt works for you but here is what i had wrote.
from Tkinter import *
def wtf(coordinates):
reportFile = open('gridCenters.txt','w')
reportFile.write('In movement order:\n')
for x in xrange(0,len(coordinates)):
reportFile.write('%s\n' % str(coordinates[x]))
reportFile.close()
def main():
coordinates = [(0,1),(0,2.5),(0,3.5),(0,4.5)]
root = Tk()
btn = Button(root,text='click me',command = lambda:wtf(coordinates))
btn.pack()
root.mainloop()
main()
in wtf function if 'w' is flag (reportFile = open('gridCenters.txt','w')) the gridCenters.txt is rewritten every time,but if the flag is 'a' instead of 'w' than result is just appending one below another.I hope this is what u want.
from Tkinter import *
coords = [1, 2, 3, 4, 5]
def write():
global coords
fileName = "testButton.txt"
fileObj = open(fileName, 'w')
fileObj.write("Some words\n")
for i in xrange(0, len(coords)):
fileObj.write("%d\n" %coords[i])
fileObj.close()
for i in range(5):
coords[i] += 1
root = Tk()
f = Frame(root).pack()
b = Button(root, text = "OK", command = write).pack(side = LEFT)
root.mainloop()
This works for me, overwriting the file every time and the values are updated every time as well. Something must be going on elsewhere in your program.

Categories

Resources