diff --git a/geomagio/JSON/JSONFactory.py b/geomagio/JSON/JSONFactory.py
index 9cb43039fa776e6a575accfb5fea318152c38bd9..539cba2c0c9f3655a550ea47a4ed4bbd4cb85b7c 100644
--- a/geomagio/JSON/JSONFactory.py
+++ b/geomagio/JSON/JSONFactory.py
@@ -26,25 +26,6 @@ class JSONFactory(TimeseriesFactory):
     def __init__(self, **kwargs):
         TimeseriesFactory.__init__(self, **kwargs)
 
-    # TODO: Write parser method
-    def parse_string(self, data, observatory=None, interval='minute',
-            **kwargs):
-        """Parse the contents of a string in the format of an json file.
-
-        Parameters
-        ----------
-        jsonString : str
-            string containing IAGA2002 content.
-        observatory : str
-            observatory in case headers are unavailable.
-            parses observatory from headers when available.
-        Returns
-        -------
-        obspy.core.Stream
-            parsed data.
-        """
-        pass
-
     def write_file(self, fh, timeseries, channels):
         """writes timeseries data to the given file object.
 
diff --git a/geomagio/JSON/JSONWriter.py b/geomagio/JSON/JSONWriter.py
index 1574a48ee7a1e6360a83f4c01b5a47fc3ad86527..bad681dba62931cbec5d1e8826b4860f58126f66 100644
--- a/geomagio/JSON/JSONWriter.py
+++ b/geomagio/JSON/JSONWriter.py
@@ -5,21 +5,17 @@ from io import BytesIO
 from collections import OrderedDict
 from datetime import datetime
 import json
-import numpy
+import numpy as np
 import textwrap
 from .. import ChannelConverter, TimeseriesUtility
 from ..edge import EdgeFactory
 from ..TimeseriesFactoryException import TimeseriesFactoryException
 from ..Util import create_empty_trace
 
-
 class JSONWriter(object):
     """JSON writer.
     """
 
-    def __init__(self):
-        self.dictionary = OrderedDict()
-
     def write(self, out, timeseries, channels, **kwargs):
         """write timeseries to json file
 
@@ -32,6 +28,7 @@ class JSONWriter(object):
         channels: array_like
             channels to be written from timeseries object
         """
+        dictionary = OrderedDict()
         request = kwargs.get('request')
         for channel in channels:
             if timeseries.select(channel=channel).count() == 0:
@@ -39,14 +36,13 @@ class JSONWriter(object):
                     'Missing channel "%s" for output, available channels %s' %
                     (channel, str(TimeseriesUtility.get_channels(timeseries))))
         stats = timeseries[0].stats
-        if len(channels) != 4:
-            channels = self._pad_to_four_channels(timeseries, channels)
-        self._format_metadata(stats, channels)
+        dictionary['type'] = 'Timeseries'
+        dictionary['metadata'] = self._format_metadata(stats, channels)
         if request:
-            self.dictionary['metadata']['url'] = 'http://geomag.usgs.gov/ws/edge/?' + request
-        self._format_times(timeseries, channels)
-        self._format_data(timeseries, channels, stats)
-        out.write(json.dumps(self.dictionary, ensure_ascii=True).encode(
+            dictionary['metadata']['url'] = 'http://geomag.usgs.gov/ws/edge/?' + request
+        dictionary['times'] = self._format_times(timeseries, channels)
+        dictionary['values'] = self._format_data(timeseries, channels, stats)
+        out.write(json.dumps(dictionary, ensure_ascii=True).encode(
                 'utf8'))
 
     def _format_metadata(self, stats, channels):
@@ -58,15 +54,18 @@ class JSONWriter(object):
             holds the observatory metadata
         channels: array_like
             channels to be reported.
+
+        Returns
+        -------
+        dictionary
+            a dictionary containing metadata.
         """
-        dict = self.dictionary.copy()
-        dict['type'] = 'Timeseries'
-        dict['metadata'] = OrderedDict()
-        dict['metadata']['intermagnet'] = OrderedDict()
-        dict['metadata']['intermagnet']['imo'] = OrderedDict()
-        dict['metadata']['intermagnet']['imo']['iaga_code'] = stats.station
+        metadata_dict = OrderedDict()
+        intermag = OrderedDict()
+        imo = OrderedDict()
+        imo['iaga_code'] = stats.station
         if 'station_name' in stats:
-            dict['metadata']['intermagnet']['imo']['name'] = stats.station_name
+            imo['name'] = stats.station_name
         coords = [None] * 3
         if 'geodetic_longitude' in stats:
             coords[0] = str(stats.geodetic_longitude)
@@ -74,12 +73,13 @@ class JSONWriter(object):
             coords[1] = str(stats.geodetic_latitude)
         if 'elevation' in stats:
             coords[2] = str(stats.elevation)
-        dict['metadata']['intermagnet']['imo']['coordinates'] = coords
-        dict['metadata']['intermagnet']['reported_orientation'] = ''.join(channels)
+        imo['coordinates'] = coords
+        intermag['imo'] = imo
+        intermag['reported_orientation'] = ''.join(channels)
         if 'sensor_orientation' in stats:
-            dict['metadata']['intermagnet']['sensor_orientation'] = stats.sensor_orientation
+            intermag['sensor_orientation'] = stats.sensor_orientation
         if 'data_type' in stats:
-            dict['metadata']['intermagnet']['data_type'] = stats.data_type
+            intermag['data_type'] = stats.data_type
         if 'sampling_rate' in stats:
             if stats.sampling_rate == 1. / 60.:
                 rate = 60
@@ -89,22 +89,28 @@ class JSONWriter(object):
                 rate = 86400
             else:
                 rate = 1
-            dict['metadata']['intermagnet']['sampling_period'] = str(rate)
+            intermag['sampling_period'] = str(rate)
         if 'sensor_sampling_rate' in stats:
-            dict['metadata']['intermagnet']['digital_sampling_rate'] = str(1 / stats.sensor_sampling_rate)
-        dict['metadata']['status'] = 200
-        dict['metadata']['generated'] = datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ")
-        self.dictionary = dict
+            intermag['digital_sampling_rate'] = str(1 / stats.sensor_sampling_rate)
+        metadata_dict['intermagnet'] = intermag
+        metadata_dict['status'] = 200
+        metadata_dict['generated'] = datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ")
+        return metadata_dict
 
     def _format_times(self, timeseries, channels):
         """format times for json file and update dictionary
 
         Parameters
         ----------
-        timeseries: obspy.core.stream
-            timeseries object with data to be written
+        stats: obspy.core.trace.stats
+            holds the observatory metadata
         channels: array_like
             channels to be reported.
+
+        Returns
+        -------
+        array_like
+            an array containing formatted strings of time data.
         """
         times = []
         traces = [timeseries.select(channel=c)[0] for c in channels]
@@ -113,7 +119,7 @@ class JSONWriter(object):
         for i in range(len(traces[0].data)):
             times.append(self._format_time_string(
                 datetime.utcfromtimestamp(starttime + i * delta)))
-        self.dictionary['times'] = times
+        return times
 
     def _format_time_string(self, time):
         """format one time.
@@ -144,8 +150,12 @@ class JSONWriter(object):
             list and order of channel values to output.
         stats: obspy.core.trace.stats
             holds the observatory metadata
+
+        Returns
+        -------
+        array_like
+            an array containing dictionaries of data.
         """
-        self.dictionary['values'] = []
         if timeseries.select(channel='D'):
             d = timeseries.select(channel='D')
             d[0].data = ChannelConverter.get_minutes_from_radians(d[0].data)
@@ -155,38 +165,24 @@ class JSONWriter(object):
             value_dict = OrderedDict()
             trace = timeseries.select(channel=c)[0]
             value_dict['id'] = c
-            value_dict['metadata'] = OrderedDict()
-            value_dict['metadata']['element'] = c
+            value_dict = OrderedDict()
+            value_dict['element'] = c
             if 'network' in stats:
-                value_dict['metadata']['network'] = stats.network
-            value_dict['metadata']['station'] = stats.station
-            edge_channel = self.edge._get_edge_channel(stats.station,
-                                                        c,
-                                                        stats.data_type,
-                                                        stats.data_interval)
-            value_dict['metadata']['channel'] = edge_channel
+                value_dict['network'] = stats.network
+            value_dict['station'] = stats.station
+            if 'channel' in stats:
+                edge_channel = trace.stats.channel
+            else:
+                edge_channel = c
+            value_dict['channel'] = edge_channel
             if 'location' in stats:
-                value_dict['metadata']['location'] = stats.location
+                value_dict['location'] = stats.location
             # TODO: Add flag metadata
             values += [value_dict]
-            data = []
-            for i in range(len(trace.data)):
-                if numpy.isnan(trace.data[i]):
-                    data += ['null']
-                else:
-                    data += [str(trace.data[i])]
-
-
-            value_dict['values'] = data
-        self.dictionary['values'] += values
-
-    def _pad_to_four_channels(self, timeseries, channels):
-        padded = channels[:]
-        for x in range(len(channels), 4):
-            channel = 'NUL'
-            padded.append(channel)
-            timeseries += create_empty_trace(timeseries[0], channel)
-        return padded
+            data = np.copy(trace.data)
+            data[np.isnan(data)] = None
+            value_dict['values'] = data.tolist()
+        return values
 
     @classmethod
     def format(self, timeseries, channels, **kwargs):