我正在尝试使用WebAgg后端将交互式matplotlib图嵌入到Django应用程序中。每当调用fig.canvas.draw()时,浏览器中只会渲染该图的一部分。
版本: Python-3.6.7 的Django-2.2.4 频道-2.2.0 Matplotlib-3.1.1
我正在使用Django Channels作为该图的websocket。该图形有3条点,由两条线相连,用户可以单击并拖动这些点,在释放鼠标按钮后,图形将重画这些线。
在断开回调ID之前,该图应在每个'motion_notify_event'和'button_release_event'上绘制整个画布,但似乎只是在绘制某些艺术家,甚至没有绘制x或y轴。我已经能够在Tornado Web应用程序中使用此图。我尝试跟踪fig.canvas.draw调用以查看艺术家列表是否为空,但事实并非如此。我认为以某种方式浏览器只显示了差异。
example.html:
s = (df['Item'].isin(item_list)
.groupby([df['InvoiceNo'], df['CategoryNo']])
.transform('any')
)
df[s]
consumers.py:
{% load staticfiles %}
<html>
<head>
<script type="text/javascript" src='https://cdnjs.cloudflare.com/ajax/libs/reconnecting-websocket/1.0.0/reconnecting-websocket.min.js'></script>
<link rel="stylesheet" href="{% static 'css/page.css' %}">
<link rel="stylesheet" href="{% static 'css/boilerplate.css' %}">
<link rel="stylesheet" href="{% static 'css/fbm.css' %}">
<link rel="stylesheet" href="{% static 'jquery-ui-1.12.1/jquery-ui.min.css' %}">
<script src="{% static 'jquery-ui-1.12.1/external/jquery/jquery.js' %}"></script>
<script src="{% static 'jquery-ui-1.12.1/jquery-ui.min.js' %}"></script>
<script src="{% static 'js/mpl.js' %}"></script>
<script>
/* This is a callback that is called when the user saves
(downloads) a file. Its purpose is really to map from a
figure and file format to a url in the application. */
function ondownload(figure, format) {
window.open('download.' + format, '_blank');
};
var loc = window.location
var wsStart = 'ws://'
if (loc.protocol == 'https:'){
wsStart = 'wss://'
}
var fig_id = {{ mpl_fig_id }}
var webSocketEndpoint = wsStart + loc.host + loc.pathname + fig_id + "/"
console.log(webSocketEndpoint)
$(document).ready(
function() {
socket = new ReconnectingWebSocket(webSocketEndpoint)
// mpl.figure creates a new figure on the webpage.
fig = new mpl.figure({{ mpl_fig_id }}, socket, ondownload, $('div#figure'));
}
);
</script>
<title>matplotlib</title>
</head>
<body>
<h1> MATPLOTLIB WEB AGG WITH DJANGO CHANNELS </h1>
<div id="figure">
</div>
</body>
</html>
interactive_line.py:
class MplConsumer(AsyncConsumer):
supports_binary = True
async def websocket_connect(self, event):
print("connected", event)
fig_id = self.scope['url_route']['kwargs']['fig_id']
self.figure = plt.figure(num="test")
point_coords = [[.75, .75],
[1, 1],
[1.25, .125]]
self.il = InteractiveLine(point_coords,self.figure)
self.content_to_send = None
plt.savefig('fig_at_consumer.png')
# self.figure = il.fig
# self.manager = self.figure.canvas.manager
self.il.fig.canvas.manager.add_web_socket(self)
self.il.fig.canvas.mpl_connect('button_press_event', self.on_click)
await self.send({
"type": "websocket.accept"
})
def send_json(self, content):
self.content_to_send = {
'type': 'text',
'content': json.dumps(content),
}
# await self.send(json.dumps(content))
def send_binary(self, blob):
if self.supports_binary:
self.content_to_send = {
'type': 'bytes',
'content': blob,
}
else:
# b64_blob = str(blob).replace('\n', '')
# data_uri = "data:image/png;base64,{0}".format(b64_blob)
# self.content_to_send = {
# 'type': 'text',
# 'content': data_uri,
# }
self.content_to_send = {
'type': 'bytes',
'content': blob,
}
async def websocket_receive(self, event):
# print("receive", event)
message = json.loads(event['text'])
if message['type'] == 'supports_binary':
self.supports_binary = message['value']
else:
self.il.fig.canvas.manager.handle_json(message)
if self.content_to_send is not None:
content_dict = {
"type": "websocket.send",
self.content_to_send['type']: self.content_to_send['content'],
}
# print("Sending...",content_dict)
await self.send(content_dict)
async def websocket_disconnect(self, event):
print("disconnected", event)
def on_click(self, event):
contains, info = self.il.points.contains(event)
print(contains)
print(info)
if contains:
ind = info['ind'][0]
print("You clicked {}!".format(ind))
self.start_drag(ind)
def start_drag(self, ind):
self.drag_ind = ind
connect = self.il.fig.canvas.mpl_connect
cid1 = connect('motion_notify_event', self.drag_update)
cid2 = connect('button_release_event', self.end_drag)
self.il.drag_cids = [cid1, cid2]
self.on_press()
def drag_update(self, event):
self.il.xy[self.drag_ind] = [event.xdata, event.ydata]
self.il.points.set_offsets(self.il.xy)
self.il.ax.draw_artist(self.il.points)
self.il.fig.canvas.draw()
def end_drag(self, event):
print("going to redraw!")
self.redraw()
for cid in self.il.drag_cids:
self.il.fig.canvas.mpl_disconnect(cid)
def on_press(self):
self.il.line[0].set_alpha(.4)
def redraw(self):
x_data, y_data = self.il.line[0].get_data()
pt_x, pt_y = self.il.xy[self.drag_ind]
x_data[self.drag_ind] = pt_x
y_data[self.drag_ind] = pt_y
self.il.line[0].set_data(x_data, y_data)
self.il.line[0].set_alpha(1)
self.il.fig.savefig('r.png')
self.il.fig.canvas.draw()
self.il.fig.savefig('r2.png')
以下是该情节发生的GIF: my django app
在我的redraw()函数中,我保存了该图以查看Django后端中的图是否看起来类似于浏览器中的图。后端Django中的图是我的预期结果: expected result