Пример #1
0
def visualize(
    temporal_networks,
    frame_dt,
    time_normalization_factor=1,
    time_unit=None,
    titles=None,
    config=None,
    port=8226,
    export_path=None,
):
    """
    Visualize a temporal network or a list of temporal networks interactively.
    This routine starts up an HTTP server, bins the networks according to the
    time step ``frame_dt`` and copies them to ``~/.tacoma/web``. Subsequently,
    a the interaction is started in the standard browser.

    The visualization is stopped with KeyboardInterrupt. The temporary
    temporal network files will subsequently be deleted.

    Parameters
    ----------
    temporal_networks : an instance of :class:`_tacoma.edge_changes`, :class:`_tacoma.edge_lists`, :class:`_tacoma.edge_lists_with_histograms`, :class:`_tacoma.edge_changes_with_histograms` or a list containing those.
        The temporal networks to visualize. If a list is provided, all networks need to have the
        same `t0` and `tmax`.
    frame_dt : float
        The duration of a frame in the visualization.

        .. note::

            This has to be given in the original time units
            of the temporal network, disregarding any
            value of ``time_normalization_factor``.
    time_normalization_factor : float, default : 1.0
        Rescale time with this factor.
    time_unit : string, default : None,
        Unit of time of the visualization.
    titles : string or list of strings, default : None
        Titles to put on the figures of the corresponding temporal networks.
    config : dict or str
        Configuration values for the JavaScript visualization. If this
        is a string, it can be either ``hs13``, ``dtu``, or ``ht09`` and
        the appropriate configuration is loaded.
    port : int, default : 8226
        Port of the started HTTP server.
    export_path : string, default : None
        path to a directory to which the whole visualization is copied.
        Use ``os.get_cwd()+'/export_dir/'`` for the current working directory (after
        ``import os``).

        .. warning::
            
            No subdirectory will be made for the export. All visualization files
            will be exported to ``export_path`` directly.

    Notes
    -----

    The configuration dictionary is filled with values to control
    the appearance of the visualizations. The standard configuration is

    .. code:: python

        config = {
            "plot_width" : 320 ,
            "network_plot_height" : 250,
            "edges_plot_height" : 100,
            "padding" : 10,
            "start_it" : 0,
            "node_radius" : 2.5,
            "link_distance" : 10,
            "node_charge": -8,
            "edge_line_width" : 1,
            "font_size_in_px" : 14,
            "link_width" : 1,
            "d3_format_string": ".3f",
        }
    """

    if not hasattr(temporal_networks, '__len__'):
        temporal_networks = [temporal_networks]

    if titles is None:
        titles = ["" for _ in temporal_networks]
    elif type(titles) == str or not hasattr(titles, '__len__'):
        titles = [titles]

    this_config = copy.deepcopy(standard_config)

    if isinstance(config, str):
        if config == 'dtu':
            config = dict(dtu_config)
        elif config == 'hs13':
            config = dict(hs13_config)
        elif config == 'ht09':
            config = dict(ht09_config)
        else:
            raise ValueError("config", config, "is unknown.")

    if config is not None:
        this_config.update(config)

    # print(titles)

    # define the server address
    # server_address = ('127.0.0.1', port)
    path = '~/.tacoma/web/'

    web_dir = os.path.abspath(os.path.expanduser(path))

    # download d3 if that did not happen yet
    download_d3()

    # copy the html and js files for the visualizations
    prepare_visualization_directory()

    # create a subfolder based on the current time
    subdir = "tmp_{:x}".format(int(time.time() * 1000))
    mkdirp_customdir(directory=web_dir)
    subdir_path = os.path.join(web_dir, subdir)
    mkdirp_customdir(directory=subdir_path)

    # in case an export is demanded, prepare the export directory
    if export_path is not None:
        export_path = os.path.abspath(os.path.expanduser(export_path))
        prepare_export_directory(export_path, subdir)

    # change directory to this directory
    print("changing directory to", web_dir)
    print("starting server here ...", web_dir)
    cwd = os.getcwd()
    os.chdir(web_dir)

    server = StoppableHTTPServer(
        ("127.0.0.1", port),
        http.server.SimpleHTTPRequestHandler,
        subdir_path,
    )

    for itn, tn in enumerate(temporal_networks):
        print("preparing network", titles[itn])
        tn_b = _get_prepared_network(tn, frame_dt, time_unit,
                                     time_normalization_factor)
        taco_fname = os.path.join(subdir, subdir + '_' + str(itn) + '.taco')
        edge_fname = os.path.join(subdir, subdir + '_' + str(itn) + '.json')
        tc.write_edge_trajectory_coordinates(tn_b,
                                             os.path.join(web_dir, edge_fname),
                                             filter_for_duration=frame_dt *
                                             time_normalization_factor)
        tc.write_json_taco(tn_b, os.path.join(web_dir, taco_fname))

        this_config['temporal_network_files'].append(taco_fname)
        this_config['edges_coordinate_files'].append(edge_fname)
        this_config['titles'].append(titles[itn])

    with open(os.path.join(web_dir, subdir + '_config.json'), 'w') as f:
        json.dump(this_config, f)

    if export_path is not None:
        copy_tree(subdir_path, os.path.join(export_path, subdir))
        with open(os.path.join(export_path, 'default_config.json'), 'w') as f:
            json.dump(this_config, f)

    # ========= start server ============
    thread = threading.Thread(None, server.run)
    thread.start()

    webbrowser.open("http://localhost:" + str(port) + "/?data=" + subdir)

    try:
        while True:
            time.sleep(2)
    except KeyboardInterrupt:
        # thread.join()
        print('stopping server ...')
        server.stop_this()
        thread.join()

    # time.sleep(1)

    print('changing directory back to', cwd)

    os.chdir(cwd)
Пример #2
0
def visualize(
    network,
    port=9853,
    verbose=False,
    config=None,
    plot_in_cell_below=True,
    is_test=False,
):
    """
    Visualize a network interactively using Ulf Aslak's d3 web app.
    Saves the network as json, saves the passed config and runs 
    a local HTTP server which then runs the web app.
    
    Parameters
    ----------
    network : networkx.Graph or networkx.DiGraph or node-link dictionary
        The network to visualize
    port : int, default : 9853
        The port at which to run the server locally.
    verbose : bool, default : False
        Be chatty.
    config : dict, default : None,
        In the default configuration, each key-value-pair will
        be overwritten with the key-value-pair provided in `config`.
        The default configuration is

        .. code:: python

            default_config = {
                # Input/output
                'zoom': 1,
                # Physics
                'node_charge': -45,
                'node_gravity': 0.1,
                'link_distance': 15,
                'link_distance_variation': 0,
                'node_collision': True,
                'wiggle_nodes': False,
                'freeze_nodes': False,
                # Nodes
                'node_fill_color': '#79aaa0',
                'node_stroke_color': '#555555',
                'node_label_color': '#000000',
                'display_node_labels': False,
                'scale_node_size_by_strength': False,
                'node_size': 5,
                'node_stroke_width': 1,
                'node_size_variation': 0.5,
                # Links
                'link_color': '#7c7c7c',
                'link_width': 2,
                'link_alpha': 0.5,
                'link_width_variation': 0.5,
                # Thresholding
                'display_singleton_nodes': True,
                'min_link_weight_percentile': 0,
                'max_link_weight_percentile': 1
            }

        When started from a Jupyter notebook, this will show a
        reproduced matplotlib figure of the stylized network
        in a cell below. Only works if ``verbose = False``.
    is_test : bool, default : False
        If ``True``, the interactive environment will post
        its visualization to Python automatically after 5 seconds.

    Returns
    -------
    network_properties : dict
        contains all necessary information to redraw the figure which
        was created in the interactive visualization
    config : dict
        contains all configurational values of the interactive
        visualization
    """

    this_config = deepcopy(default_config)
    if config is not None:
        this_config.update(config)

    path = netwulf_user_folder
    mkdirp_customdir()
    web_dir = pathlib.Path(path)

    # copy the html and js files for the visualizations
    prepare_visualization_directory()

    # create a json-file based on the current time
    file_id = "tmp_{:x}".format(int(time.time() * 1000)) + ".json"
    filename = file_id
    configname = "config_" + filename

    filepath = str(web_dir / filename)
    configpath = str(web_dir / configname)

    with open(filepath, 'w') as f:
        if type(network) in [nx.Graph, nx.DiGraph]:
            network = nx.node_link_data(network)
            if 'graph' in network:
                network.update(network['graph'])
                del network['graph']
        json.dump(network, f, iterable_as_array=True, default=_json_default)

    with open(configpath, 'w') as f:
        json.dump(this_config, f, default=_json_default)

    # change directory to this directory
    if verbose:
        print("changing directory to", str(web_dir))
        print("starting server here ...", str(web_dir))
    cwd = os.getcwd()
    os.chdir(str(web_dir))

    server = NetwulfHTTPServer(
        ("127.0.0.1", port),
        NetwulfHTTPRequestHandler,
        [filepath, configpath],
        verbose=verbose,
    )

    # ========= start server ============
    thread = threading.Thread(None, server.run)
    thread.start()

    url = "http://localhost:" + str(
        port) + "/?data=" + filename + "&config=" + configname
    if is_test:
        url += "&pytest"
    webbrowser.open(url)

    try:
        while not server.end_requested:
            time.sleep(0.1)
        is_keyboard_interrupted = False
    except KeyboardInterrupt:
        is_keyboard_interrupted = True

    server.end_requested = True

    if verbose:
        print('stopping server ...')
    server.stop_this()
    thread.join(0.2)

    posted_network_properties = server.posted_network_properties
    posted_config = server.posted_config

    if verbose:
        print('changing directory back to', cwd)

    os.chdir(cwd)

    # see whether or not the whole thing was started from a jupyter notebook and if yes,
    # actually re-draw the figure and display it
    env = os.environ
    try:
        is_jupyter = 'jupyter' in pathlib.PurePath(env['_']).name
    except:  # this should actually be a key error
        # apparently this is how it has to be on Windows
        is_jupyter = 'JPY_PARENT_PID' in env

    if is_jupyter and plot_in_cell_below and not is_keyboard_interrupted:
        if verbose:
            print('recreating layout in matplotlib ...')
        fig, ax = wulf.draw_netwulf(posted_network_properties)

    return posted_network_properties, posted_config
Пример #3
0
def visualize(network,
              port=9853,
              config=None):
    """
    Visualize a network interactively using Ulf Aslak's d3 web app.
    Saves the network as json, saves the passed config and runs 
    a local HTTP server which then runs the web app.
    
    Parameters
    ==========
    network : networkx.Graph or networkx.DiGraph
        The network to visualize
    port : int, default : 9853
        The port at which to run the server locally.
    config : dict, default : None,
        In the default configuration, each key-value-pair will
        be overwritten with the key-value-pair provided in `config`.
        The default configuration is
        ```
            default_config = {
              'Apply heat (wiggle)': false,
              'Charge strength': -10,
              'Center gravity': 0.1,
              'Link distance': 10,
              'Link width': 2,
              'Link alpha': 0.5,
              'Node size': 5, 
              'Node stroke size': 0.5,
              'Node size exponent': 0.5,
              'Link strength exponent': 0.1,
              'Link width exponent': 0.5,
              'Collision': False,
              'Node fill': '#16a085',
              'Node stroke': '#000000',
              'Link stroke': '#7c7c7c',
              'Label stroke': '#000000',
              'Show labels': False,
              'Zoom': 1.5,
              'Min. link weight %': 0,
              'Max. link weight %': 100
        ```
    """

    this_config = deepcopy(default_config)
    if config is not None:
        this_config.update(config)

    path = "~/.netwulf/"
    mkdirp_customdir()
    web_dir = os.path.abspath(os.path.expanduser(path))

    # copy the html and js files for the visualizations
    prepare_visualization_directory()

    # create a json-file based on the current time
    file_id = "tmp_{:x}".format(int(time.time()*1000)) + ".json"
    filename = file_id
    configname = "config_" + filename

    filepath = os.path.join(web_dir, filename)
    configpath = os.path.join(web_dir, configname)

    with open(filepath,'w') as f:
        json.dump(nx.node_link_data(network), f)

    with open(configpath,'w') as f:
        json.dump(this_config, f)

    # change directory to this directory
    print("changing directory to", web_dir)
    print("starting server here ...", web_dir)
    cwd = os.getcwd()
    os.chdir(web_dir)

    server = StoppableHTTPServer(("127.0.0.1", port),
                                 http.server.SimpleHTTPRequestHandler,
                                 [filepath, configpath],
                                 )

    # ========= start server ============
    thread = threading.Thread(None, server.run)
    thread.start()

    webbrowser.open("http://localhost:"+str(port)+"/?data=" + filename + "&config=" + configname)

    try:
        while True:
            time.sleep(2)
    except KeyboardInterrupt:
        print('stopping server ...')
        server.stop_this()
        thread.join()


    print('changing directory back to', cwd)

    os.chdir(cwd)