Esempio n. 1
0
    def evaluate(input_rows, data, aggregate):

        quantities = [
            QuantityFactory.create_quantity(
                symbol_type=ROW_IDX_TO_SYMBOL_NAME[idx],
                value=ureg.parse_expression(row['Editable Value']))
            for idx, row in enumerate(input_rows) if row['Editable Value']
        ]

        if data and len(data) > 0:
            quantities += json.loads(data, cls=MontyDecoder).values()

        if not quantities:
            raise PreventUpdate

        material = Material()

        for quantity in quantities:
            material.add_quantity(quantity)

        graph = Graph()
        output_material = graph.evaluate(material)

        if aggregate:
            output_quantities = output_material.get_aggregated_quantities(
            ).values()
        else:
            output_quantities = output_material.get_quantities()

        output_rows = [{
            'Property': quantity.symbol.display_names[0],
            'Value': quantity.pretty_string(sigfigs=3)
        } for quantity in output_quantities]

        output_table = dt.DataTable(id='output-table',
                                    rows=output_rows,
                                    editable=False)

        # TODO: clean up

        input_quantity_names = [q.symbol.name for q in quantities]
        derived_quantity_names = set(
            [q.symbol.name for q in output_quantities]) - \
                                 set(input_quantity_names)
        material_graph_data = graph_conversion(
            graph.get_networkx_graph(),
            nodes_to_highlight_green=input_quantity_names,
            nodes_to_highlight_yellow=list(derived_quantity_names))
        options = AESTHETICS['global_options']
        options['edges']['color'] = '#000000'
        output_graph = html.Div(GraphComponent(id='material-graph',
                                               graph=material_graph_data,
                                               options=options),
                                style={
                                    'width': '100%',
                                    'height': '400px'
                                })

        return [output_graph, html.Br(), output_table]
Esempio n. 2
0
 def test_graph_conversion(self):
     graph = Graph()
     converted = graph_conversion(graph.get_networkx_graph())
     serialized = json.dumps(converted)
     self.assertIsNotNone(serialized)
     # Ensure that there are both nodes and proper edges
     self.assertIn('Band gap', [n['label'] for n in converted['nodes']])
     self.assertIn({'from': 'band_gap', "to": "Is Metallic"},
                   converted['edges'])
Esempio n. 3
0
 def test_graph_conversion(self):
     graph = Graph()
     converted = graph_conversion(graph.get_networkx_graph())
     serialized = json.dumps(converted)
     self.assertIsNotNone(serialized)
     # Ensure that there are both nodes and proper edges
     self.assertIn('Band gap', [n['data']['label']
                                for n in converted if n['group'] == 'nodes'])
     self.assertIn({'source': 'band_gap', "target": "Is Metallic"},
                   [n['data'] for n in converted if n['group'] == 'edges'])
Esempio n. 4
0
def explore_layout(app):
    graph_data = graph_conversion(propnet_nx_graph,
                                  hide_unconnected_nodes=False)
    graph_component = html.Div(
        id='graph_component',
        children=[
            Cytoscape(id='pn-graph',
                      elements=graph_data,
                      stylesheet=GRAPH_STYLESHEET,
                      layout=GRAPH_LAYOUT_CONFIG,
                      **GRAPH_SETTINGS['full_view'])
        ],
    )

    graph_layout = html.Div(id='graph_top_level',
                            children=[
                                dcc.Checklist(
                                    id='graph_options',
                                    options=[{
                                        'label': 'Show models',
                                        'value': 'show_models'
                                    }, {
                                        'label': 'Show properties',
                                        'value': 'show_properties'
                                    }],
                                    value=['show_properties'],
                                    labelStyle={'display': 'inline-block'}),
                                html.Div(id='graph_explorer',
                                         children=[graph_component])
                            ])

    @app.callback(Output('pn-graph',
                         'elements'), [Input('graph_options', 'value')],
                  [State('pn-graph', 'elements')])
    def change_propnet_graph_label_selection(props, elements):
        show_properties = 'show_properties' in props
        show_models = 'show_models' in props

        update_labels(elements,
                      show_models=show_models,
                      show_symbols=show_properties)

        return elements

    layout = html.Div([
        html.Div([graph_layout], className='row'),
        html.Div([
            html.Div([models_index], className='six columns'),
            html.Div([symbols_index()], className='six columns'),
        ],
                 className='row')
    ])

    return layout
Esempio n. 5
0
 def get_graph_component(props):
     aesthetics = AESTHETICS.copy()
     show_properties = 'show_properties' in props
     show_models = 'show_models' in props
     set_(aesthetics, "node_aesthetics.Symbol.show_labels", show_properties)
     set_(aesthetics, "node_aesthetics.Model.show_labels", show_models)
     graph_data = graph_conversion(g, aesthetics=aesthetics)
     graph_component = html.Div(
         id=str(uuid4()),
         children=[
             GraphComponent(id=str(uuid4()),
                            graph=graph_data,
                            options=AESTHETICS['global_options'])
         ],
         style={
             'width': '100%',
             'height': '800px'
         })
     return [graph_component]
Esempio n. 6
0
def symbol_layout(symbol_name):
    """Create a Dash layout for a provided symbol.

    Args:
      symbol_name (str): a symbol name
      aesthetics (dict): an aesthetics configuration dictionary

    Returns:
      Dash layout

    """
    # list to hold layouts for each section
    layouts = []

    symbol = Registry("symbols")[symbol_name]

    main_name = symbol.display_names[0]

    layouts.append(html.H6('Graph'))
    # TODO: costly, should just construct subgraph directly?
    subgraph = nx.ego_graph(propnet_nx_graph,
                            symbol,
                            undirected=True,
                            radius=2)
    subgraph_data = graph_conversion(subgraph,
                                     show_model_labels=True,
                                     show_symbol_labels=True)

    if len(subgraph_data) < 50:
        graph_config = GRAPH_LAYOUT_CONFIG.copy()
        graph_config['maxSimulationTime'] = 1500
    else:
        graph_config = GRAPH_LAYOUT_CONFIG

    layouts.append(
        html.Div(
            Cytoscape(id="model_graph",
                      elements=subgraph_data,
                      stylesheet=GRAPH_STYLESHEET,
                      layout=graph_config,
                      **GRAPH_SETTINGS['model_symbol_view'])))

    if len(symbol.display_names) > 1:
        display_names = ", ".join(symbol.display_names[1:])
        other_names = dcc.Markdown("Also known as: {}".format(display_names))
        layouts.append(other_names)

    if len(symbol.display_symbols) > 1:
        symbols = " ".join(symbol.display_symbols)
        symbols = dcc.Markdown("Common symbols: {}".format(symbols))
        layouts.append(symbols)

    if symbol.category in ('property', 'condition'):
        units = dcc.Markdown("Canonical units: **{}**".format(
            symbol.unit_as_string))
        dimension = dcc.Markdown("**{}**".format(symbol.dimension_as_string))
        layouts.append(units)
        layouts.append(dimension)

    if symbol.comment:
        layouts.append(dcc.Markdown(symbol.comment))

    return html.Div([
        main_name,
        html.Br(),
        html.Div(layouts),
        html.Br(),
        #dcc.Link('< Back to Properties', href='/property'),
        #html.Br(),
        dcc.Link('< Back', href='/explore')
    ])
Esempio n. 7
0
def symbol_layout(symbol_name, aesthetics=None):
    """Create a Dash layout for a provided symbol.

    Args:
      model: a symbol name

    Returns:
      Dash layout

    """
    aesthetics = aesthetics or AESTHETICS.copy()

    # list to hold layouts for each section
    layouts = []

    symbol = DEFAULT_SYMBOLS[symbol_name]

    main_name = symbol.display_names[0]

    layouts.append(html.H6('Graph'))
    # TODO: costly, should just construct subgraph directly?
    g = Graph()
    subgraph = nx.ego_graph(g.graph, symbol, undirected=True, radius=2)
    options = AESTHETICS['global_options']
    if "arrows" in options["edges"]:
        options["edges"]["arrows"] = "to"
    set_(aesthetics, "node_options.show_model_labels", True)
    layouts.append(
        html.Div(GraphComponent(id="model_graph",
                                graph=graph_conversion(subgraph,
                                                       aesthetics=AESTHETICS),
                                options=AESTHETICS['global_options']),
                 style={
                     'width': '100%',
                     'height': '300px'
                 }))

    if len(symbol.display_names) > 1:
        display_names = ", ".join(symbol.display_names[1:])
        other_names = dcc.Markdown("Also known as: {}".format(display_names))
        layouts.append(other_names)

    if len(symbol.display_symbols) > 1:
        symbols = " ".join(symbol.display_symbols)
        symbols = dcc.Markdown("Common symbols: {}".format(symbols))
        layouts.append(symbols)

    if symbol.category in ('property', 'condition'):
        units = dcc.Markdown("Canonical units: **{}**".format(
            symbol.unit_as_string))
        dimension = dcc.Markdown("**{}**".format(symbol.dimension_as_string))
        layouts.append(units)
        layouts.append(dimension)

    if symbol.comment:
        layouts.append(dcc.Markdown(symbol.comment))

    return html.Div([
        main_name,
        html.Br(),
        html.Div(layouts),
        html.Br(),
        dcc.Link('< Back to Properties', href='/property'),
        html.Br(),
        dcc.Link('<< Back to Home', href='/')
    ])
Esempio n. 8
0
def model_layout(model_name):
    """Create a Dash layout for a provided model.

    Args:
      model: an instance of an AbstractModel subclass

    Returns:
      Dash layout

    """

    # dict to hold layouts for each section
    layouts = OrderedDict()

    # instantiate model from name
    model = DEFAULT_MODEL_DICT[model_name]

    model_title = html.Div(className='row', children=[
        html.H3(model.title),
    ])

    # TODO: costly, should just construct subgraph directly?
    g = Graph()
    subgraph = nx.ego_graph(g.graph, model, undirected=True)
    options = AESTHETICS['global_options']
    if "arrows" in options["edges"]:
        options["edges"]["arrows"] = "to"
    layouts['Graph'] = html.Div(GraphComponent(
        id="model_graph",
        graph=graph_conversion(subgraph),
        options=AESTHETICS['global_options']),
                                style={
                                    'width': '100%',
                                    'height': '300px'
                                })

    if model.categories:
        tags = html.Ul(className="tags",
                       children=[
                           html.Li(tag, className="tag")
                           for tag in model.categories
                       ])
        layouts['Tags'] = tags

    if model.references:
        references = html.Div([
            dcc.Markdown(references_to_markdown(ref))
            for ref in model.references
        ])

        layouts['References'] = references

    symbols = html.Div(children=[
        html.Div(className='row',
                 children=[
                     html.Div(className='two columns', children=[str(symbol)]),
                     html.Div(
                         className='ten columns',
                         children=[
                             dcc.Link(
                                 DEFAULT_SYMBOLS[prop_name].display_names[0],
                                 href='/property/{}'.format(prop_name))
                         ])
                 ]) for symbol, prop_name in model.symbol_property_map.items()
    ])

    layouts['Symbols'] = symbols

    layouts['Description'] = dcc.Markdown(model.description)

    if model.validate_from_preset_test():
        sample_data_header = html.Div(
            className='row',
            children=[
                html.Div(className='five columns',
                         style={'text-align': 'center'},
                         children=[html.H4('Input(s)')]),
                html.Div(className='two columns',
                         style={'text-align': 'center'},
                         children=[html.H4('->')]),
                html.Div(className='five columns',
                         style={'text-align': 'center'},
                         children=[html.H4('Output(s)')])
            ])

        layouts['Sample Code'] = dcc.Markdown('```\n{}```'.format(
            model.example_code))

    sublayouts = []
    for title, layout in layouts.items():
        sublayouts.append(html.H6(title))
        sublayouts.append(layout)

    return html.Div([
        model_title,
        html.Br(), *sublayouts,
        html.Br(),
        dcc.Link('< Back to Models', href='/model'),
        html.Br(),
        dcc.Link('<< Back to Home', href='/')
    ])
Esempio n. 9
0
app = dash.Dash()
server = app.server
app.config.supress_callback_exceptions = True  # TODO: remove this?
app.scripts.config.serve_locally = True
app.title = "The Hitchhikers Guide to Materials Science"
route = dcc.Location(id='url', refresh=False)

cache = Cache(app.server, config={
    'CACHE_TYPE': 'filesystem', 'CACHE_DIR': '.tmp'
})

mpr = MPRester()

g = Propnet().graph
graph_data = graph_conversion(g)
graph_component = html.Div(id='graph', children=[
    ForceGraphComponent(
        id='propnet-graph',
        graphData=graph_data,
        width=800,
        height=350
    )], className='box')


# highlight node for corresponding content
@app.callback(
    Output('propnet-graph', 'selectedNode'),
    [Input('url', 'pathname')]
)
def hightlight_node_for_content(pathname):
Esempio n. 10
0
def retrieve_material(n_clicks, query, derive_properties):
    """
    Gets the material view from options

    Args:
        n_clicks (int): load material click
        formula (string): formula to find
        derive_properties ([str]): list of derivation options

    Returns:
        Div of graph component with fulfilled options

    """
    if n_clicks is None:
        return ""

    log.info("Fetching data from MP for query {}".format(query))
    if query.startswith("mp-") or query.startswith("mvc-"):
        mpid = query
    else:
        mpid = mpr.get_mpid_from_formula(query)
    material = mpr.get_material_for_mpid(mpid)
    if not material:
        return "Material not found."
    log.info("Retrieved material {} for formula {}".format(
        mpid, material['pretty_formula']))

    log.debug("Adding material to graph.")
    p = Graph()
    material_quantity_names = [
        q.symbol.name for q in material.get_quantities()
    ]
    g = p.graph

    if 'derive' in derive_properties:
        log.info("Deriving quantities for {}".format(mpid))
        material = p.evaluate(material)

        if 'aggregate' in derive_properties:
            log.debug("Aggregating quantities for material {}".format(mpid))
            # TODO: get aggregated quantities should return a list
            quantities = material.get_aggregated_quantities().items()
        else:
            quantities = [(q.symbol, q) for q in material.get_quantities()]
    else:
        quantities = [(q.symbol, q) for q in material.get_quantities()]

    rows = []
    for symbol, quantity in quantities:
        rows.append({
            'Symbol': symbol.display_names[0],
            'Value': quantity.pretty_string(3),
            # TODO: node.node_value.value? this has to make sense
            # 'Units': str(node.node_value.symbol.unit_as_string)
        })

    table = dt.DataTable(rows=rows,
                         row_selectable=True,
                         filterable=True,
                         sortable=True,
                         editable=False,
                         selected_row_indices=[],
                         id='datatable')
    derived_quantity_names = set([symbol.name for symbol, quantity in quantities]) -\
        set(material_quantity_names)
    material_graph_data = graph_conversion(
        g,
        nodes_to_highlight_green=material_quantity_names,
        nodes_to_highlight_yellow=list(derived_quantity_names))
    options = AESTHETICS['global_options']
    options['edges']['color'] = '#000000'
    material_graph_component = html.Div(GraphComponent(
        id='material-graph', graph=material_graph_data, options=options),
                                        style={
                                            'width': '100%',
                                            'height': '400px'
                                        })

    return html.Div(
        [html.H3('Graph'), material_graph_component,
         html.H3('Table'), table])
Esempio n. 11
0
    def evaluate(input_rows, data, aggregate):

        quantities = []

        for idx, row in enumerate(input_rows):
            if row['Editable Value']:
                try:
                    value = ureg.parse_expression(row['Editable Value'])
                    units = Registry("units").get(ROW_IDX_TO_SYMBOL_NAME[idx])
                    value.ito(units)
                except Exception:
                    # Someone put an invalid value in the table
                    # TODO: Make error known to the user
                    raise PreventUpdate
                q = QuantityFactory.create_quantity(
                    symbol_type=ROW_IDX_TO_SYMBOL_NAME[idx], value=value)
                quantities.append(q)

        if data and len(data) > 0:
            quantities += json.loads(data, cls=MontyDecoder).values()

        if not quantities:
            raise PreventUpdate

        material = Material()

        for quantity in quantities:
            material.add_quantity(quantity)

        output_material = graph_evaluator.evaluate(material, timeout=5)

        if aggregate:
            aggregated_quantities = output_material.get_aggregated_quantities()
            non_aggregatable_quantities = [
                v for v in output_material.get_quantities()
                if v.symbol not in aggregated_quantities
            ]
            output_quantities = list(
                aggregated_quantities.values()) + non_aggregatable_quantities
        else:
            output_quantities = output_material.get_quantities()

        output_rows = [{
            'Property': quantity.symbol.display_names[0],
            'Value': quantity.pretty_string(sigfigs=3)
        } for quantity in output_quantities]

        output_table = dt.DataTable(id='output-table',
                                    data=output_rows,
                                    columns=[{
                                        'id': val,
                                        'name': val
                                    } for val in ('Property', 'Value')],
                                    editable=False,
                                    **DATA_TABLE_STYLE)

        # TODO: clean up

        input_quantity_names = [q.symbol for q in quantities]
        derived_quantity_names = \
            set([q.symbol for q in output_quantities]) - \
            set(input_quantity_names)

        models_evaluated = set(
            output_q.provenance.model
            for output_q in output_material.get_quantities())
        models_evaluated = [
            Registry("models").get(m) for m in models_evaluated
            if Registry("models").get(m) is not None
        ]

        material_graph_data = graph_conversion(
            propnet_nx_graph,
            derivation_pathway={
                'inputs': input_quantity_names,
                'outputs': list(derived_quantity_names),
                'models': models_evaluated
            })

        output_graph = html.Div(children=[
            dcc.Checklist(id='material-graph-options',
                          options=[{
                              'label': 'Show models',
                              'value': 'show_models'
                          }, {
                              'label': 'Show properties',
                              'value': 'show_properties'
                          }],
                          value=['show_properties'],
                          labelStyle={'display': 'inline-block'}),
            Cytoscape(id='material-graph',
                      elements=material_graph_data,
                      stylesheet=GRAPH_STYLESHEET,
                      layout=GRAPH_LAYOUT_CONFIG,
                      **GRAPH_SETTINGS['full_view'])
        ])

        return [output_graph, html.Br(), output_table]
Esempio n. 12
0
def explore_layout(app):

    g = Graph().get_networkx_graph()

    graph_data = graph_conversion(g)
    graph_component = html.Div(id='graph_component',
                               children=[
                                   GraphComponent(
                                       id='propnet-graph',
                                       graph=graph_data,
                                       options=AESTHETICS['global_options'])
                               ],
                               style={
                                   'width': '100%',
                                   'height': '800px'
                               })

    graph_layout = html.Div(id='graph_top_level',
                            children=[
                                dcc.Checklist(
                                    id='graph_options',
                                    options=[{
                                        'label': 'Show models',
                                        'value': 'show_models'
                                    }, {
                                        'label': 'Show properties',
                                        'value': 'show_properties'
                                    }],
                                    values=['show_properties'],
                                    labelStyle={'display': 'inline-block'}),
                                html.Div(id='graph_explorer',
                                         children=[graph_component])
                            ])

    # Define default graph component
    # TODO: this looks bad, re-evaluate
    @app.callback(Output('graph_explorer', 'children'),
                  [Input('graph_options', 'values')])
    def get_graph_component(props):
        aesthetics = AESTHETICS.copy()
        show_properties = 'show_properties' in props
        show_models = 'show_models' in props
        set_(aesthetics, "node_aesthetics.Symbol.show_labels", show_properties)
        set_(aesthetics, "node_aesthetics.Model.show_labels", show_models)
        graph_data = graph_conversion(g, aesthetics=aesthetics)
        graph_component = html.Div(
            id=str(uuid4()),
            children=[
                GraphComponent(id=str(uuid4()),
                               graph=graph_data,
                               options=AESTHETICS['global_options'])
            ],
            style={
                'width': '100%',
                'height': '800px'
            })
        return [graph_component]

    layout = html.Div([
        html.Div([graph_layout], className='row'),
        html.Div([
            html.Div([models_index], className='six columns'),
            html.Div([symbols_index()], className='six columns'),
        ],
                 className='row')
    ])

    return layout