使用Django Channels的交互式WebAgg图未呈现整个图形

时间:2019-09-04 21:01:40

标签: javascript python django matplotlib django-channels

我正在尝试使用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

Full code of my project can be found here

0 个答案:

没有答案