Forum Archive

UI for matplotlib

p_atrick

I new to Python/Pythonista, and I am wondering if it would be possible to have a UI to launch something I did in matplotlib. I want to be able to tap a button and launch the scatter plot. The scatter plot works without the UI, but I am having trouble getting the button to work. Here is the code I have so far:

import ui
import matplotlib.pyplot as plt
from random import choice, randint

v = ui.load_view()
v.present('sheet')

def button_tapped(sender):
    show_walk()

def fill_x_values(walk_length):
    x_values = [0]
    points = walk_length
    while len(x_values) < points:
        x_direction = choice([1, -1])
        x_distance = choice([1, 2, 3, 4])
        x_step = x_direction * x_distance
        next_x = x_values[-1] + x_step
        x_values.append(next_x)
    return x_values

def fill_y_values(walk_length):
    y_values = [0]
    points = walk_length
    while len(y_values) < points:
        y_direction = choice([1, -1])
        y_distance = choice([1, 2, 3, 4])
        y_step = y_direction * y_distance
        next_y = y_values[-1] + y_step
        y_values.append(next_y)
    return y_values

def show_walk():
    walk_length = 50000
    x_values = fill_x_values(walk_length)
    y_values = fill_x_values(walk_length)

    plt.scatter(x_values, y_values,c='red', edgecolor='none', alpha=0.2, s=7)
    plt.axes().get_xaxis().set_visible(False)
    plt.axes().get_yaxis().set_visible(False)
    plt.show()

button = ui.Button()
button.action = button_tapped

Do any of you see what I am doing wrong? If you need any more info from me, please let me know. Thanks in advance.

chriswilson

Hi @p_atrick
Welcome to Pythonista.

While I'm not familiar with matplotlib, I can suggest a couple of points regarding the UI.

The lines...

v = ui.load_view()
v.present('sheet')

...need to go towards the end of your code, after the function definitions like def button_tapped(sender) so that the UI can "see" these definitions before it is initialised. Presenting the view should be the last thing you do.

I see you use ui.load_view() which will load a pyui file with the same name as your script. It might be easier to define your button entirely in the interface builder (including setting its action attribute).

Currently your last two lines of code only create a button object but do not place it anywhere within the UI (and as your UI is already "presented" it cannot be added anyway). These lines are unnecessary if the button is defined in the pyui file.

Finally, I understand matplotlib draws things in the console, so you might not see anything on pressing the button unless you exit to the console.

I hope this is helpful!

chriswilson

This code will present a very basic button that will run the matplotlib stuff when pressed. No pyui file used here.

As I mentioned, the matplotlib graph appears in the console rather than the UI. You might need to use a different UI element to display a matplotlib graph (maybe a ui.ImageView()) but I'm not sure of the specifics as regards working with matplotlib.

import ui
import matplotlib.pyplot as plt
from random import choice, randint

def button_tapped(sender):
    button.title = "Tapped!"
    show_walk()

def fill_x_values(walk_length):
    x_values = [0]
    points = walk_length
    while len(x_values) < points:
        x_direction = choice([1, -1])
        x_distance = choice([1, 2, 3, 4])
        x_step = x_direction * x_distance
        next_x = x_values[-1] + x_step
        x_values.append(next_x)
    return x_values

def fill_y_values(walk_length):
    y_values = [0]
    points = walk_length
    while len(y_values) < points:
        y_direction = choice([1, -1])
        y_distance = choice([1, 2, 3, 4])
        y_step = y_direction * y_distance
        next_y = y_values[-1] + y_step
        y_values.append(next_y)
    return y_values

def show_walk():
    walk_length = 50000
    x_values = fill_x_values(walk_length)
    y_values = fill_x_values(walk_length)

    plt.scatter(x_values, y_values,c='red', edgecolor='none', alpha=0.2, s=7)
    plt.axes().get_xaxis().set_visible(False)
    plt.axes().get_yaxis().set_visible(False)
    plt.show()

button = ui.Button()
button.present()
button.title = "Press here!"
button.action = button_tapped
JonB

see here for an example of a matplotlib interactive zooming plot. I am not entirely sure if this works in the latest pythonista versions (probably only for the 2.7 interpreter)

But the key to simple static plots is basically:

         self.b.seek(0)   
         plt.savefig(self.b,format='jpg',dpi=dpi)
         self.img_view.image = ui.Image.from_data(self.b.getvalue())

where self.b is a BytesIO object, and dpi is a number which you can experiment with to trade off speed vs quality.

Also, something like

plt.gcf().set_size_inches(self.width/dpi,self.height/dpi)

might be needed so the dpi values are meaningful.