code: def term_matrix(idlist, subject_category, taxon, **kwargs):
      
      results = search_associations(objects=idlist,
                                    subject_taxon=taxon,
                                    subject_category=subject_category,
                                    select_fields=[M.SUBJECT, M.OBJECT_CLOSURE],
                                    facet_fields=[],
                                    rows=-1,
                                    include_raw=True,
                                    **kwargs)
      docs = results['raw'].docs
  
      subjects_per_term = {}
      smap = {}
      for d in docs:
          smap[d[M.SUBJECT]] = 1
          for c in d[M.OBJECT_CLOSURE]:
              if c in idlist:
                  if c not in subjects_per_term:
                      subjects_per_term[c] = []
                  subjects_per_term[c].append(d[M.SUBJECT])
      pop_n = len(smap.keys())
  
      cells = []
      for cx in idlist:
          csubjs = set(subjects_per_term[cx])
          for dx in idlist:
              dsubjs = set(subjects_per_term[dx])
              a = len(csubjs.intersection(dsubjs))
              b = len(csubjs) - a
              c = len(dsubjs) - a
              d = pop_n - len(dsubjs) - b
              ctable = [[a, b], [c, d]]
  
              _, p_under = sp.stats.fisher_exact(ctable, 'less')
              _, p_over = sp.stats.fisher_exact(ctable, 'greater')
  
              cells.append({'c':cx, 'd':dx,
                            'nc':len(csubjs),
                            'nd':len(dsubjs),
                            'n':a,
                            'p_l':p_under,
                            'p_g':p_over
              })
      return cells
docs: Intersection between annotated objects
  
               P1  not(P1)
      F1       0   5
      not(F1)  6   0