Forum Archive

displaying image or matplotlib plot in a imageview ui element

paulj03

I am new to python, pythonista and programming an ui for ipad. Pythonista has been great for all of this... great app.

So I am following the examples... I have written a script to decode some data from a file, and I want to plot it as a x-y graph (x=time, y = temperature, wind or humidity)- 1440 time steps = 1 minute data for 24 hours. I can do it as a matplotlib graph in the console. I want to develop a ui app with buttons to switch y, with two sliders to control the end time (say 8pm) and duration of the plot (previous one or two hours). So I've used the graphical interface to create the UI, able to control the time/duration and parameters with sliders and buttons respectively...but the graph shows up in the console - I thought of somehow creating a png file on disk, read it up and then somehow display in the imageview window - but I can't seem to find how to do that - I can display an icon from the ui list but not my own graph or image... any hints. Attached is my script - not the most efficient, just trying to learn how to display in imageview window (or any other window)....the ??? shows where i am stuck ???

# wxtui
# A simple RGB color mixer with three sliders.

import ui
import clipboard
from random import random
from console import hud_alert
import os
import re
import console
import matplotlib.pylab as plt

global endTime, duration, wxt520Time, wxt520Data, nparm, parm

endTime=242
duration=120
wxt520Time=[]
wxt520Data=[]
# interactive wxt520 plot


def get_num(s):
    return float( ''.join( x for x in s if x.isdigit() or x == '.') )

def getWxt520Data():

    cwd = os.getcwd()
    print cwd

    list = os.listdir(cwd)
    print list

    files=[]
    for f in list:
        if re.match("WXT",f):
            files.append(f)
    print files

    f = files[1]
    fn = open(f,"r")
    lines = fn.readlines()

    date=[]
    time=[]
    count=[]
    data=[]
    for line in lines:
        parts = re.split(' ',line)
        date.append(parts[0])
        time.append(parts[1])
        count.append(parts[2])
        data.append(parts[3])

#create dictionary from data   key:index (location of element to plot)
    dict_index2parameter={}
    dict_parameter2index={}
    parts = re.split(',',data[0])
    lp = len ( parts )
    for i in range(lp):
        if re.search('=',parts[i]):
            q = re.split("=",parts[i])
            dict_parameter2index[q[0]]=i
            dict_index2parameter[i]=q[0]

    print dict_parameter2index
    print dict_index2parameter

# create decimal time
    dtime=[]
    for t in time:
        parts = re.split(':',t)
        d     = float( parts[0] ) + float( parts[1] )/60. + float( parts[2])/3600.   # decimal time
        dtime.append(d)
    return dtime,data,dict_index2parameter,dict_parameter2index 

def extractWxt520Parm(data,nparm):  

# extract data
#   nparm = 4   # parameter to display
    y = []
    for d in data:
        parts = re.split(',',d)
        y.append(get_num(parts[nparm]))
    return y

def extractWxt520Subinterval(endtime,duration,dtime,parm):
    iend = 60*endtime
    istart = iend - duration
    if istart <0:
        istart = 0;
        iend   = duration
    if iend > 1440:
        iend = 1439
        istart = iend - duration
    x=dtime[istart:iend]
    y=parm[istart:iend]
    return x,y


def pltwxt520(x,y):
    plt.grid()
    plt.plot(x,y)
    plt.save("wxt520.png",'PNG')   #??? save the file to disk
#   plt.show()

def button1(sender):
    global wxt520Data, wxt520Time,nparm, parm
    # Get the root view:
    v = sender.superview
    nparm = 7
    parm = extractWxt520Parm(wxt520Data,nparm)
    v['label2'].text = 'fn = '+str(nparm)
    x,y = extractWxt520Subinterval(end,dur,wxt520Time,parm)
    pltwxt520 (x,y)

def button2(sender):
    global wxt520Data, wxt520Time,nparm, parm
    # Get the root view:
    v = sender.superview
    nparm = 4
    parm = extractWxt520Parm(wxt520Data,nparm)
    v['label2'].text = 'fn = '+str(nparm)
    x,y = extractWxt520Subinterval(end,dur,wxt520Time,parm)
    pltwxt520 (x,y)

def button3(sender):
    global wxt520Data, wxt520Time,nparm,parm
    # Get the root view:
    v = sender.superview
    nparm = 9
    parm = extractWxt520Parm(wxt520Data,nparm)
    v['label2'].text = 'fn = '+str(nparm)
    x,y = extractWxt520Subinterval(end,dur,wxt520Time,parm)
    pltwxt520 (x,y)


def slider_action(sender):
    global wxt520Data, wxt520Time,nparm,parm
    # Get the root view:
    v = sender.superview
    # Get the sliders:
    end = int( v['endtime'].value * 24 )
    dur = int ( v['duration'].value * 120 )
    # Create the new color from the slider values:
#   v['view1'].background_color = (r, r*0.1, r*0.23)
    v['label1'].text = 'End Time [h] = '+str(end)+'  Duration [m] = '+str(dur)      
    v['label2'].text = 'fn = '+str(nparm)
#   print end, dur
    x,y = extractWxt520Subinterval(end,dur,wxt520Time,parm)
    pltwxt520 (x,y)
#   img = image.load("wxt520.png")                            # ??? I am stuck here, at this point, I have image on console, image on disk but no image in my imageview1 ui element
#   v['imageview1'].image = img #.named("wxt520.png") 


def main():

    global wxt520Time, wxt520Data, nparm, parm

    time, data, dict1, dict2 = getWxt520Data()

    nparm=4
    parm = extractWxt520Parm(data,nparm)
    endTime = 24
    duration = 120
    wxt520Time = time
    wxt520Data = data
#   print wxt520Data

    x,y = extractWxt520Subinterval(endTime,duration,time,parm)
#   print x
#   print y
    v = ui.load_view('wxtuiplot')
    slider_action(v['endtime'])

    if ui.get_screen_size()[1] >= 768:
        # iPad
        v.present('fullscreen')
    else:
        # iPhone
        v.present()

main()
omz

Have you tried something like v['imageview1'].image = ui.Image.named('wxt520.png')?

Gerzer

Just so you know, the image must be in the same directory as the script. Also, in case you didn’t notice, these are the Editorial forums. Editorial is @omz’s other iOS app. Click omz:software Forums at the top of the page to go to the forums homepage, where you can see the Pythonista forums link.

ccc

Other ideas inline...

#coding: utf-8

# wxtui
# A simple RGB color mixer with three sliders.

import ui
import clipboard
from random import random
from console import hud_alert
import os
#import re   # str.split(), str.partition(), and `in` replace re for plain text
import console
import matplotlib.pylab as plt
import sys  # for sys.exit()

global endTime, duration, wxt520Time, wxt520Data, nparm, parm

endTime=242
duration=120
wxt520Time=[]
wxt520Data=[]
# interactive wxt520 plot

def get_num(s):
    return float( ''.join( x for x in s if x.isdigit() or x == '.') )

def getWxt520Data():
    cwd = os.getcwd()
    print cwd

    local_files = os.listdir(cwd)  # using 'list' as a variable name is dangerous... 'time' also.
    print local_files

    # list comprehension, only file ending with '.wxt', case insensitive!
    files = [f for f in local_files if f.upper().endswith('.WXT')]
    if not files:  # deal with no .wxt files found
        sys.exit('No .WXT files found in "{}"!'.format(cwd))
    #for f in list:
    #    if re.match("WXT",f):
    #        files.append(f)
    #print files

    f = files[1]  # why the second .WXT file?  files[0] is the first .WXT file.
    #fn = open(f,"r")  # you are not closing this file which leak memory, etc.
    with open(f) as in_file:  # use `with open() as file_handle` which will automatically close()
        lines = in_file.readlines()

    date=[]
    time=[]
    count=[]
    data=[]
    for line in lines:
        parts = line.split()  # str.split() is more commonly used than re.split()
        date.append(parts[0])
        time.append(parts[1])
        count.append(parts[2])
        data.append(parts[3])

#create dictionary from data   key:index (location of element to plot)
    dict_index2parameter={}
    dict_parameter2index={}
    parts = data[0].split(',')  # str.split() is more commonly used than re.split()
    for i, part in enumerate(parts):  # enumerate counts and separates at the same time
        if '=' in part:  # `in` is more commonly used than re.search()
            q = part.split('=')  # str.partition() is also useful in this instance
            dict_parameter2index[q[0]]=i
            dict_index2parameter[i]=q[0]

    print dict_parameter2index
    print dict_index2parameter

# create decimal time
    dtime=[]
    for t in time:
        parts = t.split(':')
        d     = float( parts[0] ) + float( parts[1] )/60. + float( parts[2])/3600.   # decimal time
        dtime.append(d)
    return dtime,data,dict_index2parameter,dict_parameter2index

def extractWxt520Parm(data,nparm):

# extract data
#   nparm = 4   # parameter to display
    y = []
    for d in data:
        parts = d.split(',')
        y.append(get_num(parts[nparm]))
    return y

def extractWxt520Subinterval(endtime,duration,dtime,parm):
    iend = 60*endtime
    istart = iend - duration
    if istart <0:
        istart = 0;
        iend   = duration
    if iend > 1440:
        iend = 1439
        istart = iend - duration
    x=dtime[istart:iend]
    y=parm[istart:iend]
    return x,y

def pltwxt520(x,y):
    plt.grid()
    plt.plot(x,y)
    plt.save("wxt520.png",'PNG')   #??? save the file to disk
#   plt.show()

def button_action(sender):
    global wxt520Data, wxt520Time, nparm, parm
    # Get the root view:
    v = sender.superview
    parm = extractWxt520Parm(wxt520Data, nparm)
    v['label2'].text = 'fn = '+str(nparm)
    x,y = extractWxt520Subinterval(end, dur, wxt520Time, parm)
    pltwxt520(x, y)

def button1(sender):
    nparm = 7
    button_action(sender)

def button2(sender):
    nparm = 4
    button_action(sender)

def button3(sender):
    nparm = 9
    button_action(sender)

def slider_action(sender):
    global wxt520Data, wxt520Time,nparm,parm
    # Get the root view:
    v = sender.superview
    # Get the sliders:
    end = int( v['endtime'].value * 24 )
    dur = int ( v['duration'].value * 120 )
    # Create the new color from the slider values:
#   v['view1'].background_color = (r, r*0.1, r*0.23)
    v['label1'].text = 'End Time [h] = {}  Duration [m] = {}'.format(end, dur)  # str.format()
    v['label2'].text = 'fn = '+str(nparm)
#   print end, dur
    x,y = extractWxt520Subinterval(end,dur,wxt520Time,parm)
    pltwxt520(x,y)
#   img = image.load("wxt520.png")                            # ??? I am stuck here, at this point, I have image on console, image on disk but no image in my imageview1 ui element
#   v['imageview1'].image = img #.named("wxt520.png")
    v['imageview1'].image = ui.Image.named('wxt520.png')

def main():
    global wxt520Time, wxt520Data, nparm, parm

    time, data, dict1, dict2 = getWxt520Data()

    nparm=4
    parm = extractWxt520Parm(data,nparm)
    endTime = 24
    duration = 120
    wxt520Time = time
    wxt520Data = data
#   print wxt520Data

    x,y = extractWxt520Subinterval(endTime,duration,time,parm)
#   print x
#   print y
    v = ui.load_view('wxtuiplot')
    slider_action(v['endtime'])

    #if ui.get_screen_size()[1] >= 768:
    #    # iPad
    #    v.present('fullscreen')
    #else:
    #    # iPhone
    v.present()  # 'fullscreen' is the default

main()
paulj03

Apologies for delay in response - I did not expect such rapid response. This is great.

I had bashed my head too much on that before posting and then started working/learning to do other pythonista stuff.

  1. Re OMZ Feb 8 reply. It worked, now to make it really work. Thanks a lot. After bashing hard on it, I shifted to another python. I picked this up again and was just reading about ui and context etc got all confused. Really great. As usual, so close and yet so far.

  2. re Gerzer comment. Apologies. Last time in Editorial.

  3. re CCC... thanks, this was not production quality code and was trying to learn MPL, ui, etc all at the same time. One of the first things I did was try to snoop around the ipad and realize that I can write only into my own directory. (Maybe others like photos but not there yet.) Your additions are great. I've leaned a bunch of stuff and hopefully I can streamline this code.

Gerzer

@paulj03 This may not be your last time here, you may choose to buy Editorial as well! ;-) But seriously, Editorial may be a text automation app, but you don’t have to use it for that. It has a robust drag-and-drop workflow system that even lets you create UIs like in Pythonista but without any Python code. This would be a good way to learn UI programming fundamentals before you dive in to the actual code.

And who knows, you may find some text automation hole in your life. ;-P