title: communication between dash and another thread using a queue
body: <p>I've written a program that periodically receives and processes geographic data.  I'd like to plot the (latitude, longitude) pairs that are generated by that program in a <code>dash</code> app providing a <code>plotly</code> <code>Scattergeo</code> plot, more or less as the data comes in.</p>
  <p>Here's a MWE of a two-threaded program that uses a queue to receive data from the geographic data source and simply print it.  The data in this case is simply <code>(lat, lon)</code> tuples.</p>
  <pre class="lang-py prettyprint-override"><code>import threading
  from queue import Queue
  from CoordSource import CoordGetter
  
  class Receiver(object):
      def __init__(self, q):
          while True:
              item = q.get()
              print(&quot;RECEIVED&quot;, item)
  
  if __name__ == '__main__':
      mainQueue = Queue()
  
      cg = threading.Thread(target=CoordGetter, args=(mainQueue, ))
      cg.start()
  
      rt = threading.Thread(target=Receiver, args=(mainQueue, ))
      rt.start()
  </code></pre>
  <p>Here's a MWE of a basic dash app that creates a <code>Scattergeo</code> plot and updates the plotted data every two seconds, but in this case it simply plots two hard-coded points:</p>
  <pre class="lang-py prettyprint-override"><code>import dash
  import dash_core_components as dcc
  import dash_html_components as html
  from dash.dependencies import Input, Output
  import plotly
  import plotly.graph_objects as go
  import pandas as pd
  
  app = dash.Dash(__name__, prevent_initial_callbacks=True)
  app.layout = html.Div(
      html.Div([
          dcc.Graph(id='live-update-graph'),
          dcc.Interval(
              id='interval-component',
              interval=1*2000,
              n_intervals=1
          )
      ])
  )
  
  @app.callback(Output('live-update-graph', 'figure'),
                Input('interval-component', 'n_intervals'))
  def update_graph_live(n):
      fig = go.Figure(go.Scattergeo())
      fig.update_geos(projection_type=&quot;orthographic&quot;)
  
      # hard-coded points, would like to receive from queue instead
      df = pd.DataFrame({'lat': [0, 20], 'lon': [20, 0]}) 
  
      fig.add_traces(data=go.Scattergeo(lat=df['lat'], lon=df['lon']))
      return fig
  
  if __name__ == '__main__':
      app.run_server(debug=True)
  </code></pre>
  <p>Both MWEs, per my reference to them, are tested and working beautifully.  However, I have been having trouble <strong>sharing a queue between the thread that generates the data and the dash app that plots it</strong>.</p>
  <p>I've tried quite a few things, read a lot of documentation and examples, and at this point I'm pretty sure I'm misunderstanding something about how dash maintains its thread(s?).  So as part of an answer, I'd love some insight into how dash works in this regard.</p>
  <p>Also, I should note, when I start a <code>CoordGetter</code> right before <code>app.run_server()</code>, it appears to starts <em>twice</em>.  That is, any debugging print statements in its <code>__init__()</code> function are output twice, and it complains the second time about the UDP port that it opens already being in use.  That it starts twice and that I expect it to start once suggests an additional misunderstanding of how dash does threads that I would like clarified.  I suspect that a good answer to my main question will clarify this too, but I figured I'd mention it explicitly.</p>
  <p><s>Note: I can share <code>CoordSource</code> if it would help, but it's a bit messy and interacts with both external hardware and software.  I think for this question it's okay to simply say that it works and treat it like a black box.  I guess it would be just as effective for testing here to make a little class that randomly generates coordinates, which I'm also happy to do to make the question more self-contained.</s></p>
  <p>EDIT: The following class roughly mimics the behaviour of <code>CoordSource.CoordGetter</code>:</p>
  <pre class="lang-py prettyprint-override"><code>from random import randrange, uniform
  from time import sleep
  
  class CoordGetter():
      def __init__(self, queue):
          self.queue = queue
          self.generate()
  
      def generate(self):
          while True:
              sleep(randrange(10))
              for i in range(1, randrange(10)):
                  lat = uniform(-90,90)
                  lon = uniform(-180,180)
                  self.queue.put((lat, lon))
  </code></pre>
  <p><strong>TLDR</strong>: How can I get data from <code>CoordSource.CoordGetter</code> (the third example) to plot as it updates in realtime using <code>Scattergeo</code> (the second example)?  Making a simple threaded script (like the first example) does not succeed.</p>