text: from graphviz import Digraph
  import tempfile
  import base64
  from copy import copy
  from pm4py.filtering.tracelog.attributes import attributes_filter
  from pm4py.visualization.common.utils import *
  
  
  def get_min_max_value(dfg):
      """
      Gets min and max value assigned to edges
      in DFG graph
  
      Parameters
      -----------
      dfg
          Directly follows graph
  
      Returns
      -----------
      min_value
          Minimum value in directly follows graph
      max_value
          Maximum value in directly follows graph
      """
      min_value = 9999999999
      max_value = -1
  
      for edge in dfg:
          if dfg[edge] < min_value:
              min_value = dfg[edge]
          if dfg[edge] > max_value:
              max_value = dfg[edge]
  
      return min_value, max_value
  
  def assign_penwidth_edges(dfg):
      """
      Assign penwidth to edges in directly-follows graph
  
      Parameters
      -----------
      dfg
          Direcly follows graph
  
      Returns
      -----------
      penwidth
          Graph penwidth that edges should have in the direcly follows graph
      """
      penwidth = {}
      min_value, max_value = get_min_max_value(dfg)
      for edge in dfg:
          v0 = dfg[edge]
          v1 = get_arc_penwidth(v0, min_value, max_value)
          penwidth[edge] = str(v1)
  
      return penwidth
  
  def get_activities_color(activities_count):
      """
      Get frequency color for attributes
  
      Parameters
      -----------
      activities_count
          Count of attributes in the log
  
      Returns
      -----------
      activities_color
          Color assigned to attributes in the graph
      """
      activities_color = {}
  
      min_value, max_value = get_min_max_value(activities_count)
  
      for ac in activities_count:
          v0 = activities_count[ac]
          """transBaseColor = int(
              255 - 100 * (v0 - min_value) / (max_value - min_value + 0.00001))
          transBaseColorHex = str(hex(transBaseColor))[2:].upper()
          v1 = "#" + transBaseColorHex + transBaseColorHex + "FF"""
  
          v1 = get_trans_freq_color(v0, min_value, max_value)
  
          activities_color[ac] = v1
  
      return activities_color
  
  def apply_frequency(dfg, log=None, activities_count=None, parameters=None):
      """
      Apply method (to be called from the factory method; calls the graphviz_visualization method)
  
      Parameters
      -----------
      dfg
          DFG graph
      log
          Event log
      parameters
          Parameters passed to the algorithm (may include the format, the replay measure and the maximum number of edges
          in the diagram)
      """
  
      return apply(dfg, log=log, parameters=parameters, activities_count=activities_count, measure="frequency")
  
  def apply_performance(dfg, log=None, activities_count=None, parameters=None):
      """
      Apply method (to be called from the factory method; calls the graphviz_visualization method)
  
      Parameters
      -----------
      dfg
          DFG graph
      log
          Event log
      parameters
          Parameters passed to the algorithm (may include the format, the replay measure and the maximum number of edges
          in the diagram)
      """
  
      return apply(dfg, log=log, parameters=parameters, activities_count=activities_count, measure="performance")
  
  def apply(dfg, log=None, parameters=None, activities_count=None, measure="frequency"):
      if parameters is None:
          parameters = {}
      format = "pdf"
      maxNoOfEdgesInDiagram = 75
  
      if "format" in parameters:
          format = parameters["format"]
      if "maxNoOfEdgesInDiagram" in parameters:
          maxNoOfEdgesInDiagram = parameters["maxNoOfEdgesInDiagram"]
  
      if activities_count is None:
          activities_count = attributes_filter.get_activities_from_log(log)
  
      return graphviz_visualization(activities_count, dfg, format=format, measure=measure, maxNoOfEdgesInDiagram=maxNoOfEdgesInDiagram)
  
  def graphviz_visualization(activities_count, dfg, format="pdf", measure="frequency", maxNoOfEdgesInDiagram=75):
      """
      Do GraphViz visualization of a DFG graph
  
      Parameters
      -----------
      activities_count
          Count of attributes in the log (may include attributes that are not in the DFG graph)
      dfg
          DFG graph
      format
          GraphViz should be represented in this format
      measure
          Describes which measure is assigned to edges in direcly follows graph (frequency/performance)
      maxNoOfEdgesInDiagram
          Maximum number of edges in the diagram allowed for visualization
  
      Returns
      -----------
      viz
          Digraph object
      """
      filename = tempfile.NamedTemporaryFile(suffix='.gv')
      viz = Digraph("", filename=filename.name, engine='dot')
  
      # first, remove edges in diagram that exceeds the maximum number of edges in the diagram
      dfgKeyValueList = []
      for edge in dfg:
          dfgKeyValueList.append([edge, dfg[edge]])
      dfgKeyValueList = sorted(dfgKeyValueList, key=lambda x: x[1], reverse=True)
      dfgKeyValueList = dfgKeyValueList[0:min(len(dfgKeyValueList),maxNoOfEdgesInDiagram)]
      dfgAllowedKeys = [x[0] for x in dfgKeyValueList]
      dfgKeys = list(dfg.keys())
      for edge in dfgKeys:
          if not edge in dfgAllowedKeys:
              del dfg[edge]
  
      # calculate edges penwidth
      penwidth = assign_penwidth_edges(dfg)
      activities_in_dfg = set()
      activities_count_int = copy(activities_count)
      ackeys = copy(list(activities_count_int.keys()))
  
      for edge in dfg:
          activities_in_dfg.add(edge[0])
          activities_in_dfg.add(edge[1])
  
      for act in ackeys:
          if not act in activities_in_dfg:
              del activities_count_int[act]
  
      # assign attributes color
      activities_color = get_activities_color(activities_count_int)
  
      # represent nodes
      viz.attr('node', shape='box')
      for act in activities_in_dfg:
          if measure == "frequency":
              viz.node(act, act + " ("+str(activities_count_int[act])+")", style='filled', fillcolor=activities_color[act])
          else:
              viz.node(act, act)
  
      # represent edges
      for edge in dfg:
          if measure == "frequency":
              label = str(dfg[edge])
          else:
              label = human_readable_stat(dfg[edge])
          viz.edge(edge[0], edge[1], label=label, penwidth=str(penwidth[edge]))
  
      viz.attr(overlap='false')
      viz.attr(fontsize='11')
  
      viz.format = format
  
      return viz
  
  def return_diagram_as_base64(activities_count, dfg, format="svg", measure="frequency", maxNoOfEdgesInDiagram=75):
      """
      Return process model in Base64 format
  
      Parameters
      -----------
      activities_count
          Count of attributes in the log (may include attributes that are not in the DFG graph
      dfg
          DFG graph
      format
          GraphViz should be represented in this format
      measure
          Describes hich measure is assigned to edges in direcly follows graph (frequency/performance)
      maxNoOfEdgesInDiagram
          Maximum number of edges in the diagram allowed for visualization
  
      Returns
      -----------
      string
      """
  
      graphviz = graphviz_visualization(activities_count, dfg, format=format, measure=measure)
      render = graphviz.render(view=False)
      with open(render, "rb") as f:
          return base64.b64encode(f.read())