Take the 2-minute tour ×
Geographic Information Systems Stack Exchange is a question and answer site for cartographers, geographers and GIS professionals. It's 100% free, no registration required.

I'd like to create a flex wrapper for python code run locally (utilizing arcgis data and outputting data that can be displayed on the flexviewer). I'd like to use gdal or pyproj modules to process data locally with distributed scripts.

How would one go about creating a wrapper-widget that extends the basewidget class in the arcgis viewer for flex that can communicate with the local install of the python interpreter?

EDIT

web.py rest services

in terms of the workflow: user without arcgis server license (for geoprocessing tasks) wants to perform some spatial analysis on a graphic layer in the flex viewer (flash or air).

python script running as a web service (web.py?) accepts vector input ("public" viewshed geoprocessing task demonstrated by esri (http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/Elevation/ESRI_Elevation_World/GPServer/Viewshed) creates a graphic polygon layer as output). Using a graphic layer from the flex viewer as input to a "point in polygon" python script (http://geospatialpython.com/2011/01/point-in-polygon.html) would make the output from the viewshed (or other graphic generating tool) more useful.

I hope that answers your question.

share|improve this question
    
Could you expand on the workflow a little more? I'm not quite understanding what the big picture is here. There is probably many ways to get to the same endpoint, but with more information the better options will be more obvious. –  MLowry May 10 '12 at 14:02
add comment

2 Answers

This isn't really a doable thing -- the best you can hope for here is to install ArcGIS Server on the local machine and expose the Python script as a Geoprocessing service.

share|improve this answer
    
I disagree.. it is possible if the ArcGIS Viewer is compiled into an Adobe AIR app (using AIR >= v2.0), through which AIR's NativeProcess API could be leveraged to call the Python script. Meanwhile, since AIR is still client/server, distributed ArcServer support should still work. The con here is that the Flex solution would not port to a public-facing web page. For an example, though, note this page among Adobe's documentation that calls a Python script from a Flex/AIR application: help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/… –  elrobis May 10 '12 at 21:03
add comment

To put it succinctly: you'll need to burn the ArcGIS Viewer for Flex into a thick client (Adobe AIR) implementation in order to take advantage of the Flex/AIR NativeProcess API, which will allow you to call local executables such as a Python file.

Here's a quick demo app I whipped up awhile back demonstrating how to call an ogr2ogr instruction from a Flex/AIR application. This shows calling a .exe executable, but calling a local Python script uses the same plumbing.

[The Caveat]

Foremost, while it's impossible to do this from a Flex appelet--that is, a Flex app embedded in an HTML page, it is possible to do this from an Adobe AIR app--that is, a thick-client (the AIR app) implementation that is crippled without its service tier (the ArcServer instance). Consider Google Earth: you install it and run it locally, but it needs your internet connection to pull in the Google data. This is the same thinking.

Also, this example demonstrates only the Flex/AIR implementation of the NativeProcess API. Adding the ArcGIS Viewer for Flex to the app is irrelevant to the actual problem here, which is merely bridging Flex and Python, or whatever else you want to execute locally.

Additionally, this example is relative to Flex 3 using the Flex 3.6 SDK overlaid with the AIR 3.0 SDK. However, compiling a Flex 3 + AIR solution in Flex Builder 3 will likely prove challenging, as you'll need to compile a native installer (.exe) manually using the SDK's command line compiler, ADT.

The approach is actually much easier for Flex 4 + AIR solution, presuming you overlay your Flex SDK with a minimum AIR version 2.0 SDK, because Flash Builder 4 can compile the requisite native installer right out of the box.

[Now, the Solution]

1) Make sure to update the supportedProfiles tag in your AIR app's XML descriptor file so that your application will be compiled with extendedDesktop support.

<!-- We recommend omitting the supportedProfiles element, -->
<!-- which in turn permits your application to be deployed to all -->
<!-- devices supported by AIR. If you wish to restrict deployment -->
<!-- (i.e., to only mobile devices) then add this element and list -->
<!-- only the profiles which your application does support. -->

<supportedProfiles>extendedDesktop</supportedProfiles>

2) Here's the one-file MXML application I wrote to test this sort of functionality:

<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" 
    layout="vertical" verticalScrollPolicy="off" height="450" 
    paddingTop="12" paddingBottom="12" 
    paddingLeft="12" paddingRight="12" 
    horizontalAlign="left">

    <mx:Script>
        <![CDATA[
            import __AS3__.vec.Vector;
            import flash.desktop.NativeProcess;
            import flash.desktop.NativeProcessStartupInfo;
            import flash.filesystem.File;
            import flash.system.Capabilities;
            import mx.controls.Alert;

            /**
             * Build and execute an OGR2OGR method call from an AIR app.
             * 
             * This app attempts to execute the following OGR2OGR script:
             * 
             *   ogr2ogr -f ESRI Shapefile E:\4_GIS\01_tutorials\junk\us_states.shp 
             *   MySql:dbName,host=localhost,user=root,password=pass,port=3306 
             *   us_states
             **/

            private var _proc:NativeProcess;

            private function launchApp():void
            {
                if(NativeProcess.isSupported)
                {                   
                    if(Capabilities.os.toLowerCase().indexOf("win") > -1)
                    {
                        // Attach to ogr2ogr.exe here..
                        var file:File = new File(exePathTI.text);

                        var npsi:NativeProcessStartupInfo;
                        npsi = new NativeProcessStartupInfo();
                        npsi.executable = file;

    // ogr2ogr method arguments here..                  
    // CAVEAT: ..something doesn't like "quotes" in the OGR2OGR arguments.
    // For instance, use ESRI Shapefile, not "ESRI Shapefile".
                        var procArgs:Vector.<String> = new Vector.<String>();

                        // output format flag
                        // -f
                        procArgs[0] = arg0TI.text;

                        // output format
                        // ESRI Shapefile 
                        procArgs[1] = arg1TI.text;

                        // file destination
                        // i.e. E:\4_GIS\01_tutorials\junk\us_states.shp
                        var savePathFile:File = new File(arg2TI.text);
                        procArgs[2] = savePathFile.nativePath;

                        // connection string
                        // i.e. MySql:dbName,host=localhost,user=root,password=pass,port=3306
                        procArgs[3] = arg3TI.text;

                        // table name 
                        // i.e. us_states
                        procArgs[4] = arg4TI.text;
                        npsi.arguments = procArgs;

                        _proc = new NativeProcess();
                        _proc.start(npsi);
                        _proc.addEventListener(ProgressEvent.STANDARD_OUTPUT_DATA, onOutputData);
                        _proc.addEventListener(ProgressEvent.STANDARD_ERROR_DATA, onErrorData);
                        _proc.addEventListener(NativeProcessExitEvent.EXIT, onExit);
                        _proc.addEventListener(IOErrorEvent.STANDARD_OUTPUT_IO_ERROR, onIOError);
                        _proc.addEventListener(IOErrorEvent.STANDARD_ERROR_IO_ERROR, onIOError);
                    }
                    else
                    {
                        Alert.show("Something bombed..");   
                    }
                }
                else
                {
                    Alert.show("NativeProcess support not detected");
                }
            }

            private function onOutputData(event:ProgressEvent):void
            {
                trace( "(Response) THE PROCESS RESPONDED: ", 
                        _proc.standardOutput.readUTFBytes(
                            _proc.standardOutput.bytesAvailable) ); 
            }

            private function onErrorData(event:ProgressEvent):void
            {
                trace( "(Error) SOMETHING FAILED: ", 
                        _proc.standardError.readUTFBytes(
                            _proc.standardError.bytesAvailable) ); 
            }

            private function onExit(event:NativeProcessExitEvent):void
            {
                trace( "(Exit) THE PROCESS RETURNED: ", event.exitCode );
            }

            private function onIOError(event:IOErrorEvent):void
            {
                 trace(event.toString());
            }
        ]]>
    </mx:Script>

    <!-- full path to the ogr2ogr.exe executable -->
    <mx:Label text="Path to the ogr2ogr executable:"/>
    <mx:TextInput id="exePathTI" text="C:\Program Files\GDAL\ogr2ogr.exe" width="100%"/>

    <mx:Spacer height="25"/>

    <!-- sample ogr2ogr arguments that worked in testing -->
    <mx:Label text="Output format flag:"/>
    <mx:TextInput id="arg0TI" text="-f" width="100%"/>
    <mx:Label text="Output format:"/>
    <mx:TextInput id="arg1TI" text="ESRI Shapefile" width="100%"/>
    <mx:Label text="Output directory (MUST ALREADY EXIST):"/>
    <mx:TextInput id="arg2TI" text="E:\4_GIS\01_tutorials\junk\us_states.shp" width="100%"/>
    <mx:Label text="OGR Connection string:"/>
    <mx:TextInput id="arg3TI" text='MySql:dbName,host=localhost,user=root,password=pass,port=3306' width="100%"/>
    <mx:Label text="Table name:"/>
    <mx:TextInput id="arg4TI" text="us_states" width="100%"/>

    <mx:Button label="Try It!" click="launchApp();"/>

</mx:WindowedApplication>

[The ADT Script]

(Not necessary if using Flash Builder 4, as you can compile a native installer right out of the box!)

I used the following ADT script to compile this for my Flex 3 + AIR 3 implementation:

adt -package -storetype pkcs12 -keystore "C:\dev\flexwksp\CallOgrFromAIR\cert_pass_is_heyflex.p12" -target native -CallOgrFromAIR.exe CallOgrFromAIR-app.xml CallOgrFromAIR.swf

Finally, if you want another example of this kind of thing --one flavored more for Flex 4 and Flash Builder 4, I posted a similar answer on StackOverflow once upon a time. It has a couple supporting screenshots that might also prove helpful.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.