docs: def movie_network():
      """Generate interactive network graph of movie appearances
  
      Output is an html page, rendered to 'movie_network.html' in the output directory.
      """
      # page template
      template = jenv.get_template("movie_network.html")
  
      # container for template context
      context = dict()
  
      # a database client/session to run queries in
      cl = client.get_client()
      session = cl.create_session()
  
      #
      # query data
      #
  
      # get all Movies
      query = session.query(models.Movie.id,
                            models.Movie.name,
                            models.Movie.url,
                            models.Movie.budget_inflation_adjusted,
                            models.Movie.imdb_rating)
      movies = cl.df_query(query)
  
      # get all Movie Appearances
      query = session.query(models.MovieAppearance.movie_id,
                            models.MovieAppearance.character_id)
      appearances = cl.df_query(query)
  
      # get all Characters that have movie appearances
      query = session.query(models.Character.id,
                            models.Character.url,
                            models.Character.name) \
          .filter(models.Character.id.in_([int(i) for i in appearances['character_id'].unique()]))
      characters = cl.df_query(query)
  
      #
      # transform to network graph
      #
  
      graph = dict(nodes=[],
                   graph=[],  # this stays empty
                   links=[],
                   directed=False,
                   multigraph=True)
  
      # containers for lookups from movie/character IDs to node IDs
      movie_node_id = dict()
      character_node_id = dict()
  
      # normalization for movie node size: 100 = max budget
      movie_size_factor = 100. / movies['budget_inflation_adjusted'].max()
  
      # nodes for movies
      for _, data in movies.iterrows():
          movie_node_id[data['id']] = len(graph['nodes'])
          # noinspection PyTypeChecker
          graph['nodes'].append(dict(id=data['name'],
                                     size=max(5., data['budget_inflation_adjusted'] * movie_size_factor),
                                     score=data['imdb_rating'] / 10.,
                                     type='square',
                                     url="http://marvel.wikia.com" + data['url']))
  
      # nodes for characters
      for _, data in characters.iterrows():
          character_node_id[data['id']] = len(graph['nodes'])
          # noinspection PyTypeChecker
          graph['nodes'].append(dict(id=data['name'],
                                     size=10,
                                     type='circle',
                                     url="http://marvel.wikia.com" + data['url']))
  
      # links: movie appearances
      for _, data in appearances.iterrows():
          # noinspection PyTypeChecker
          graph['links'].append(dict(source=movie_node_id[data['movie_id']],
                                     target=character_node_id[data['character_id']]))
  
      context['graph'] = json.dumps(graph, indent=4)
  
      #
      # render template
      #
  
      out_file = path.join(out_dir, "movie_network.html")
      html_content = template.render(**context)
      with open(out_file, 'w') as f:
          f.write(html_content)
  
      # done, clean up
      plt.close('all')
      session.close()