text: 
  """
  General support for producing Plotly output (as JSON files)
  """
  
  import random
  import os.path as op
  import gzip
  import json
  
  import numpy as np
  from plotly import graph_objs
  
  from pbcommand.models.report import PlotlyPlot
  
  PLOTLYJS_VERSION = "1.37.1"
  
  
  class PlotlyImage(object):
      """
      Simple IO wrapper for the plot file format.
      """
  
      def __init__(self, data, layout):
          self._data = data
          self._layout = layout
  
      def to_dict(self):
          return {"data": self._data, "layout": self._layout}
  
      def write_json(self, file_name):
          assert file_name.endswith(".json.gz")
          with gzip.open(file_name, "wb") as gzip_out:
              gzip_out.write(json.dumps(self.to_dict()))
  
      @staticmethod
      def from_file(file_name):
          with gzip.open(file_name, "rb") as json_in:
              d = json.loads(json_in.read())
              return PlotlyImage(d["data"], d["layout"])
  
  
  def to_plotly_plot(id_, file_name, plot, layout, caption=None):
      """
      Wrapper for instantiating pbcommand.models.report.Plot for a plotly image.
      """
      img = PlotlyImage(
          data=[plot],
          layout=layout)
      img.write_json(file_name)
      return PlotlyPlot(id_, op.basename(file_name), caption=caption,
                        plotly_version=PLOTLYJS_VERSION)
  
  
  def to_simple_layout(xlabel, ylabel, title, margin={}):
      return graph_objs.Layout(
          title=title,
          xaxis=dict(title=xlabel),
          yaxis=dict(title=ylabel),
          margin=dict(margin))
  
  
  def to_heatmap(x, y, z, colorscale=None):
      """
      Generate a heatmap plot, typically a pre-generated histogram.
      """
      # I think the API will not be happy with us passing None...
      if colorscale is not None:
          return graph_objs.Heatmap(x=x, y=y, z=z, colorscale=colorscale)
      else:
          return graph_objs.Heatmap(x=x, y=y, z=z)
  
  
  def to_sample_heatmap(x, y, sample_labels, y_bins, yrange, colorscale,
                        sample_axis="x"):
      """
      Generic 2D histogram from unbinned data for a series of N samples
      (plotted along either the X or Y axis).
      """
      assert sample_axis in {"x", "y"}
      x_bins = max(1, len(sample_labels))
      hist = np.histogram2d(x, y,
                            bins=[x_bins, len(y_bins)],
                            range=[[1, x_bins], list(yrange)])
      if sample_axis == "y":
          x_data, y_data = y_bins, sample_labels
          z = [[int(z[i]) for i in range(len(y_bins))] for z in hist[0]]
      else:
          x_data, y_data = sample_labels, y_bins
          z_data = [[int(z[i]) for z in hist[0]] for i in range(len(y_bins))]
      return to_heatmap(
          x=x_data,
          y=y_data,
          z=z_data,
          colorscale=colorscale)
  
  
  # TODO add more plot types
  def to_mock_plot(file_name):
      """
      Write a simple mock plot using synthetic data.
      """
      x = list(range(1, 501))
      y = [random.randint(0, 100) for x_ in x]
      plot = graph_objs.Scatter(x=x, y=y)
      layout = to_simple_layout(
          "Read Length", "Mapping Concordance", "Plotly Test")
      return to_plotly_plot("plotly_mock", file_name, plot, layout, "Plotly Test")
  