Howdy, Stranger!

We are about to switch to a new forum software. Until then we have removed the registration on this forum.

  • Pulling time from PC and sending to arduino

    Check these prev posts: https://forum.processing.org/two/search?Search=datetime

    Or you can start by checking the reference: day(), month(), hour(), etc.

    Also check some arduino code: https://forum.processing.org/two/search?Search=arduino

    Kf

  • GSoc 2017: Application for processing.py

    Processing.py is based on Jython and you can easily access most of the Python standard library through it. In light of that, couple of comments on your suggestions list:

    1. Data Types: Python is dynamically typed language i.e., you don't have to define data types for your variables explicitly. So the lack of data types isn't a feature of Processing.py, rather, it's something that is built into the Python language itself! And as far as introducing data types in Python is concerned, it's a controversial issue even in the Python community. (You might want to look up the ctypes Python library and new Python features like type-hints and the like if you are interested in how static typing might be used in Python)
    2. Methods: Since you have access to the standard python library you can pretty much do all the things that you have listed. For instance, if d is some dictionary in python, you can copy it using d.copy(), you can check if a certain string s ends with the substring "py" using s.endswith("py"), etc. You should definitely take a look at the python standard library documentation to see what's possible.
    3. Date and Time: The python libraries like datetime and time provide a range of functions you can use through Python (and, by extension, through Processing.py)
    4. 3D Primitives: Is this something that you can do in "normal" Processing but not in Processing.py? If yes, then you can sure extend the Processing.py codebase to include cover this!
    5. Math: Python does have libraries like numpy that help you perform linear algebra operations (and a range of other numerical computing operations). Unfortunately, we can't call numpy through Processing.py. I'm not sure of Jython's limitations, but it would be interesting if you could find a hack that lets us call numpy and the like through Processing.py.
  • Date format

    The link was fantastic. I was able to get it to work. here is what I wrote:

    ii = -16;//start Time lable section
    DateTime = avg.get(forecast, 1);//avg is my file.csv and forecast is the row number of interest
    front = DateTime.substr(0, 10);//2016-05-25 15:00:00, silly time is missing the 'T'
    back = DateTime.substr(11);
    stringDateTime = front + "T" + back;// insert T, //2016-05-25T15:00:00
    newShadeTime = new Date(stringDateTime);
    for (i = 48; i < 970; i = i + 40) { //date draw
        front = DateTime.substr(0, 10);//2016-05-25 15:00:00
        back = DateTime.substr(11);
        stringDateTime = front + "T" + back;// insert T, //2016-05-25T15:00:00
        newDateTime = new Date(stringDateTime);
        TimeZoneOffset = (newDateTime.getTimezoneOffset() / 60);
        dateHour = newDateTime.getHours();
        TimeZoneOffset = dateHour - TimeZoneOffset;
        newDateTime.setHours((TimeZoneOffset));
        ii = ii + 8;
        var checkTime = newDateTime.getHours();
        var hourStep = checkTime + ii;
        newDateTime.setHours(hourStep);
        dateHour = newDateTime.getHours();
        dateMonth = newDateTime.getMonth();
        dateDate = newDateTime.getDate();
        dateDay = newDateTime.getDay();
    
        push(); // hour
        translate(77, 470 + graphNumber);
        rotate(-HALF_PI);
        fill(220);
        textSize(16);
        noStroke();
        textAlign(RIGHT);
        text(dateHour + ":", 0, i);// hours
        if (ii == 0 || ii == 24 || ii == 48 || ii == 72 || ii == 96 || ii == 120 || ii == 144 || ii == 168) {
            text(MonName[dateMonth] + " " + dateDate, -30, i - 1);// date
            rotate(HALF_PI);
            text(DayNames[dateDay], i + 50, 45);
        }
        pop();
    
        if (i == 88) {
            fill(220);
            textSize(23);
            noStroke();
            textAlign(RIGHT);
            text(MonName[dateMonth] + " " + dateDate + ", " + dateHour + ":00", 1040, 29 + graphNumber);
            shadeHour = dateHour;
        }
    } //end time lable section
    
  • Only displaying information from one dot

    Hi there,

    I'm plotting many dots representing bus routes in the US from a csv file. When hovering them I would like to display the bus route number of that specific point, unfortunately these are so close that many of them display making them unreadable.

    How can I go about solving this?

    Thanks in advance :)

    float [] lat, lon, x, y;
    int [] time;
    String [] dateTime, busRoute;
    int count;
    
    void setup() {
    
      size(600, 400);
      loadData();
      background(0);
      noStroke();
      smooth();
      textAlign(LEFT);
      cursor(CROSS);
    }
    
    
    void loadData() {
    
      //each array element is a *row* of data
      String [] sData = loadStrings("buses1.csv");
    
      //define length of longitude and lattitude array
      lat = new float[sData.length-1];
      lon = new float[sData.length-1];
      time = new int[sData.length-1];
      dateTime = new String[sData.length-1];
      busRoute = new String[sData.length-1];
    
      //iterate through rows and extract data
      for (int i = 1; i<sData.length; i++) {
    
        //split the row into an array on comma
        String [] thisRow = split(sData[i], ",");
    
        //format time into minutes
        String [] thisTime = split(thisRow[13], ":");
        int hours = int(thisTime[1]);
        int mins = int(thisTime[2].substring(0, 2));
        time[i-1] = (hours * 60) + mins;
    
        //extract date & time
        dateTime[i-1] = thisRow[8];
    
        //extract bus route
        busRoute[i-1] = thisRow[6];
    
        //write the correct cell to the lat and lon arrays
        //and convert them to floats
        lon[i-1] = float(thisRow[1]);
        lat[i-1] = float(thisRow[2]);
      }  
    
      //cast int on x & y position
      x = new float[lon.length];
      y = new float[lat.length];
    
      //use the mapping operation
      for (int i = 0; i<lat.length; i++) {
    
        x[i] = map(lon[i], min(lon), max(lon), 0, width);
        y[i] = map(lat[i], min(lat), max(lat), height-20, 0);
      }
    }
    
    void draw() {
    
      background(0);
    
      //increase size over time
      float size = time[count] * 0.1;
      if (size < 2) { 
        size = 2;
      }
    
      // draw points
      for (int j = 0; j < count; j++) {
        //Change color based on last report time
        if (time[j] <= 10) {
          fill(0, 0, 255, 150); 
          ellipse(x[j], y[j], size, size);
        } else {
          fill(255, 0, 0, 150);
          rect(x[j], y[j], size, size);
        }
      }
    
      //display bus route when hover over point - How do you only display one at a time?
      for (int i = 0; i < count; i++) {
        if ( dist(mouseX, mouseY, x[i], y[i]) < 10) {
          if (mouseY < 20) {
            pushStyle();
            fill(255);
            text("Bus route: " + busRoute[i], x[i], y[i] + 25);
          } else if (mouseX > width-75) {
            pushStyle();
            fill(255);
            text("Bus route: " + busRoute[i], x[i] - 90, y[i]);
          } else {
            pushStyle();
            fill(255);
            text("Bus route: " + busRoute[i], x[i], y[i] - 10);
          }
        }
      }
    
      count++;
    
      //progress bar
      fill(30);
      rect(0, height-20, map(count, 0, x.length, 0, width), 20);
      fill(255);
      text(nf(map(count, 0, x.length, 0, 100), 2, 0) + " %", width/2-40, height-5);
    
      // reset upon completion
      if (count == x.length) {
        count = 0;
        setup();
      }
    }
    
  • editing dynamic string // substring for dynamic xml value

    @honzojd: As with your other post: include a sample of the XML. If the time is in a standard datetime format you should be able to parse it directly to a date object, which is probably your intention...

    @benja: if the intention is to do something programmatically with the time values then none of your suggestions are especially useful as you're simply swapping one string representation for another. @GoToLoop's suggestion is better, but a datetime parser may be the best option depending on the string being parsed...

  • SimpleDateFormat conversion

    Hi Quark,

    This is perfect - I get the same results on my computer too. Thank you very much.

    Although ... ... I'm still a little confused by all the ways to record & derive java datetime values and I would like to learn more. If I would rewrite the sliding scale again in a more Java oriented way how would you propose I program it?

    Thanks again

  • How to convert Date (no time) to Unix Timetamp in Joda Time 2.4

    LocalDate isn't the right object for this task: it doesn't represent a moment in time. After some searches, I had a better result with DateTime:

    import org.joda.time.DateTime;
    
    int year = 2012;
    int weekNumber = 8;
    DateTime weekStartDate = new DateTime().withWeekOfWeekyear(weekNumber).withYear(year);
    DateTime weekEndDate = new DateTime().withWeekOfWeekyear(weekNumber + 1).withYear(year);
    println(weekStartDate+" - "+weekEndDate);
    println(weekStartDate.getMillis());
    exit();
    
  • Adding a time slider on a map

    I am still not sure about how to compare the tweet timestamp with the current start and end seek positions. Its getting hanged when I am trying to run it.

    void draw()
    {
      TableRow row;
      Location location;
      ScreenPosition position;
      DateTime dataTime;
    
      DateTime startDateTime1 , endDateTime1;
    
      Table data1;
      data1 = loadTable("2013-02-01.csv", "header");
    
        int i, rowCount;
      rowCount = data1.getRowCount();
    
      checkBoundingBox();  // to restrict panning
      map.draw();
    
      //debugDisplay.draw();
    
      image(button, buttonX, buttonY);
      timeRangeSlider1.draw();
    
     for(i = 0; i<rowCount; i++)
      { row = data1.getRow(i);
    
       dataTime = new DateTime(row.getInt("Year"), row.getInt("Month"), row.getInt("Date"), row.getInt("Hour"), row.getInt("Minute"), row.getInt("Second"));
       //println("tweet time :");    println(dataTime);
       startDateTime1 = timeRangeSlider1.getStartDateTime();  //returns the current start time
       endDateTime1 = timeRangeSlider1.getEndDateTime();  //returns the current end time
    
       if (dataTime.isAfter(startDateTime1) && dataTime.isBefore(endDateTime1)) 
       {
          location = new Location(row.getInt("Latitude"), row.getInt("Longitude"));
          position = map.getScreenPosition(location);
          fill(200, 0, 0, 100);
          //float s = map.getZoom();
          ellipse(position.x,position.y, 3, 3);
        }
      }
    }
    
  • Adding a time slider on a map

    I meant you could take your date properties from your tweets (which are stored in some type, I don't know, maybe String maybe Date) and convert them to DateTime for convenience. No need to do that, but as my TimeRangeSlider uses those it's very easy to compare then.

    Secondly, the drawing of the slider itself should only be changed if you want to change the style. As I wrote you could put the part where you time-compare your markers (or whatever you store the visual representations of the tweets in) into either the main draw method or into the timeUpdated() method.

  • Adding a time slider on a map

    I am not sure what you mean by "store my date properties as DateTime" . Does it mean that you are getting the value of time at which the seek of the slider is at the moment?

    I am also not sure of where to put this code. For eg, in the code of StyledTimeRangeSliderApp, when timeRangeSlider1.draw(); is called, the seek moves the whole width of the slider without checking any conditions. I am not sure about where to check if the time of my markers is within the range of the time slider.

  • Adding a time slider on a map

    Yes, you have to do it manually (so, what koogs said).

    What I typically do is use the Joda time library for convenience, store my date properties as DateTime, and then have a simple check if the time of my markers (e.g. your tweets) is within the range of the time slider.

    for (Marker marker : allTweetMarkers) {
      DateTime markerTime = (DateTime) marker.getProperty("dateTime");
      if (markerTime.isAfter(startDateTime) && markerTime.isBefore(endDateTime)) {
        // ...
      }
    }
    

    And then call that either in your draw method each frame, or set visibility of your markers in the timeUpdated() method of the TimeRangeSlider, e.g.

    public void timeUpdated(DateTime startDateTime, DateTime endDateTime) {
      filterMarkersByTime(startDateTime, endDateTime);
    }
    
  • Problem with Cyrillic characters when writing strings to MySQL

    I use BezierSQLib with MySQL to save tweets.

    // create table
    msql.execute( "CREATE TABLE IF NOT EXISTS " + table + " ("+"id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, TWEETID TEXT, DATE DATETIME, USER TEXT, LATITUDE FLOAT, LONGITUDE FLOAT, TWEET BLOB)  default charset=utf8");
    
    // Insert to MySQL
    if ( msql.connect() ) {
          msql.execute("INSERT INTO `dbtweets`.`tweets` (TWEETID , DATE , USER , LATITUDE , LONGITUDE , TWEET) VALUES (2,'1000-01-01 00:00:00',3,4,5,'" + status.getText() + "')");
        }
    

    But instead of Cyrillic letters I get "?". Please tell me what I'm doing wrong.

  • Help exporting my processing file to via udp

    Hi everyone, I am super new to processing and coding anything in general. I was hoping someone could help me with what I believe should be very simple. I downloaded a gps tracker to my smartphone that then exports the data to a processing script (the app is called moves and then has an app imbedded called mmapper) I have the processing script running no problem however I want to export it to grasshopper. I have been trying ti figure it out for some time now but just have no experience with any of these things. Hope it wont be too much trouble to help me out, Thanks!!

    // Format Events into Array of Dates 
    // - - - - - - - - - - - - - - - - - - - - - - - 
    
    void listDates() {
      movesDates = new int[0];
      for (int i=0; i<checkbox.getArrayValue().length; i++) {
        if (checkbox.getArrayValue(i) != 0) {
          if (d1.getValue() < 9) {
            month = "0" + str(int(d1.getValue()));
          } 
          else {
            month = str(int(d1.getValue()));
          }
          if (i < 9) {
            day = "0" + str(i+1);
          } 
          else {
            day = str(i+1);
          }
          year = str(int(d2.getValue()));
          date = year + month + day;
          movesDates = append(movesDates, int(date));
        }
      }
      println("- - - - - - - - - - - - - - -");
      makeMoves();
    }
    
    
    // Add Elements as necessary to Moves hashmap
    // elements in hashmap that shouldn't be shown won't be called in display function
    // - - - - - - - - - - - - - - - - - - - - - - - 
    void makeMoves() {
      for (int i=0; i<movesDates.length; i++) {
        if ( moves.containsKey(str(movesDates[i])) ) {
          //            println("Object key found: " + (movesDates[i]) +  " do nothing");
        } 
        else {
          //            println("Object key not found: " + (movesDates[i]) +  " add to hashmap");
          moves.put( str(movesDates[i]), new Move(str(movesDates[i])) );
        }
      }
    
      for (String k : moves.keySet()) {
        moves.get(k).mapPaths();
      }
    }
    
    
    
    void timeLabel() {
      String TimeOfDay_hour = str(floor(TimeOfDay/3600));
      String TimeOfDay_min = str(floor((TimeOfDay-int(TimeOfDay_hour)*3600)/60));
      String TimeOfDay_sec = str(TimeOfDay-int(TimeOfDay_hour)*3600-int(TimeOfDay_min)*60);
    
      if (TimeOfDay_hour.length() == 1) {
        TimeOfDay_hour = "0" + TimeOfDay_hour;
      } else if (TimeOfDay_min.length() == 1) {
        TimeOfDay_min = "0" + TimeOfDay_min;
      } else if (TimeOfDay_sec.length() == 1) {
        TimeOfDay_sec = "0" + TimeOfDay_sec;
      }
    
    //  println(TimeOfDay_hour + ":" + TimeOfDay_min + ":" + TimeOfDay_sec);
      TimeString = TimeOfDay_hour + ":" + TimeOfDay_min + ":" + TimeOfDay_sec + " UTC";
    
      cp5.getController("TimeOfDay").getValueLabel().setText(TimeString);
    }
    
    
    
    
    
    // - - - - - - - - - - - - - - - - - - - - - - - 
    // MOVE OBJECT
    // - - - - - - - - - - - - - - - - - - - - - - -  
    
    class Move { 
      String jsonDate;
      String place_name[] = new String[0];
      float place_long[] = new float[0];
      float place_lat[] = new float[0];
      int place_time[] = new int[0];
      float path_long[] = new float[0];
      float path_lat[] = new float[0];
      int path_time[] = new int[0];
      float loc_x[];
      float loc_y[];
      float place_loc_x, place_loc_y, lat_delta, long_delta, dimensionDelta;
      String path_type[] = new String[0];
      String[] dateTime = new String[1];
      String[] PlaceDateTime = new String[1];
      int hours, mins, secs;
    
      Move(String jsonDate_) {
        jsonDate = jsonDate_;
        jsonFetch(jsonDate);
        // Parse JSON
        JSONArray moves = loadJSONArray(jsonDate + ".json");
        for (int i = 0; i < moves.size(); i++) {
          JSONObject day = moves.getJSONObject(0);
          //      println("Date: " + day.getString("date"));
          JSONArray segments = day.getJSONArray("segments");
          //      println(day.getString("date") + ": " + segments.size() + " SEGMENTS");
          for (int j = 0; j < segments.size(); j++) {
            //        println("- - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
            //        println("Segment Number: " + j);
            JSONObject segment = segments.getJSONObject(j);
            //        println("Type: " + segment.getString("type"));
            //        println("Start Time: " + segment.getString("startTime"));
            //        println("End Time: " + segment.getString("endTime"));
            try {
              JSONArray activities = segment.getJSONArray("activities");
              for (int k = 0; k < activities.size(); k++) {
                JSONObject activity = activities.getJSONObject(k);
                //            println("Activity: " + activity.getString("activity"));
                //            println("Start Time: " + activity.getString("startTime"));
                //            println("End Time: " + activity.getString("endTime"));
                //            println("Duration: " + activity.getInt("duration"));
                if (activity.getString("activity").equals("wlk") || activity.getString("activity").equals("run")) {
                  //              println("Distance: " + activity.getInt("distance"));
                  //              println("Steps: " + activity.getInt("steps"));
                }
                JSONArray path = activity.getJSONArray("trackPoints");
                for (int l = 0; l < path.size(); l++) {
                  JSONObject point = path.getJSONObject(l);
                  //              println("- Lat: " + point.getFloat("lat"));
                  //              println("- Long: " + point.getFloat("lon"));
                  //              println("- Time: " + point.getString("time"));
                  // build path array
                  path_type = append(path_type, activity.getString("activity"));
                  path_long = append(path_long, point.getFloat("lon"));
                  path_lat = append(path_lat, point.getFloat("lat"));
                  dateTime = split(point.getString("time"), 'T');
                  //              println(activity.getString("activity") + " / iterator:" + l + " / arraySize:" + path_time.length + " / PathSize:" + path.size());
                  //              println(point.getString("time"));
                  dateTime = split(dateTime[1], 'Z');
                  path_time = append(path_time, int(dateTime[0]));
                  // convert path_time to minutes
                  hours = floor(path_time[path_time.length-1]*0.0001);
                  mins = floor((path_time[path_time.length-1] - hours*10000)*0.01);
                  secs = path_time[path_time.length-1] - hours*10000 - mins*100;
                  path_time[path_time.length-1] = hours*3600 + mins*60 + secs;
                }
              }
            }
            catch (Exception e) {
              //          println("error "+e);
            }
            try {
              JSONObject place = segment.getJSONObject("place");
    //          println("Start Time: " + segment.getString("startTime"));
    //          println("* " + place.getString("name"));
              //          println("* Type: " + place.getString("type"));
              //          println("* ID: " + place.getInt("id"));
              JSONObject location = place.getJSONObject("location");
              //          println("* Lat: " + location.getFloat("lat"));
              //          println("* Long: " + location.getFloat("lon"));
              // build unique places array
              place_name = append(place_name, place.getString("name"));
              place_long = append(place_long, location.getFloat("lon"));
              place_lat = append(place_lat, location.getFloat("lat"));
              // compute place_time in minutes
              PlaceDateTime = split(segment.getString("startTime"), 'T');
    //          println(PlaceDateTime);
              PlaceDateTime = split(PlaceDateTime[1], 'Z');
    //          println(PlaceDateTime);
              place_time = append(place_time, int(PlaceDateTime[0]));
    //          println("before: " + place_time[place_time.length-1]);
              // convert path_time to minutes
              hours = floor(place_time[place_time.length-1]*0.0001);
              mins = floor((place_time[place_time.length-1] - hours*10000)*0.01);
              secs = place_time[place_time.length-1] - hours*10000 - mins*100;
              place_time[place_time.length-1] = hours*3600 + mins*60 + secs;
    //          println( hours + ":" + mins + ":" + secs);
    //          println("after: " + place_time[place_time.length-1]);
            }
            catch (Exception e) {
              //          println("error "+e);
            }
          }
        }
        max_lats.set(jsonDate, max(path_lat));
        min_lats.set(jsonDate, min(path_lat));
        max_longs.set(jsonDate, max(path_long));
        min_longs.set(jsonDate, min(path_long));
      }
    
    
      void display() {
        // Draw Paths
        noFill();
        for (int i=0; i<path_long.length; i++) {
          if ( i>0 && path_type[i].equals("cyc") && cycle.booleanValue() && path_time[i] < TimeOfDay) {
            stroke(0, 255, 255, 100);
            line(loc_x[i], loc_y[i], loc_x[i-1], loc_y[i-1]);
          } 
          else if ( i>0 && path_type[i].equals("run") && run.booleanValue() && path_time[i] < TimeOfDay) {
            stroke(255, 0, 255, 100);
            line(loc_x[i], loc_y[i], loc_x[i-1], loc_y[i-1]);
          }
          else if ( i>0 && path_type[i].equals("wlk") && walk.booleanValue() && path_time[i] < TimeOfDay) {
            stroke(255, 255, 0, 100);
            line(loc_x[i], loc_y[i], loc_x[i-1], loc_y[i-1]);
          }
          else if ( i>0 && path_type[i].equals("trp") && transportation.booleanValue() && path_time[i] < TimeOfDay) {
            stroke(255, 40);
            line(loc_x[i], loc_y[i], loc_x[i-1], loc_y[i-1]);
          }
        }
        // Draw Places
        noStroke();
        for (int i=0; i<place_long.length; i++) {
          if (placesDrawn.hasKey(place_name[i])) {
          } 
          else if ( labels.booleanValue() && place_time[i] < TimeOfDay ) {
            place_loc_x = map(place_long[i], min_long, max_long, margin, canvasSize-margin);
            place_loc_y = map(place_lat[i], max_lat, min_lat, 80, canvasSize-margin);
            fill(255);
            ellipse(place_loc_x, place_loc_y, placeSize, placeSize);
            fill(255, 150);
            textSize(9);
            text(place_name[i], place_loc_x+placeSize, place_loc_y+3);
            placesDrawn.set(place_name[i], "true");
          }
        }
      }
    
    
      void mapBounds() {
        float max_lats_array[] = new float[0];
        float min_lats_array[] = new float[0];
        float max_longs_array[] = new float[0];
        float min_longs_array[] = new float[0];
        for (int i=0; i<movesDates.length; i++) {
          try {
            max_lats_array = append(max_lats_array, max_lats.get(str(movesDates[i])));
            min_lats_array = append(min_lats_array, min_lats.get(str(movesDates[i])));
            max_longs_array = append(max_longs_array, max_longs.get(str(movesDates[i])));
            min_longs_array = append(min_longs_array, min_longs.get(str(movesDates[i])));
          }
          catch (Exception e) {
          }
        }
        max_lat = max(max_lats_array);
        min_lat = min(min_lats_array);
        max_long = max(max_longs_array);
        min_long = min(min_longs_array);
        //    println(max_lat + " / " + min_lat + " / " + max_long + " / " + min_long);
      }
    
    
      void mapPaths() {
        loc_x = new float[path_long.length];
        loc_y = new float[path_lat.length];
        long_delta = abs(max_long-min_long)/2;
        lat_delta = abs(max_lat-min_lat);
        if (long_delta > lat_delta) {
          //      println( "long greater " + long_delta/lat_delta/2 + " / " + min_lat + " / " + max_lat );
          for (int i=0; i<path_long.length; i++) {
            loc_x[i] = map(path_long[i], min_long, max_long, margin, canvasSize-margin);
            loc_y[i] = map(path_lat[i], max_lat, min_lat, 80, canvasSize-margin);
          }
        }
        else {
          //      println("lat greater " + lat_delta/long_delta/2 + " / " + min_long + " / " + max_long);
          for (int i=0; i<path_long.length; i++) {
            loc_x[i] = map(path_long[i], min_long, max_long, margin, canvasSize-margin);
            loc_y[i] = map(path_lat[i], max_lat, min_lat, 80, canvasSize-margin);
          }
        }
      }
    
    
      void jsonFetch(String fetchDate) {
        File f = new File(dataPath( fetchDate + ".json" ));
        if ( !f.exists() ) { // Call API if data doesn't exist
          try {
            println("Querying… " + fetchDate);
            apiCall = "https://api.moves-app.com/api/v1/user/storyline/daily/" + fetchDate + "?trackPoints=true&access_token=" + accessToken;
            JSONArray result = loadJSONArray( apiCall );
            if (result != null) { // unsure if this call works
              saveJSONArray(result, dataPath(fetchDate + ".json"));
            }
          } 
          catch (Exception e) {
            println("No Data");
          }
        }
      }
    }
    
    
    
    // - - - - - - - - - - - - - - - - - - - - - - - 
    // MOVES MAPPER v1.0
    // Nicholas Felton — August 23, 2013
    // - - - - - - - - - - - - - - - - - - - - - - - 
    
    
    // - - - - - - - - - - - - - - - - - - - - - - - 
    // LIBRARIES
    // - - - - - - - - - - - - - - - - - - - - - - - 
    import controlP5.*;
    import java.util.Map;
    
    // - - - - - - - - - - - - - - - - - - - - - - - 
    // GLOBAL VARIABLES
    // - - - - - - - - - - - - - - - - - - - - - - - 
    
    // General
    int canvasSize = 800; // 550 minimum value
    
    // Data
    String date, year, month, day;
    int[] movesDates;
    String accessToken = "T6Ka1cm30D590JOviXtQmV9RKLtc5DQ01cRyqyODrMir0o5ubiuO09589719l16e";
    String apiCall;
    HashMap<String, Move> moves = new HashMap<String, Move>();
    int timeOffset = -4;
    
    // Draw
    int placeSize = 6;
    FloatDict max_lats = new FloatDict();
    FloatDict min_lats = new FloatDict();
    FloatDict max_longs = new FloatDict();
    FloatDict min_longs = new FloatDict();
    float max_lat, min_lat, max_long, min_long;
    float mapOffset;
    StringDict placesDrawn = new StringDict();
    int margin = 30;
    
    // GUI
    ControlP5 cp5;
    DropdownList d1, d2;
    CheckBox checkbox;
    Button labels, walk, run, cycle, transportation;
    String[] monthNames = {
      "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"
    };
    String[] monthDaysStandard = {
      "31", "28", "31", "30", "31", "30", "31", "31", "30", "31", "30", "31"
    };
    String[] monthDaysLeap = {
      "31", "29", "31", "30", "31", "30", "31", "31", "30", "31", "30", "31"
    };
    int TimeOfDay;
    String TimeString = "00:00:00";
    
    
    
    
    
    // - - - - - - - - - - - - - - - - - - - - - - - 
    // SETUP
    // - - - - - - - - - - - - - - - - - - - - - - - 
    void setup() {
      size(canvasSize, canvasSize+150);
      smooth();
      hint(ENABLE_STROKE_PURE);
      cp5 = new ControlP5(this);
    
      // Instantiate Date GUI
      GUIcheckbox("checkbox", 150, height-135);
      GUIdropdownD1("d1-month", 20, height-95, "MONTH");
      GUIdropdownD2("d2-year", 20, height-120, "YEAR");
    
      // Populate Date GUI
      GUImonth(year(), month(), month());
      GUIyear(year());
      GUIday(year(), month(), day());
    
      // Additional GUI
      labels = cp5.addButton("labels")
        .setPosition(width-120, height-135)
          .setSize(100, 20)
            .setHeight(15)
              .setColorForeground(color(190))
                .setColorBackground(color(60))
                  .setColorActive(color(255, 128))
                    .setSwitch(true)
                      .setOn()
                      ;
    
      walk = cp5.addButton("walk")
        .setPosition(width-120, height-110)
          .setSize(100, 20)
            .setHeight(15)
              .setColorForeground(color(45))
                .setColorBackground(color(60))
                  .setColorActive(color(255, 128))
                    .setSwitch(true)
                      .setOn()
                      ;
    
      run = cp5.addButton("run")
        .setPosition(width-120, height-85)
          .setSize(100, 20)
            .setHeight(15)
              .setColorForeground(color(190))
                .setColorBackground(color(60))
                  .setColorActive(color(255, 128))
                    .setSwitch(true)
                      .setOn()
                      ;
    
      cycle = cp5.addButton("cycle")
        .setPosition(width-120, height-60)
          .setSize(100, 20)
            .setHeight(15)
              .setColorForeground(color(190))
                .setColorBackground(color(60))
                  .setColorActive(color(255, 128))
                    .setSwitch(true)
                      .setOn()
                      ;
    
      transportation = cp5.addButton("transportation")
        .setPosition(width-120, height-35)
          .setSize(100, 20)
            .setHeight(15)
              .setColorForeground(color(190))
                .setColorBackground(color(60))
                  .setColorActive(color(255, 128))
                    .setSwitch(true)
                      .setOn()
                      ;
    
      // add a vertical slider
      cp5.addSlider("TimeOfDay")
        .setPosition(margin, margin)
          .setSize(width-(2*margin), 10)
            .setRange(0, 86400)
              .setValue(86400)
                .setColorForeground(color(190))
                  .setColorBackground(color(60))
                    .setColorActive(color(255, 128))
                      ;
    
      // reposition the Label for controller 'slider'
      cp5.getController("TimeOfDay").getValueLabel().setText(TimeString).align(ControlP5.LEFT, ControlP5.BOTTOM_OUTSIDE).setPaddingX(0);
      cp5.getController("TimeOfDay").getCaptionLabel().align(ControlP5.RIGHT, ControlP5.BOTTOM_OUTSIDE).setPaddingX(0);
    }
    
    
    // - - - - - - - - - - - - - - - - - - - - - - - 
    // DRAW LOOP
    // - - - - - - - - - - - - - - - - - - - - - - - 
    
    void draw() {
      frame.setTitle(int(frameRate) + " fps / " + frameCount + " frames");
      background(40);
      placesDrawn.clear();
      timeLabel();
    
      // Draw Moves
      for (int i=0; i<movesDates.length; i++) {      
        try {
          moves.get(str(movesDates[i])).display();
        }
        catch (Exception e) {
        }
    

    } }