SciPy, NumPy, and Matplotlib: Plotting in 3D

You can see this app running online at: Plotting in 3D Online

This app aims to demonstrate:

What this app does:

  • Accepts a set of parameters for a 3D plot (mesh size, x y max and mins).
  • Creates a plot of Z=sin(sqrt(x^2 + y^2)) using SciPy, NumPy and Matplotlib.
  • Displays this plot.

Setup Instructions

Before you can run this app, you will need to install:

There are many ways to install SciPy, NumPy and Matplotlib, most of which as listed here. Anaconda, provide easy installers for Windows, OSX, Ubuntu and Debian.

If you don’t want to use a pre-built installer:

  • Matplotlib has non Python dependencies which must be installed first:
    • Windows: Download an installer and run. Get the .exe file which matches your Python version (probably 2.7)
    • Unix: May need additional non Python dependencies. E.g for Ubuntu run:
    sudo apt-get install libfreetype6-dev libpng-dev
    
  • Then install the Python packages (note separating the commands, seems to work smoother):

    (tropofy_env) $ pip install numpy; pip install scipy; pip install matplotlib
    
  • Errors installing Scipy? On Ubuntu you may need to also run:

    sudo apt-get install libblas-dev liblapack-dev gfortran
    

Next, use the app name 'tropofy_plotting_in_3d' to quickstart as in Running and Debugging Tropofy Apps

Full Source

"""
Author:      www.tropofy.com

Copyright 2015 Tropofy Pty Ltd, all rights reserved.

This source file is part of Tropofy and governed by the Tropofy terms of service
available at: http://www.tropofy.com/terms_of_service.html

This source file is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
"""

from tropofy.app import AppWithDataSets, Parameter, Step, StepGroup, ParameterGroup
from tropofy.widgets import StaticImage, ExecuteFunction, ParameterForm
from tropofy.file_io import read_write_aws_s3
import StringIO

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import pylab as pl
import pkg_resources


class OutputPlot(StaticImage):
    def get_file_path(self, app_session):
        return read_write_aws_s3.AwsS3Reader.get_file_access_url(app_session, file_name='output.png')


def validate_value_g_zero(value):
    return True if value > 0 else "Value must be > 0."


class PlotParameterGroup(ParameterGroup):
    MESH_SIZE = Parameter(name='mesh_size', label='Mesh Size', default=0.25, allowed_type=float, validator=validate_value_g_zero)
    X_MIN = Parameter(name='x_min', label='X-Min', default=-4, allowed_type=float)
    X_MAX = Parameter(name='x_max', label='X-Max', default=4, allowed_type=float)
    Y_MIN = Parameter(name='y_min', label='Y-Min', default=-4, allowed_type=float)
    Y_MAX = Parameter(name='y_max', label='Y-Max', default=4, allowed_type=float)


class MyApp(AppWithDataSets):
    def get_name(self):
        return "Plotting in 3d"

    def get_static_content_path(self, app_session):
        return pkg_resources.resource_filename('te_plotting_in_3d', 'static')

    def get_gui(self):
        return [
            StepGroup(
                name='Input',
                steps=[
                    Step(name='Parameters', widgets=[
                        {"widget": ParameterForm(), "cols": 6},
                    ]),
                    Step(name='Create Plot', widgets=[CreatePlot()]),
                ]
            ),
            StepGroup(
                name='Output',
                steps=[
                    Step(name='Output', widgets=[OutputPlot()])
                ]
            ),
        ]

    def get_parameters(self):
        return PlotParameterGroup.get_params()

    def get_examples(self):
        return {"Demo data set": load_example_data}

    def get_icon_url(self):
        return "/{}/static/{}/histogram_3d.png".format(
            self.url_name,
            self.get_app_version(),
        )


class CreatePlot(ExecuteFunction):
    def get_button_text(self, app_session):
        return "Create plot of Z = sin(sqrt(x^2 + y^2))"

    def execute_function(self, app_session):
        fig = pl.figure()
        ax = Axes3D(fig)
        X = np.arange(
            app_session.data_set.get_param(PlotParameterGroup.X_MIN.name),
            app_session.data_set.get_param(PlotParameterGroup.X_MAX.name),
            app_session.data_set.get_param(PlotParameterGroup.MESH_SIZE.name)
        )
        Y = np.arange(
            app_session.data_set.get_param(PlotParameterGroup.Y_MIN.name),
            app_session.data_set.get_param(PlotParameterGroup.Y_MAX.name),
            app_session.data_set.get_param(PlotParameterGroup.MESH_SIZE.name)
        )
        X, Y = np.meshgrid(X, Y)
        R = np.sqrt(X ** 2 + Y ** 2)
        Z = np.sin(R)

        ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=pl.cm.hot)
        ax.contourf(X, Y, Z, zdir='z', offset=-2, cmap=pl.cm.hot)
        ax.set_zlim(-2, 2)

        plt.title('Plot of $Z = sin\sqrt{x^2+y^2}$')

        img_data = StringIO.StringIO()
        plt.savefig(img_data, format="png", bbox_inches=0)
        img_data.seek(0)
        file = img_data.buf

        read_write_aws_s3.AwsS3Writer.save_file_string(app_session, string_data=file, file_name='output.png')
        app_session.task_manager.send_progress_message("Plot successfully created. Go to next step to view it.")


def load_example_data(app_session):
    pass