Skip to content

Instantly share code, notes, and snippets.

@benbovy
Created March 20, 2014 14:46
Show Gist options
  • Save benbovy/9665418 to your computer and use it in GitHub Desktop.
Save benbovy/9665418 to your computer and use it in GitHub Desktop.
pyHEMCO examples
Display the source blob
Display the rendered blob
Raw
{
"metadata": {
"name": ""
},
"nbformat": 3,
"nbformat_minor": 0,
"worksheets": [
{
"cells": [
{
"cell_type": "heading",
"level": 1,
"metadata": {},
"source": [
"pyHEMCO (Python API for GEOS-Chem's HEMCO): usage examples"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"First, import the `pyhemco.emissions` Python module. The commands below allow to import the package without installing it."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"import sys\n",
"sys.path.extend('/home/bovy/MyGitRepos/pyHEMCO') # replace with your path/to/pyHEMCO_git_repo\n",
"\n",
"from pyhemco import emissions"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 1
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"HEMCO Input file\n",
"----------------\n",
"\n",
"For all examples shown in this notebook, the following HEMCO input file is taken as a reference."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"input_content=!cat HEMCO_input_sample.txt\n",
"from IPython.display import HTML\n",
"HTML('<pre style=\"font-size:80%;\">' + '<br>'.join(input_content) + '</pre>')"
],
"language": "python",
"metadata": {},
"outputs": [
{
"html": [
"<pre style=\"font-size:80%;\">### HEMCO INPUT FILE ###<br>#<br># ==================================================================================================<br># This file contains source file information of all emission fields used by the Harvard emissions <br># component (HEMCO). <br># Base emissions, scale factors and masks are listed in three separate sections. HEMCO settings and <br># extensions are defined/activated at the end of the input file.<br>#<br># Required for all fields: <br># - Name: Descriptive field name.<br># - sourceFile: (netCDF) file name (incl. full path)<br># - sourceVar: file variable of interest<br># - sourceTime: time stamp of interest. Format is YYYY/MM/DD/HH. Ranges are allowed for temporally <br># changing data, e.g. 1990-2005/1/1/0 or 2002/1-12/1/0, in which case the time slices <br># closest to the simulation date is read and used (data will be updated automatically). <br># Use wildcard character (*) to read all time slices at once, e.g. 1990/1/1/*. This is <br># only recommended for quickly varying data, e.g. hourly data.<br># - srcDim: dimension of data: xy or xyz. This is mainly for compatibility with ESMF.<br># - srcUnit: unit of data. This is mainly for compatibility with ESMF.<br>#<br># Additional fields required for base emissions:<br># - ExtNr: Extension number. Must match the extension number set in the extensions toggle section. <br># Use 0 for data to be used by HEMCO core.<br># - Species: Model name of emitted species. Emissions will only be calculated if Species matches one <br># of the model species names defined during initialization of HEMCO.<br># - ScalIDs: Scale factor IDs to be applied to the base field. Must match one of the ScalID entries <br># given in the scale factor/mask section. Separate multiple scale factors by forwardslash <br># (/). Use dash (-) if none.<br># - Cat: Emission category. Fields of the same category will be assembled based upon hierarchies. <br># - Hier: Emission hierarchy. Higher hierarchy emissions will overwrite lower hierarchy emissions <br># (if same category).<br>#<br># Additional fields required for scale factors:<br># - ScalID: Scale factor ID. To identify scale factor IDs assigend to base emissions<br># - Oper: Mathematical operator.<br># 1: Multiply, i.e. E = B * S.<br># 2: Square, i.e. E = B * S^2.<br># -1: Divide, i.e. E = B * (1/S). Zeros will be ignored.<br># 3: Mirror, i.e. E = B * (1-S). Only applies to mask fields.<br># - Scalar: Instead of using gridded scale data from a (netCDF) file, a scalar value can be defined. <br># This value will be uniformly applied to each grid box (e.g. to divide lumped VOC <br># emissions into individual species). Leave all file information blank (-) if scalar value <br># shall be used. Scalars can be uniform in time (one entry), hourly scale factors (24 <br># entries, separated by forward slash), day-of-week factor (7 entries), or monthly scale <br># factors (12 entries).<br>#<br># Additional fields required for masks:<br># - Lon1/Lat1/Lon2/Lat2: Mask window. Give the approximate window of the mask field. Only used to <br># determine whether or not a field is important for a given CPU. Lon1/Lat1 <br># denote the lower left corner, Lon2/Lat2 is the upper right corner.<br>#<br># Settings:<br># - Verbose: Set to true to run HEMCO in verbose mode.<br>#<br># Extensions switches:<br># This section steers which extensions shall be used and the files associated with them.<br># - ExtName: extension name<br># - on/off: Set to on to activate extension<br># - ExtNr: Extensions number. Determines the base emission fields accessible within an extension<br># (and only in this extension!). Note that ExtNr 0 is reserved for HEMCO core!<br># ==================================================================================================<br><br>####################################################################################<br>### BASE EMISSIONS <br>####################################################################################<br><br># ExtNr\tName sourceFile\tsourceVar sourceTime SrcDim SrcUnit Species ScalIDs Cat Hier<br><br># --- GEIA ---<br>0 GEIA_NO /path/to/emis/GEIA/nc/GEIA_NOSO4.fullyear.geos.4x5.nc NO 1985/1-12/1/0 xy kg/m2/s NO 1/2/20/25 1 1<br><br># --- Bromocarbon emissions ---<br>0 LIANG_CHBR3 /path/to/data/emis/BROMINE/Bromocarb_Liang2010.nc CHBr3_emission 2000/1/1/0 xy kg/m2/s CHBr3 38 1 1<br>0 LIANG_CH2BR2 /path/to/data/emis/BROMINE/Bromocarb_Liang2010.nc CH2Br2_emission 2000/1/1/0 xy kg/m2/s CH2Br2 38 1 1<br><br># --- Seawater concentrations for oceanic emissions (Extension 101) ---<br>101 ACET_SEAWATER /path/to/data/emis/ACET/nc/ACET_seawater.generic.1x1.nc ACET 2005/1/1/0 xy ngL ACET - 1 1<br>101 DMS_SEAWATER /path/to/data/emis/DMS/nc/DMS_seawater.geos.4x5.nc DMS 1985/1-12/1/0 xy ngL DMS - 1 1<br>101 CH3I_SEAWATER /path/to/data/emis/CH3I/nc/ocean_ch3i.geos.4x5.nc CH3I 1985/1-12/1/0 xy ngL CH3I - 1 1<br><br># --- PARANOX emissions (Extension 102) ---<br># Ship NO emissions will be assembled from all inventories listed below based upon <br># the assigned hierarchies.<br>102 ICOADS_SHIP_NO /path/to/data/emis/ICOADS_SHIP/nc/ICOADS_ship.geos.1x1.nc NO 2002/1-12/1/0 xy kg/m2/s NO 1/3 1 1<br>102 EDGAR_SHIP_NO /path/to/data/emis/EDGAR/nc/EDGAR.NO.generic.1x1.nc NO.f5800 2000/1/1/0 xy kg/m2/s NO 1 1 2<br>102 EMEP_SHIP_NO /path/to/data/emis/EMEP/nc/EMEP.updt.ship.geos.1x1.nc NO 1990-2007/1/1/0 xy kg/m2/s NO 1000 1 10<br><br>#<br># END OF BASE EMISSIONS <br><br>####################################################################################<br>### SCALE FACTORS <br>####################################################################################<br><br># ScalID Name sourceFile sourceVar sourceTime SrcDim SrcUnit Oper Scalar<br><br># --- annual scale factors ---<br>1 TOTFUEL_THISYR /path/to/data/emis/AnnualScalar/nc/NOx-AnnualScalar.geos.1x1.nc NOXscalar 1985-2008/1/1/0 xy unitless 1 -<br>2 TOTFUEL_1985 /path/to/data/emis/AnnualScalar/nc/NOx-AnnualScalar.geos.1x1.nc NOXscalar 1985/1/1/0 xy unitless -1 -<br>3 TOTFUEL_2002 /path/to/data/emis/AnnualScalar/nc/NOx-AnnualScalar.geos.1x1.nc NOXscalar 2002/1/1/0 xy unitless -1 -<br><br># --- day-of-week scale factors --- <br>20 GEIA_DOW_NOX - - - xy unitless 1 1.0706/1.0706/1.0706/1.0706/1.0706/0.863/0.784 <br><br># --- diurnal scale factors --- <br>25 EDGAR_TODNOX /path/to/data/emis/EDGAR/nc/dailyScal.nc NOXscale 2000/1/1/1-24 xy unitless 1 -<br><br># Seasonal scale factors for bromocarbons:<br>38 BROMOCARB_SEASON /path/to/data/emis/BROMINE/BromoCarb_Season.nc CHXBRY_scale 2000/1-12/1/0 xy unitless 1 -<br><br>####################################################################################<br>### MASKS <br>####################################################################################<br>#<br># ScalID Name sourceFile sourceVar sourceTime SrcDim SrcUnit Oper Lon1/Lat1/Lon2/Lat2<br>1000 EMEP_MASK /path/to/data/emis/MASKS/nc/EMEP_mask.geos.1x1.nc MASK */*/*/* xy xxx 1 -30/30/45//70<br><br>#<br># END OF MASKS <br><br>####################################################################################<br>### SETTINGS<br>####################################################################################<br>#<br>Verbose: false<br>#<br># END OF SETTINGS <br><br>####################################################################################<br>### EXTENSIONS SWITCHES<br>####################################################################################<br># For extensions using gridded data organized by HEMCO, make sure that these files <br># are listed in the base emissions section and match the ExtNr of the respective <br># extension!<br>#<br># ExtName on/off ExtNr<br>SeaFlux off 101<br>PARANOX off 102<br>LightNOx off 103<br>SoilNOx off 104<br><br>### END OF HEMCO INPUT FILE ###</pre>"
],
"metadata": {},
"output_type": "pyout",
"prompt_number": 2,
"text": [
"<IPython.core.display.HTML at 0x2482810>"
]
}
],
"prompt_number": 2
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Creating a new emission setup \"from scratch\"\n",
"--------------------------------------------\n",
"\n",
"Steps required for creating a new emission setup using pyhemco are detailed below.\n",
"\n",
"- Base emission fields, scale factors and masks are all GEOS-Chem data fields to which we add some specific metadata. It can be created from any existing `GCField` object. In this example, we first create new `GCField` objects for fields that will be included in the emission setup (a GEOS-Chem Python API currently in development will provide high-level functions for reading NetCDF files and importing the NetCDF variables as `GCField` objects). "
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"noxscalar = emissions.GCField('NOXScalar',\n",
" var_name='NOXScalar',\n",
" filename='/path/to/data/emis/AnnualScalar/nc/NOx-AnnualScalar.geos.1x1.nc',\n",
" ndim=2,\n",
" unit='unitless')\n",
"\n",
"geia_dow_nox = emissions.GCField('GEIA_DOW_NOX',\n",
" ndim=1, # does all scalar-based scale factors have 'xy' dims in HEMCO input file ?\n",
" unit='unitless',\n",
" data=[1.0706, 1.0706, 1.0706, 1.0706, 1.0706, 0.863, 0.784])\n",
"\n",
"emep_mask = emissions.GCField('EMEP_MASK',\n",
" var_name='MASK',\n",
" filename='/path/to/data/emis/MASKS/nc/EMEP_mask.geos.1x1.nc',\n",
" ndim=2,\n",
" unit='xxx')\n",
"\n",
"geia_no = emissions.GCField('GIEA_NO',\n",
" var_name='NO',\n",
" filename='/path/to/emis/GEIA/nc/GEIA_NOSO4.fullyear.geos.4x5.nc',\n",
" ndim=2,\n",
" unit='kg/m2/s')\n",
"\n",
"emep_ship_no = emissions.GCField('EMEP_SHIP_NO',\n",
" var_name='NO',\n",
" filename='/path/to/data/emis/EMEP/nc/EMEP.updt.ship.geos.1x1.nc',\n",
" ndim=2,\n",
" unit='kg/m2/s')"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 3
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"- Datafields that will be used by the HEMCO core and its extensions are created using the `base_emission_field`, `scale_factor` and `mask` functions, which basically add the metadata required by HEMCO to `GCField` objects.\n",
"\n",
" Scale factors and masks IDs (`fid`) can be left undefined, although it must be set when saving the emission setup to a file. Note that mask fields are specific scale factor fields and therefore have some common metadata attributes.\n",
" \n",
" Scale factors and masks can be assigned to a base emission field with the `scale_factor` argument of the `base_emission_field` function. \n",
" \n",
" Emission metadata can be added to a `GCField` in place (`copy=False`, default) or to a copy of this `GCField` (`copy=True`). The latter option may be useful, for example, when we need to create multiple scale factors or masks from one `GCField`. "
]
},
{
"cell_type": "code",
"collapsed": true,
"input": [
"# copy GCField and add metadata\n",
"totfuel_thisyr = emissions.scale_factor(noxscalar, 'TOTFUEL_THISYR', '1985-2008/1/1/0', operator='*',\n",
" fid=1, copy=True)\n",
"totfuel_1985 = emissions.scale_factor(noxscalar, 'TOTFUEL_1985', '1985/1/1/0', operator='/',\n",
" fid=2, copy=True)\n",
"totfuel_2002 = emissions.scale_factor(noxscalar, 'TOTFUEL_2002', '2002/1/1/0', operator='/',\n",
" fid=3, copy=True)\n",
"\n",
"# add metadata in place\n",
"emissions.scale_factor(geia_dow_nox, geia_dow_nox.name, '*/*/*/*', operator='*', fid=None) # fid will be set later\n",
"\n",
"emissions.mask(emep_mask, emep_mask.name, '*/*/*/*', mask_window=[-30, 30, 45, 70], fid=1000)\n",
"\n",
"emissions.base_emission_field(geia_no, geia_no.name, '1985/1-12/1/0', 'NO', 1, 1,\n",
" scale_factors=[totfuel_thisyr, totfuel_1985, geia_dow_nox])\n",
"emissions.base_emission_field(emep_ship_no, emep_ship_no.name, '1990-2007/1/1/0', 'NO', 1, 10,\n",
" scale_factors=[emep_mask])\n"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 4
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"- Creation of a new `EmissionExt` object for each HEMCO extension to include in the setup (must be done at least for HEMCO Core!). Currently, the `EmissionExt` class only stores basic information about the extension (extension name, on/off switch, extension number). Base emissions fields can eventually be attached to an extension. Similar to scale factors, User can optionally give a value for `eid` (i.e., the extension number) or leave it undefined (`None`, default), though it is higly recommended to define a value. When settings are written to a file, a `eid` value must be defined for each extension (it can be done automatically, see below). Note that HEMCO Core must have `eid` set to 0 ! "
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"core_ext = emissions.EmissionExt('HEMCOCore', eid=0, base_emission_fields=[geia_no]) \n",
"seaflux_ext = emissions.EmissionExt('SeaFlux', enabled=False, eid=101)\n",
"paranox_ext = emissions.EmissionExt('PARANOX', enabled=False, eid=102, base_emission_fields=[emep_ship_no])\n",
"lightnox_ext = emissions.EmissionExt('LightNOx', enabled=True, eid=103)\n",
"soilnox_ext = emissions.EmissionExt('SoilNOx', enabled=True, eid=None) # eid will be set later."
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 5
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"- Creating a new emission setup only requires providing the extensions (each extensions has reference to base emission fields and each emission field has references to scale factors and masks). Additional emission settings can be given with the `extra_settings` keyword argument. It is also possible to define an empty setup and add extensions later (see section 'Editing an existing emission setup' below). "
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"example_setup = emissions.Emissions([core_ext, seaflux_ext, paranox_ext, lightnox_ext, soilnox_ext],\n",
" description='An emission setup example (not complete)',\n",
" extra_settings={'Verbose': False})\n",
"\n",
"empty_setup = emissions.Emissions([], description='An empty setup')"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 6
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Accessing emission setup data\n",
"-----------------------------\n",
"\n",
"It is easy to access to any emission setting, either directly or through filtering. Iterating over settings is also straightforward. A few basic examples are given below.\n",
"\n",
"*Get all base emission fields (returns a collection of `GCField` objects, see class `pyhemco.datatypes.ObjectCollection`):*"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"example_setup.base_emission_fields"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 7,
"text": [
"<ObjectCollection: [<GCField: GIEA_NO>, <GCField: EMEP_SHIP_NO>]>"
]
}
],
"prompt_number": 7
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"*Get all scale factors and masks that are assigned to base emission fields (read-only collection of `GCField` objects):*"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"example_setup.scale_factors"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 8,
"text": [
"<ObjectCollection: [<GCField: EMEP_MASK>, <GCField: TOTFUEL_THISYR>, <GCField: TOTFUEL_1985>, <GCField: GEIA_DOW_NOX>]>"
]
}
],
"prompt_number": 8
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"*Get all HEMCO extensions involved in the setup (read-only collection of `EmissionExt` objects):*"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"example_setup.extensions"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 9,
"text": [
"<ObjectCollection: [<EmissionExt: HEMCOCore (0)>, <EmissionExt: SeaFlux (101)>, <EmissionExt: PARANOX (102)>, <EmissionExt: LightNOx (103)>, <EmissionExt: SoilNOx (None)>]>"
]
}
],
"prompt_number": 9
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"*Get the 'GIEA_NO' base emission field*"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"giea_no = example_setup.base_emission_fields.get_object(name='GIEA_NO')\n",
"giea_no"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 10,
"text": [
"<GCField: GIEA_NO>"
]
}
],
"prompt_number": 10
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"*Base emission field metadata is stored as a dictionary in the 'emission_base' attribute of `GCField`:*"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"giea_no.attributes['emission_base']"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 11,
"text": [
"{'category': 1,\n",
" 'hierarchy': 1,\n",
" 'name': 'GIEA_NO',\n",
" 'scale_factors': <ObjectCollection: [<GCField: TOTFUEL_THISYR>, <GCField: TOTFUEL_1985>, <GCField: GEIA_DOW_NOX>]>,\n",
" 'species': 'NO',\n",
" 'timestamp': '1985/1-12/1/0'}"
]
}
],
"prompt_number": 11
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"*Similarly, for scale factors and masks ('emission_scale_factor' attribute):*"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"totfuel_thisyr = giea_no.emission_scale_factors.get_object(name='TOTFUEL_THISYR')\n",
"totfuel_thisyr.attributes['emission_scale_factor']"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 12,
"text": [
"{'fid': 1,\n",
" 'name': 'TOTFUEL_THISYR',\n",
" 'operator': '*',\n",
" 'timestamp': '1985-2008/1/1/0'}"
]
}
],
"prompt_number": 12
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"*Get all base emission fields that will be used by the 'PARANOX' extension:*"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"paranox_ext = example_setup.extensions.get_object(name='PARANOX')\n",
"paranox_fields = paranox_ext.base_emission_fields\n",
"paranox_fields"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 13,
"text": [
"<ObjectCollection: [<GCField: EMEP_SHIP_NO>]>"
]
}
],
"prompt_number": 13
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"*Get all masks:*"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"filter_masks = lambda field: 'mask_window' in field.attributes['emission_scale_factor'].keys()\n",
"masks = example_setup.scale_factors.filter(filter_masks)\n",
"masks"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 14,
"text": [
"<ObjectCollection (selection): [<GCField: EMEP_MASK>]>"
]
}
],
"prompt_number": 14
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"*Which extension will use the 'GIEA_NO' base emission field?*"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"example_setup.extensions.get_object(lambda ext: giea_no in ext.base_emission_fields)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 15,
"text": [
"<EmissionExt: HEMCOCore (0)>"
]
}
],
"prompt_number": 15
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"There is more filtering / sorting possibilities, see docstring of class `pyhemco.datatypes.ObjectCollection`."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Editing an existing emission setup\n",
"----------------------------------\n",
"\n",
"Adding / removing emission fields or changing the value of any setting in a setup is as easy as accessing the setup data. Some examples below.\n",
"\n",
"*Add a new base emission field:*"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"acet_seawater = emissions.GCField('ACET_SEAWATER',\n",
" var_name='ACET',\n",
" filename='/path/to/data/emis/ACET/nc/ACET_seawater.generic.1x1.nc',\n",
" ndim=2,\n",
" unit='ngL')\n",
"emissions.base_emission_field(acet_seawater, acet_seawater.name, '2005/1/1/0', 'ACET', 1, 1,\n",
" extension=seaflux_ext)\n",
"seaflux_ext = example_setup.extensions.get_object(name='SeaFlux')\n",
"seaflux_ext.base_emission_fields.add(acet_seawater)\n",
"seaflux_ext.base_emission_fields"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 16,
"text": [
"<ObjectCollection: [<GCField: ACET_SEAWATER>]>"
]
}
],
"prompt_number": 16
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"# base emission fields are automatically updated:\n",
"example_setup.base_emission_fields"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 17,
"text": [
"<ObjectCollection: [<GCField: GIEA_NO>, <GCField: ACET_SEAWATER>, <GCField: EMEP_SHIP_NO>]>"
]
}
],
"prompt_number": 17
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"*Create and assign a new scale factor to the 'GEIA_NO' base emission field:*"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"edgar_todnox = emissions.GCField('EDGAR_TODNOX',\n",
" var_name='NOXscale',\n",
" filename='/path/to/data/emis/EDGAR/nc/dailyScal.nc',\n",
" ndim=2,\n",
" unit='unitless')\n",
"emissions.scale_factor(edgar_todnox, edgar_todnox.name, '2000/1/1/1-24', operator='*', fid=25)\n",
"\n",
"giea_no = example_setup.base_emission_fields.get_object(name='GIEA_NO')\n",
"giea_no.emission_scale_factors.add(edgar_todnox)\n",
"giea_no.emission_scale_factors"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 18,
"text": [
"<ObjectCollection: [<GCField: TOTFUEL_THISYR>, <GCField: TOTFUEL_1985>, <GCField: GEIA_DOW_NOX>, <GCField: EDGAR_TODNOX>]>"
]
}
],
"prompt_number": 18
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"# scale factors listed in setup are automatically updated:\n",
"example_setup.scale_factors"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 19,
"text": [
"<ObjectCollection: [<GCField: EDGAR_TODNOX>, <GCField: TOTFUEL_THISYR>, <GCField: EMEP_MASK>, <GCField: TOTFUEL_1985>, <GCField: GEIA_DOW_NOX>]>"
]
}
],
"prompt_number": 19
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"*Remove the mask assigned to the 'EMEP_SHIP_NO' base emission field:*"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"emep_ship_no = example_setup.base_emission_fields.get_object(name='EMEP_SHIP_NO')\n",
"emep_ship_no.emission_scale_factors.get(name='EMEP_MASK').remove()\n",
"emep_ship_no.emission_scale_factors"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 20,
"text": [
"<ObjectCollection: []>"
]
}
],
"prompt_number": 20
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"example_setup.scale_factors"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 21,
"text": [
"<ObjectCollection: [<GCField: EDGAR_TODNOX>, <GCField: TOTFUEL_THISYR>, <GCField: TOTFUEL_1985>, <GCField: GEIA_DOW_NOX>]>"
]
}
],
"prompt_number": 21
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"*Remove all base emission fields attached to the 'PARANOX' HEMCO extension:*"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"paranox_ext = example_setup.extensions.get_object(name='PARANOX')\n",
"paranox_ext.base_emission_fields.get_all().remove()\n",
"example_setup.base_emission_fields"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 22,
"text": [
"<ObjectCollection: [<GCField: GIEA_NO>, <GCField: ACET_SEAWATER>]>"
]
}
],
"prompt_number": 22
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"*Change the ID (`fid`) of the 'EDGAR_TODNOX' scale factor:*"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"edgar_todnox = example_setup.scale_factors.get_object(name='EDGAR_TODNOX')\n",
"edgar_todnox.attributes['emission_scale_factor']['fid'] = 26\n",
"edgar_todnox.attributes"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 23,
"text": [
"{'emission_scale_factor': {'fid': 26,\n",
" 'name': 'EDGAR_TODNOX',\n",
" 'operator': '*',\n",
" 'timestamp': '2000/1/1/1-24'}}"
]
}
],
"prompt_number": 23
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"giea_no.emission_scale_factors.get_object(name='EDGAR_TODNOX').attributes"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 24,
"text": [
"{'emission_scale_factor': {'fid': 26,\n",
" 'name': 'EDGAR_TODNOX',\n",
" 'operator': '*',\n",
" 'timestamp': '2000/1/1/1-24'}}"
]
}
],
"prompt_number": 24
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Writing an emission setup to a text file\n",
"----------------------------------------\n",
"\n",
"(Not yet implemented)\n",
"\n",
"Writing a setup to a file requires consistent IDs for HEMCO extensions, scale factors and masks. The `Emission` class provides two methods for that:\n",
"\n",
"- `check_id` checks for missing or duplicate IDs"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"# should raise an error because we left some IDs undefined above\n",
"example_setup.check_id()"
],
"language": "python",
"metadata": {},
"outputs": [
{
"ename": "ValueError",
"evalue": "Missing or duplicate scale factor fid",
"output_type": "pyerr",
"traceback": [
"\u001b[1;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[1;31mValueError\u001b[0m Traceback (most recent call last)",
"\u001b[1;32m<ipython-input-25-e6fa640c767e>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m()\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[1;31m# should raise an error because we left some IDs undefined above\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 2\u001b[1;33m \u001b[0mexample_setup\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mcheck_id\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[1;32m/home/bovy/MyGitRepos/pyHEMCO/pyhemco/emissions.py\u001b[0m in \u001b[0;36mcheck_id\u001b[1;34m(self)\u001b[0m\n\u001b[0;32m 452\u001b[0m \u001b[1;32mif\u001b[0m \u001b[0mNone\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mfids\u001b[0m \u001b[1;32mor\u001b[0m \u001b[0mlen\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mset\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mfids\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;33m!=\u001b[0m \u001b[0mlen\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mfids\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 453\u001b[0m \u001b[1;31m# TODO: raise custom exception\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 454\u001b[1;33m \u001b[1;32mraise\u001b[0m \u001b[0mValueError\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m\"Missing or duplicate scale factor fid\"\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 455\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 456\u001b[0m \u001b[0meids\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;33m[\u001b[0m\u001b[0mext\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0meid\u001b[0m \u001b[1;32mfor\u001b[0m \u001b[0mext\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mextensions\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
"\u001b[1;31mValueError\u001b[0m: Missing or duplicate scale factor fid"
]
}
],
"prompt_number": 25
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"- `resolve_id` allows to set automatically new values for missing or duplicate IDs "
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"geia_dow_nox = example_setup.scale_factors.get_object(name='GEIA_DOW_NOX')\n",
"geia_dow_nox.attributes['emission_scale_factor']['fid'] is None # there is a missing ID here (should return True)"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 26,
"text": [
"True"
]
}
],
"prompt_number": 26
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"example_setup.resolve_id()\n",
"example_setup.check_id() # should not raise any error anymore\n",
"geia_dow_nox.attributes['emission_scale_factor']['fid'] # should return a valid ID"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 27,
"text": [
"3"
]
}
],
"prompt_number": 27
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Reading an emission setup from a text file\n",
"------------------------------------------\n",
"\n",
"(Not yet implemented)\n",
"\n",
"Should implement the steps described in the section 'Creating a new emission setup from scratch'."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Visualizing the emission setup as a Tree (using networkx)\n",
"---------------------------------------------------------"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"%pylab inline\n",
"pylab.rcParams['figure.figsize'] = (10.0, 8.0)\n",
"import networkx as nx\n",
"from networkx.readwrite import json_graph\n",
"import matplotlib.pyplot as plt\n",
"import json"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"Populating the interactive namespace from numpy and matplotlib\n"
]
}
],
"prompt_number": 28
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Building the graph from emission setup**"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"G = nx.DiGraph()\n",
"\n",
"G.add_node(\"SETUP\")\n",
"\n",
"for ext in example_setup.extensions.sorted(lambda ext: ext.eid):\n",
" ext_node_label = \"{} ({})\".format(ext.name, ext.eid)\n",
" G.add_node(ext_node_label)\n",
" G.add_edge(\"SETUP\", ext_node_label)\n",
" \n",
" for bef in ext.base_emission_fields:\n",
" G.add_node(bef.name)\n",
" G.add_edge(ext_node_label, bef.name)\n",
" \n",
" for sf in bef.emission_scale_factors:\n",
" # TODO: handle the case where a scale factor is assigned to\n",
" # several base emission fields (only one node?)\n",
" sf_fid = sf.attributes['emission_scale_factor']['fid']\n",
" sf_node_label = \"{} ({})\".format(sf.name, sf_fid)\n",
" G.add_node(sf_node_label)\n",
" G.add_edge(bef.name, sf_node_label)"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 29
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Visualization using matplotlib**\n",
"\n",
"Requires:\n",
"\n",
"- matplotlib\n",
"- graphviz\n",
"- pygraphviz"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"plt.title(example_setup.description)\n",
"glayout = nx.pygraphviz_layout(G, prog=\"dot\")\n",
"nx.draw(G, glayout, with_labels=True, arrows=False) # default parameters, output not very pretty\n",
"plt.show()"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "display_data",
"png": "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\nk5Pj/EruD4/Ho6K5c7UtLk7FkmYpELb8kvZKKpQ0VV8GgGBNBklqlbRL0vyoKA1JT9fs2bPDLmPh\nwoV64YUXQk4fLVy4UH/4wx+0YMEC+Xw+NTU1qaysTC+++KKWLVsmSfrlL3+p2267TTfeeKOGDBmi\n5cuX6xe/+IXa2trCLmf69Ol69913lZSUpIULF6q4uFjjx4/X+PHjtWTJEv3xj3/UmTNnnPEvueQS\n1dXV6e2335bf79fKlSs1ePBgjRw5MvBejdFHH32kUaNGqbKyUm+++aazTaqrq1VaWtqvHke/36/P\nPvtMv/rVr/Tee+8510jl5eVpypQpKiws1Mcffyy/36/xP/yhKvx+zZF0Wbd5TJT0rEJ7uCZ0DRsn\nKbZr2AaXS/8ybVqf18hJ0mWXXaaZM2dq1apVzrDLL79cxcXFmjVrlqqqquT3+7V3714VFhZq6tSp\nys3NVXV1tcrKyrRu3TpJgYu6P//8c23YsCHscjwej4YOHaqqqipn2MiRI/X+++9rwYIF+uCDD7R0\n6VJddNFFzj5QV1en48eP69prrw07z6BwX6xRUVEqLCzU/Pnzdfz4cbW3t+vll1/W/v37NW3atIjz\nysnJ0TVXX61gJGyT1NLt4e9zTaQ6Sa93diohIUGtra1qaWlxXjt06JD++te/yu/366233tK6deu0\nYMECZ7ltbW16+eWX1dnZqcOHD+uVV15xvnC3b9+umpoaGWNUW1ur0tJSFRQURFyP4LEgBY61HTt2\naPTo0br77rv1k5/8pNexJgWu2Zw0aVLEeX6T7dxTW1ubWlpa1NLSon+9/Xa97fer7qsnC+uMpIxh\nwzRq1KhzGn/lypV699131dzcrI6ODm3cuFGnT5/WmDFjvnLanm1y+eWX65ZbbtGKFSvCjj9u3Did\nOHEipNe/s7NTLS0tam9vV2dnp1pbW0N6Enfu3Kns7GxlZWWd0/sBLkhW7qnsQ1tbm3n88cfNiBEj\njNfrNZmZmWb69OnOrcw33XSTeeCBB3pNV1FRYdLT001HR0fIbdxBr7zyihk6dGhI3aVIupeaMMaY\nhoYGkxQXZ+ols0wyOV01dLIkU6rQOl936cs6XwO6bsdPHjDA+Hy+iPM3JlCrxu12h9x+/+c//9nc\nfPPNJjEx0QwYMMBMnjzZ7NixwxhjzNatW01GRoY5efJkyHxyc3Od+kHh2nbYsGFOna+ioiKnfpfL\n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\nAdAITHsRIfokAAAAAElFTkSuQmCC\n",
"text": [
"<matplotlib.figure.Figure at 0x357c950>"
]
}
],
"prompt_number": 30
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Visualization using d3.js**"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"# serialize graph into d3 tree format and write to a json file\n",
"setup_dict = json_graph.tree_data(G, \"SETUP\")\n",
"json.dump(setup_dict, open('setup_example.json', 'w'))"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 32
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"%%html\n",
"<div id=\"tree-container\"></div>\n",
"\n",
"<style>\n",
"\n",
".node circle {\n",
" fill: #fff;\n",
" stroke: steelblue;\n",
" stroke-width: 1.5px;\n",
"}\n",
"\n",
".node {\n",
" font: 10px sans-serif;\n",
"}\n",
"\n",
".link {\n",
" fill: none;\n",
" stroke: #ccc;\n",
" stroke-width: 1.5px;\n",
"}\n",
"</style>"
],
"language": "python",
"metadata": {},
"outputs": [
{
"html": [
"<div id=\"tree-container\"></div>\n",
"\n",
"<style>\n",
"\n",
".node circle {\n",
" fill: #fff;\n",
" stroke: steelblue;\n",
" stroke-width: 1.5px;\n",
"}\n",
"\n",
".node {\n",
" font: 10px sans-serif;\n",
"}\n",
"\n",
".link {\n",
" fill: none;\n",
" stroke: #ccc;\n",
" stroke-width: 1.5px;\n",
"}\n",
"</style>"
],
"metadata": {},
"output_type": "display_data",
"text": [
"<IPython.core.display.HTML at 0x3595190>"
]
}
],
"prompt_number": 33
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"%%javascript\n",
"\n",
"require.config({paths: {d3: \"http://d3js.org/d3.v3.min\",\n",
" jquery: \"http://code.jquery.com/jquery-1.10.2.min.js\"}\n",
" });\n",
"\n",
"require([\"d3\", \"jquery\"], function(d3) {\n",
" \n",
" var width = 500,\n",
" height = 400;\n",
" \n",
" var tree = d3.layout.tree()\n",
" .size([height, width - 160]);\n",
" \n",
" var diagonal = d3.svg.diagonal()\n",
" .projection(function(d) { return [d.y, d.x]; });\n",
" \n",
" var svg = d3.select(\"#tree-container\").append(\"svg\")\n",
" .attr(\"width\", width)\n",
" .attr(\"height\", height)\n",
" .append(\"g\")\n",
" .attr(\"transform\", \"translate(40,0)\");\n",
" \n",
" d3.json(\"files/setup_example.json\", function(error, root) {\n",
" var nodes = tree.nodes(root),\n",
" links = tree.links(nodes);\n",
" \n",
" var link = svg.selectAll(\".link\")\n",
" .data(links)\n",
" .enter().append(\"path\")\n",
" .attr(\"class\", \"link\")\n",
" .attr(\"d\", diagonal);\n",
" \n",
" var node = svg.selectAll(\".node\")\n",
" .data(nodes)\n",
" .enter().append(\"g\")\n",
" .attr(\"class\", \"node\")\n",
" .attr(\"transform\", function(d) { return \"translate(\" + d.y + \",\" + d.x + \")\"; })\n",
" \n",
" node.append(\"circle\")\n",
" .attr(\"r\", 4.5);\n",
" \n",
" node.append(\"text\")\n",
" .attr(\"dx\", function(d) { return d.children ? -8 : 8; })\n",
" .attr(\"dy\", 3)\n",
" .style(\"text-anchor\", function(d) { return d.children ? \"end\" : \"start\"; })\n",
" .text(function(d) { return d.id; });\n",
" });\n",
" \n",
" d3.select(self.frameElement).style(\"height\", height + \"px\");\n",
"\n",
"});\n",
"\n"
],
"language": "python",
"metadata": {},
"outputs": [
{
"javascript": [
"\n",
"require.config({paths: {d3: \"http://d3js.org/d3.v3.min\",\n",
" jquery: \"http://code.jquery.com/jquery-1.10.2.min.js\"}\n",
" });\n",
"\n",
"require([\"d3\", \"jquery\"], function(d3) {\n",
" \n",
" var width = 500,\n",
" height = 400;\n",
" \n",
" var tree = d3.layout.tree()\n",
" .size([height, width - 160]);\n",
" \n",
" var diagonal = d3.svg.diagonal()\n",
" .projection(function(d) { return [d.y, d.x]; });\n",
" \n",
" var svg = d3.select(\"#tree-container\").append(\"svg\")\n",
" .attr(\"width\", width)\n",
" .attr(\"height\", height)\n",
" .append(\"g\")\n",
" .attr(\"transform\", \"translate(40,0)\");\n",
" \n",
" d3.json(\"files/setup_example.json\", function(error, root) {\n",
" var nodes = tree.nodes(root),\n",
" links = tree.links(nodes);\n",
" \n",
" var link = svg.selectAll(\".link\")\n",
" .data(links)\n",
" .enter().append(\"path\")\n",
" .attr(\"class\", \"link\")\n",
" .attr(\"d\", diagonal);\n",
" \n",
" var node = svg.selectAll(\".node\")\n",
" .data(nodes)\n",
" .enter().append(\"g\")\n",
" .attr(\"class\", \"node\")\n",
" .attr(\"transform\", function(d) { return \"translate(\" + d.y + \",\" + d.x + \")\"; })\n",
" \n",
" node.append(\"circle\")\n",
" .attr(\"r\", 4.5);\n",
" \n",
" node.append(\"text\")\n",
" .attr(\"dx\", function(d) { return d.children ? -8 : 8; })\n",
" .attr(\"dy\", 3)\n",
" .style(\"text-anchor\", function(d) { return d.children ? \"end\" : \"start\"; })\n",
" .text(function(d) { return d.id; });\n",
" });\n",
" \n",
" d3.select(self.frameElement).style(\"height\", height + \"px\");\n",
"\n",
"});\n"
],
"metadata": {},
"output_type": "display_data",
"text": [
"<IPython.core.display.Javascript at 0x3595110>"
]
}
],
"prompt_number": 34
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Visualization with d3.js (advanced)**\n",
"\n",
"Pan, Zoom, Collapse"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"%%html\n",
"<div id=\"tree-container2\"></div>\n",
"\n",
"<style>\n",
"\n",
".node rect {\n",
" cursor: pointer;\n",
" fill: #fff;\n",
" fill-opacity: .5;\n",
" stroke: #3182bd;\n",
" stroke-width: 1.5px;\n",
"}\n",
"\n",
".node text {\n",
" font: 10px sans-serif;\n",
" pointer-events: none;\n",
"}\n",
"\n",
"path.link {\n",
" fill: none;\n",
" stroke: #9ecae1;\n",
" stroke-width: 1.5px;\n",
"}\n",
"</style>"
],
"language": "python",
"metadata": {},
"outputs": [
{
"html": [
"<div id=\"tree-container2\"></div>\n",
"\n",
"<style>\n",
"\n",
".node rect {\n",
" cursor: pointer;\n",
" fill: #fff;\n",
" fill-opacity: .5;\n",
" stroke: #3182bd;\n",
" stroke-width: 1.5px;\n",
"}\n",
"\n",
".node text {\n",
" font: 10px sans-serif;\n",
" pointer-events: none;\n",
"}\n",
"\n",
"path.link {\n",
" fill: none;\n",
" stroke: #9ecae1;\n",
" stroke-width: 1.5px;\n",
"}\n",
"</style>"
],
"metadata": {},
"output_type": "display_data",
"text": [
"<IPython.core.display.HTML at 0x3595390>"
]
}
],
"prompt_number": 35
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"%%javascript\n",
"\n",
"require.config({paths: {d3: \"http://d3js.org/d3.v3.min\",\n",
" jquery: \"http://code.jquery.com/jquery-1.10.2.min.js\"}\n",
" });\n",
"\n",
"require([\"d3\", \"jquery\"], function(d3) {\n",
"\n",
" var margin = {top: 30, right: 20, bottom: 30, left: 20},\n",
" width = 500 - margin.left - margin.right,\n",
" barHeight = 20,\n",
" barWidth = width * .8;\n",
" \n",
" var i = 0,\n",
" duration = 400,\n",
" root;\n",
" \n",
" var tree = d3.layout.tree()\n",
" .nodeSize([0, 20]);\n",
" \n",
" var diagonal = d3.svg.diagonal()\n",
" .projection(function(d) { return [d.y, d.x]; });\n",
" \n",
" var svg = d3.select(\"#tree-container2\").append(\"svg\")\n",
" .attr(\"width\", width + margin.left + margin.right)\n",
" .append(\"g\")\n",
" .attr(\"transform\", \"translate(\" + margin.left + \",\" + margin.top + \")\");\n",
" \n",
" d3.json(\"files/setup_example.json\", function(error, flare) {\n",
" flare.x0 = 0;\n",
" flare.y0 = 0;\n",
" update(root = flare);\n",
" });\n",
" \n",
" function update(source) {\n",
" \n",
" // Compute the flattened node list. TODO use d3.layout.hierarchy.\n",
" var nodes = tree.nodes(root);\n",
" \n",
" var height = Math.max(500, nodes.length * barHeight + margin.top + margin.bottom);\n",
" \n",
" d3.select(\"svg\").transition()\n",
" .duration(duration)\n",
" .attr(\"height\", height);\n",
" \n",
" d3.select(self.frameElement).transition()\n",
" .duration(duration)\n",
" .style(\"height\", height + \"px\");\n",
" \n",
" // Compute the \"layout\".\n",
" nodes.forEach(function(n, i) {\n",
" n.x = i * barHeight;\n",
" });\n",
" \n",
" // Update the nodes\u2026\n",
" var node = svg.selectAll(\"g.node\")\n",
" .data(nodes, function(d) { return d.id || (d.id = ++i); });\n",
" \n",
" var nodeEnter = node.enter().append(\"g\")\n",
" .attr(\"class\", \"node\")\n",
" .attr(\"transform\", function(d) { return \"translate(\" + source.y0 + \",\" + source.x0 + \")\"; })\n",
" .style(\"opacity\", 1e-6);\n",
" \n",
" // Enter any new nodes at the parent's previous position.\n",
" nodeEnter.append(\"rect\")\n",
" .attr(\"y\", -barHeight / 2)\n",
" .attr(\"height\", barHeight)\n",
" .attr(\"width\", barWidth)\n",
" .style(\"fill\", color)\n",
" .on(\"click\", click);\n",
" \n",
" nodeEnter.append(\"text\")\n",
" .attr(\"dy\", 3.5)\n",
" .attr(\"dx\", 5.5)\n",
" .text(function(d) { return d.id; });\n",
" \n",
" // Transition nodes to their new position.\n",
" nodeEnter.transition()\n",
" .duration(duration)\n",
" .attr(\"transform\", function(d) { return \"translate(\" + d.y + \",\" + d.x + \")\"; })\n",
" .style(\"opacity\", 1);\n",
" \n",
" node.transition()\n",
" .duration(duration)\n",
" .attr(\"transform\", function(d) { return \"translate(\" + d.y + \",\" + d.x + \")\"; })\n",
" .style(\"opacity\", 1)\n",
" .select(\"rect\")\n",
" .style(\"fill\", color);\n",
" \n",
" // Transition exiting nodes to the parent's new position.\n",
" node.exit().transition()\n",
" .duration(duration)\n",
" .attr(\"transform\", function(d) { return \"translate(\" + source.y + \",\" + source.x + \")\"; })\n",
" .style(\"opacity\", 1e-6)\n",
" .remove();\n",
" \n",
" // Update the links\u2026\n",
" var link = svg.selectAll(\"path.link\")\n",
" .data(tree.links(nodes), function(d) { return d.target.id; });\n",
" \n",
" // Enter any new links at the parent's previous position.\n",
" link.enter().insert(\"path\", \"g\")\n",
" .attr(\"class\", \"link\")\n",
" .attr(\"d\", function(d) {\n",
" var o = {x: source.x0, y: source.y0};\n",
" return diagonal({source: o, target: o});\n",
" })\n",
" .transition()\n",
" .duration(duration)\n",
" .attr(\"d\", diagonal);\n",
" \n",
" // Transition links to their new position.\n",
" link.transition()\n",
" .duration(duration)\n",
" .attr(\"d\", diagonal);\n",
" \n",
" // Transition exiting nodes to the parent's new position.\n",
" link.exit().transition()\n",
" .duration(duration)\n",
" .attr(\"d\", function(d) {\n",
" var o = {x: source.x, y: source.y};\n",
" return diagonal({source: o, target: o});\n",
" })\n",
" .remove();\n",
" \n",
" // Stash the old positions for transition.\n",
" nodes.forEach(function(d) {\n",
" d.x0 = d.x;\n",
" d.y0 = d.y;\n",
" });\n",
" }\n",
" \n",
" // Toggle children on click.\n",
" function click(d) {\n",
" if (d.children) {\n",
" d._children = d.children;\n",
" d.children = null;\n",
" } else {\n",
" d.children = d._children;\n",
" d._children = null;\n",
" }\n",
" update(d);\n",
" }\n",
" \n",
" function color(d) {\n",
" return d._children ? \"#3182bd\" : d.children ? \"#c6dbef\" : \"#fd8d3c\";\n",
" }\n",
"\n",
"});"
],
"language": "python",
"metadata": {},
"outputs": [
{
"javascript": [
"\n",
"require.config({paths: {d3: \"http://d3js.org/d3.v3.min\",\n",
" jquery: \"http://code.jquery.com/jquery-1.10.2.min.js\"}\n",
" });\n",
"\n",
"require([\"d3\", \"jquery\"], function(d3) {\n",
"\n",
" var margin = {top: 30, right: 20, bottom: 30, left: 20},\n",
" width = 500 - margin.left - margin.right,\n",
" barHeight = 20,\n",
" barWidth = width * .8;\n",
" \n",
" var i = 0,\n",
" duration = 400,\n",
" root;\n",
" \n",
" var tree = d3.layout.tree()\n",
" .nodeSize([0, 20]);\n",
" \n",
" var diagonal = d3.svg.diagonal()\n",
" .projection(function(d) { return [d.y, d.x]; });\n",
" \n",
" var svg = d3.select(\"#tree-container2\").append(\"svg\")\n",
" .attr(\"width\", width + margin.left + margin.right)\n",
" .append(\"g\")\n",
" .attr(\"transform\", \"translate(\" + margin.left + \",\" + margin.top + \")\");\n",
" \n",
" d3.json(\"files/setup_example.json\", function(error, flare) {\n",
" flare.x0 = 0;\n",
" flare.y0 = 0;\n",
" update(root = flare);\n",
" });\n",
" \n",
" function update(source) {\n",
" \n",
" // Compute the flattened node list. TODO use d3.layout.hierarchy.\n",
" var nodes = tree.nodes(root);\n",
" \n",
" var height = Math.max(500, nodes.length * barHeight + margin.top + margin.bottom);\n",
" \n",
" d3.select(\"svg\").transition()\n",
" .duration(duration)\n",
" .attr(\"height\", height);\n",
" \n",
" d3.select(self.frameElement).transition()\n",
" .duration(duration)\n",
" .style(\"height\", height + \"px\");\n",
" \n",
" // Compute the \"layout\".\n",
" nodes.forEach(function(n, i) {\n",
" n.x = i * barHeight;\n",
" });\n",
" \n",
" // Update the nodes\u2026\n",
" var node = svg.selectAll(\"g.node\")\n",
" .data(nodes, function(d) { return d.id || (d.id = ++i); });\n",
" \n",
" var nodeEnter = node.enter().append(\"g\")\n",
" .attr(\"class\", \"node\")\n",
" .attr(\"transform\", function(d) { return \"translate(\" + source.y0 + \",\" + source.x0 + \")\"; })\n",
" .style(\"opacity\", 1e-6);\n",
" \n",
" // Enter any new nodes at the parent's previous position.\n",
" nodeEnter.append(\"rect\")\n",
" .attr(\"y\", -barHeight / 2)\n",
" .attr(\"height\", barHeight)\n",
" .attr(\"width\", barWidth)\n",
" .style(\"fill\", color)\n",
" .on(\"click\", click);\n",
" \n",
" nodeEnter.append(\"text\")\n",
" .attr(\"dy\", 3.5)\n",
" .attr(\"dx\", 5.5)\n",
" .text(function(d) { return d.id; });\n",
" \n",
" // Transition nodes to their new position.\n",
" nodeEnter.transition()\n",
" .duration(duration)\n",
" .attr(\"transform\", function(d) { return \"translate(\" + d.y + \",\" + d.x + \")\"; })\n",
" .style(\"opacity\", 1);\n",
" \n",
" node.transition()\n",
" .duration(duration)\n",
" .attr(\"transform\", function(d) { return \"translate(\" + d.y + \",\" + d.x + \")\"; })\n",
" .style(\"opacity\", 1)\n",
" .select(\"rect\")\n",
" .style(\"fill\", color);\n",
" \n",
" // Transition exiting nodes to the parent's new position.\n",
" node.exit().transition()\n",
" .duration(duration)\n",
" .attr(\"transform\", function(d) { return \"translate(\" + source.y + \",\" + source.x + \")\"; })\n",
" .style(\"opacity\", 1e-6)\n",
" .remove();\n",
" \n",
" // Update the links\u2026\n",
" var link = svg.selectAll(\"path.link\")\n",
" .data(tree.links(nodes), function(d) { return d.target.id; });\n",
" \n",
" // Enter any new links at the parent's previous position.\n",
" link.enter().insert(\"path\", \"g\")\n",
" .attr(\"class\", \"link\")\n",
" .attr(\"d\", function(d) {\n",
" var o = {x: source.x0, y: source.y0};\n",
" return diagonal({source: o, target: o});\n",
" })\n",
" .transition()\n",
" .duration(duration)\n",
" .attr(\"d\", diagonal);\n",
" \n",
" // Transition links to their new position.\n",
" link.transition()\n",
" .duration(duration)\n",
" .attr(\"d\", diagonal);\n",
" \n",
" // Transition exiting nodes to the parent's new position.\n",
" link.exit().transition()\n",
" .duration(duration)\n",
" .attr(\"d\", function(d) {\n",
" var o = {x: source.x, y: source.y};\n",
" return diagonal({source: o, target: o});\n",
" })\n",
" .remove();\n",
" \n",
" // Stash the old positions for transition.\n",
" nodes.forEach(function(d) {\n",
" d.x0 = d.x;\n",
" d.y0 = d.y;\n",
" });\n",
" }\n",
" \n",
" // Toggle children on click.\n",
" function click(d) {\n",
" if (d.children) {\n",
" d._children = d.children;\n",
" d.children = null;\n",
" } else {\n",
" d.children = d._children;\n",
" d._children = null;\n",
" }\n",
" update(d);\n",
" }\n",
" \n",
" function color(d) {\n",
" return d._children ? \"#3182bd\" : d.children ? \"#c6dbef\" : \"#fd8d3c\";\n",
" }\n",
"\n",
"});"
],
"metadata": {},
"output_type": "display_data",
"text": [
"<IPython.core.display.Javascript at 0x3595390>"
]
}
],
"prompt_number": 36
},
{
"cell_type": "code",
"collapsed": false,
"input": [],
"language": "python",
"metadata": {},
"outputs": []
}
],
"metadata": {}
}
]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment