Я в процессе создания плагина mpld3 для преобразования графика NetworkX в силовой макет. У меня возникли проблемы с пониманием того, как масштабирование осей работает в mpld3 и как я могу заставить его перевести на график компоновки сил.NetworkX D3 Force Layout Plugin для mpld3
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
import mpld3
from mpld3 import plugins, utils
from networkx.readwrite.json_graph import node_link_data
class NetworkXD3ForceLayoutView(plugins.PluginBase):
"""A simple plugin showing how multiple axes can be linked"""
JAVASCRIPT = """
mpld3.register_plugin("networkxd3forcelayoutview", NetworkXD3ForceLayoutViewPlugin);
NetworkXD3ForceLayoutViewPlugin.prototype = Object.create(mpld3.Plugin.prototype);
NetworkXD3ForceLayoutViewPlugin.prototype.constructor = NetworkXD3ForceLayoutViewPlugin;
NetworkXD3ForceLayoutViewPlugin.prototype.requiredProps = ["graph", "charge", "linkDistance", "gravity"];
function NetworkXD3ForceLayoutViewPlugin(fig, props){
mpld3.Plugin.call(this, fig, props);
};
var color = d3.scale.category20();
NetworkXD3ForceLayoutViewPlugin.prototype.draw = function(){
var zoom = d3.behavior.zoom();
var height = this.fig.height
var width = this.fig.width
var graph = this.props.graph
var gravity = this.props.gravity.toFixed()
var charge = this.props.charge.toFixed()
var linkDistance = this.props.linkDistance.toFixed()
console.log(graph)
var ax = this.fig.axes[0] // axis required for zoomx and zoomy presumably?
var g = d3.select('.mpld3-axes').append('g') // This is right?
var vis = g.append('svg')
.attr('width', this.width)
.attr('height', this.height);
force = d3.layout.force()
.gravity(gravity)
.charge(charge)
.linkDistance(linkDistance)
.nodes(graph.nodes)
.links(graph.links)
.size([width, height])
.start()
var link = vis.selectAll("line.link")
.data(graph.links)
.enter().append("svg:line")
.attr("class", "link")
.attr("stroke", "black")
.style("stroke-width", function(d) { return Math.sqrt(d.value); })
.attr("x1", function(d) { return d.source.x; })
.attr("y1", function(d) { return d.source.y; })
.attr("x2", function(d) { return d.target.x; })
.attr("y2", function(d) { return d.target.y; });
var node = vis.selectAll("circle.node")
.data(graph.nodes)
.enter().append("svg:circle")
.attr("class", "node")
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; })
.attr("r", 5)
.style("fill", function(d) { return d.color; })
.call(force.drag);
node.append("svg:title")
.text(function(d) { return d.name; });
vis.style("opacity", 1e-6)
.transition()
.duration(1000)
.style("opacity", 1);
force.on("tick", function() {
link.attr("x1", function(d) { return d.source.x; })
.attr("y1", function(d) { return d.source.y; })
.attr("x2", function(d) { return d.target.x; })
.attr("y2", function(d) { return d.target.y; });
node.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
});
zoom.on("zoom", function() {
g.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
})
g.call(zoom)
};
"""
def __init__(self, G, gravity=0.5, link_distance=20, charge=-10):
self.dict_ = {"type": "networkxd3forcelayoutview",
"graph": node_link_data(G),
"gravity": gravity,
"charge": charge,
"linkDistance": link_distance}
fig, ax = plt.subplots(1, 1)
# scatter periods and amplitudes
np.random.seed(0)
import networkx as nx
G=nx.Graph()
G.add_node(1, color='red')
G.add_edge(1,2)
plugins.connect(fig, NetworkXD3ForceLayoutView(G))
mpld3.display()
Вышеупомянутый минимальный рабочий пример, который я смог запустить в ноутбуке. Я добавил обратный вызов масштабирования к элементу группы, который содержит график в настоящее время, поэтому график будет увеличиваться, если мышь, если над узлом. Как заставить его работать, когда я использую масштабирование на пользовательской панели инструментов. Правильно ли это подходит для создания плагина силового макета? Я также опубликовал here, но может быть, что SO - лучшее место для этого вопроса.
Ох, круто, я всегда этого хотел! Объекты 'zoom' действительно сложны, и я не помню, как они работают. Вы можете найти их в своем объекте 'ax', как' ax.zoom', 'ax.zoom_x' и' ax.zoom_y'. Хотелось бы, чтобы я лучше помнил, что они делают, но чтобы узнать, я бы начал копать через код js здесь: https://github.com/mpld3/mpld3/blob/73473c9ffd8ea36a1912244e664fdb7ce391fd8b/src/core/axes.js#L171 –
Спасибо за ответ! Я начинаю копаться в коде, и я нажимаю на некоторые стены. Я прокомментирую здесь, как только у меня появится лучшее представление о том, что происходит. Будет хорошо иметь это в mpld3 :) – kdheepak
Хорошо, у меня есть версия! :) Еще несколько перегибов, чтобы сгладить, и должно быть хорошо идти. Считаете ли вы, что это должно делать в основном репо? Я думаю, это будет хорошо, если мы создадим пользовательский репозиторий плагинов в организации. Мысли? – kdheepak