docstr: Do post-processing after the run completes
  
  workspace - the workspace at the end of the run
docstr_tok: ["Do","post-processing","after","the","run","completes","workspace","-","the","workspace","at","the","end","of","the","run"]
code: def post_run(self, workspace):
      """Do post-processing after the run completes
  
      workspace - the workspace at the end of the run
      """
      measurements = workspace.measurements
      assert isinstance(measurements, Measurements)
      all_objects = [
          x
          for x in measurements.get_object_names()
          if x not in [EXPERIMENT, NEIGHBORS]
      ]
      feature_set = []
      image_numbers = measurements.get_image_numbers()
      for object_name in all_objects:
          all_features = [
              x
              for x in measurements.get_feature_names(object_name)
              if self.include_feature(
                  measurements, object_name, x, image_numbers
              )
          ]
          feature_set += [
              (object_name, feature_name)
              for feature_name in all_features
          ]
      grouping_data = self.get_image_measurements(
          measurements, self.grouping_values.value
      )
      grouping_data = grouping_data.flatten()
      data = numpy.zeros((len(grouping_data), len(feature_set)))
      for i, (object_name, feature_name) in enumerate(feature_set):
          data[:, i] = self.aggregate_measurement(
              measurements, object_name, feature_name
          )
  
      (
          z,
          z_one_tailed,
          OrderedUniqueDoses,
          OrderedAverageValues,
      ) = z_factors(grouping_data, data)
      #
      # For now, use first dose value only
      #
      dose_data = self.get_image_measurements(
          measurements, self.dose_values[0].measurement.value
      )
      dose_data = numpy.array(dose_data).flatten()
      v = v_factors(dose_data, data)
      expt_measurements = {
          "Zfactor": z,
          "Vfactor": v,
          "OneTailedZfactor": z_one_tailed,
      }
      for dose_group in self.dose_values:
          dose_feature = dose_group.measurement.value
          dose_data = self.get_image_measurements(
              measurements, dose_feature
          )
          ec50_coeffs = calculate_ec50(
              dose_data, data, dose_group.log_transform.value
          )
          if len(self.dose_values) == 1:
              name = "EC50"
          else:
              name = "EC50_" + dose_feature
          expt_measurements[name] = ec50_coeffs[:, 2]
          if dose_group.wants_save_figure:
              pathname = dose_group.pathname.get_absolute_path(
                  measurements
              )
              if not os.path.exists(pathname):
                  os.makedirs(pathname)
              write_figures(
                  dose_group.figure_name,
                  pathname,
                  dose_feature,
                  dose_data,
                  data,
                  ec50_coeffs,
                  feature_set,
                  dose_group.log_transform.value,
              )
  
      for i, (object_name, feature_name) in enumerate(feature_set):
          for statistic, value in list(expt_measurements.items()):
              sfeature_name = "_".join(
                  (statistic, object_name, feature_name)
              )
              measurements.add_experiment_measurement(
                  sfeature_name, value[i]
              )
      if self.show_window:
          workspace.display_data.expt_measurements = expt_measurements
          workspace.display_data.feature_set = feature_set
  
imports: import functools
  import os
  import numpy
  import scipy.optimize
  from cellprofiler_core.constants.measurement import EXPERIMENT
  from cellprofiler_core.constants.measurement import IMAGE
  from cellprofiler_core.constants.measurement import NEIGHBORS
  from cellprofiler_core.constants.module import IO_FOLDER_CHOICE_HELP_TEXT, IO_WITH_METADATA_HELP_TEXT
  from cellprofiler_core.measurement import Measurements
  from cellprofiler_core.module import Module
  from cellprofiler_core.preferences import ABSOLUTE_FOLDER_NAME
  from cellprofiler_core.preferences import DEFAULT_INPUT_FOLDER_NAME
  from cellprofiler_core.preferences import DEFAULT_INPUT_SUBFOLDER_NAME
  from cellprofiler_core.preferences import DEFAULT_OUTPUT_FOLDER_NAME
  from cellprofiler_core.preferences import DEFAULT_OUTPUT_SUBFOLDER_NAME
  from cellprofiler_core.setting import Binary
  from cellprofiler_core.setting import Divider
  from cellprofiler_core.setting import Measurement
  from cellprofiler_core.setting import SettingsGroup
  from cellprofiler_core.setting import ValidationError
  from cellprofiler_core.setting.do_something import DoSomething
  from cellprofiler_core.setting.do_something import RemoveSettingButton
  from cellprofiler_core.setting.text import Directory
  from cellprofiler_core.setting.text import Text
label_desc: Use image node_id 10 for calling the CalculateStatistics obj's underlying member method code with example usage: obj.post_run(workspace) without return types