def exercise_twin_detection (verbose=False) : # simple model with translational pseudosymmetry # XXX one big disadvantage: no centric reflections! pdb_str = """\ CRYST1 12.000 8.000 12.000 90.02 89.96 90.05 P 1 1 ATOM 39 N ASN A 6 5.514 2.664 4.856 1.00 11.99 N ATOM 40 CA ASN A 6 6.831 2.310 4.318 1.00 12.30 C ATOM 41 C ASN A 6 7.854 2.761 5.324 1.00 13.40 C ATOM 42 O ASN A 6 8.219 3.943 5.374 1.00 13.92 O ATOM 43 CB ASN A 6 7.065 3.016 2.993 1.00 12.13 C ATOM 44 CG ASN A 6 5.961 2.735 2.003 1.00 12.77 C ATOM 45 OD1 ASN A 6 5.798 1.604 1.551 1.00 14.27 O ATOM 46 ND2 ASN A 6 5.195 3.747 1.679 1.00 10.07 N ATOM 47 N TYR A 7 8.292 1.817 6.147 1.00 14.70 N ATOM 48 CA TYR A 7 9.159 2.144 7.299 1.00 15.18 C ATOM 49 C TYR A 7 10.603 2.331 6.885 1.00 15.91 C ATOM 50 O TYR A 7 11.041 1.811 5.855 1.00 15.76 O ATOM 51 CB TYR A 7 9.061 1.065 8.369 1.00 15.35 C ATOM 52 CG TYR A 7 7.665 0.929 8.902 1.00 14.45 C ATOM 53 CD1 TYR A 7 6.771 0.021 8.327 1.00 15.68 C ATOM 54 CD2 TYR A 7 7.210 1.756 9.920 1.00 14.80 C ATOM 55 CE1 TYR A 7 5.480 -0.094 8.796 1.00 13.46 C ATOM 56 CE2 TYR A 7 5.904 1.649 10.416 1.00 14.33 C ATOM 57 CZ TYR A 7 5.047 0.729 9.831 1.00 15.09 C ATOM 58 OH TYR A 7 3.766 0.589 10.291 1.00 14.39 O ATOM 59 OXT TYR A 7 11.358 2.999 7.612 1.00 17.49 O TER ATOM 1 N ASN B 6 1.414 5.113 6.019 1.00 12.99 N ATOM 2 CA ASN B 6 2.720 4.776 5.445 1.00 13.30 C ATOM 3 C ASN B 6 3.763 5.209 6.438 1.00 14.40 C ATOM 4 O ASN B 6 4.125 6.391 6.507 1.00 14.92 O ATOM 5 CB ASN B 6 2.922 5.513 4.131 1.00 13.13 C ATOM 6 CG ASN B 6 1.798 5.250 3.160 1.00 13.77 C ATOM 7 OD1 ASN B 6 1.629 4.129 2.686 1.00 15.27 O ATOM 8 ND2 ASN B 6 1.022 6.266 2.875 1.00 11.07 N ATOM 9 N TYR B 7 4.222 4.248 7.230 1.00 15.70 N ATOM 10 CA TYR B 7 5.113 4.552 8.370 1.00 16.18 C ATOM 11 C TYR B 7 6.547 4.754 7.929 1.00 16.91 C ATOM 12 O TYR B 7 6.964 4.259 6.878 1.00 16.76 O ATOM 13 CB TYR B 7 5.042 3.449 9.417 1.00 16.35 C ATOM 14 CG TYR B 7 3.659 3.296 9.977 1.00 15.45 C ATOM 15 CD1 TYR B 7 2.756 2.398 9.402 1.00 16.68 C ATOM 16 CD2 TYR B 7 3.224 4.098 11.023 1.00 15.80 C ATOM 17 CE1 TYR B 7 1.476 2.267 9.896 1.00 14.46 C ATOM 18 CE2 TYR B 7 1.929 3.975 11.545 1.00 15.33 C ATOM 19 CZ TYR B 7 1.063 3.065 10.959 1.00 16.09 C ATOM 20 OH TYR B 7 -0.207 2.910 11.443 1.00 15.39 O ATOM 21 OXT TYR B 7 7.316 5.408 8.654 1.00 18.49 O END """ pdb_in = iotbx.pdb.hierarchy.input(pdb_string=pdb_str) xrs = pdb_in.input.xray_structure_simple() fc = abs(xrs.structure_factors(d_min=2.5).f_calc()) fc = fc.set_observation_type_xray_amplitude() sigf = flex.double(fc.size(), 0.1) + (fc.data() * 0.03) fc = fc.customized_copy(sigmas=sigf) # and now add twinning fc_twin = fc.twin_data(twin_law='-l,-k,-h', alpha=0.4) fc_twin.as_mtz_dataset(column_root_label="F").mtz_object().write( "tmp_xtriage_twinned.mtz") # twin_laws laws = twin_analyses.twin_laws(miller_array=fc_twin) assert (len(laws.operators) == 7) delta_santoro = [ tl.delta_santoro for tl in laws.operators ] assert approx_equal(delta_santoro, [0.104655, 0.104655, 0.066599, 0.104655, 0.076113, 0.066599, 0.028542]) delta_le_page = [ tl.delta_le_page for tl in laws.operators ] assert approx_equal(delta_le_page, [0.053839, 0.053839, 0.053839, 0.064020, 0.044706, 0.049480, 0.021221]) delta_lebedev = [ tl.delta_lebedev for tl in laws.operators ] assert approx_equal(delta_lebedev, [0.000787, 0.000787, 0.000767, 0.000912, 0.000637, 0.000705, 0.000302]) # TNCS tps = twin_analyses.detect_pseudo_translations( miller_array=fc_twin, out=null_out()) assert ([tps.mod_h, tps.mod_k, tps.mod_l] == [3,2,3]) assert approx_equal(tps.high_peak, 47.152352) assert approx_equal(tps.high_p_value, 0.000103) # L test fc_norm_acentric = twin_analyses.wilson_normalised_intensities( miller_array=fc_twin, normalise=True, out=null_out()).acentric ltest = twin_analyses.l_test(miller_array=fc_norm_acentric, parity_h=3, parity_l=3) assert approx_equal(ltest.mean_l, 0.498974) assert approx_equal(ltest.mean_l2, 0.371674) # we need to go through the wrapper class for a lot of these... out = StringIO() tw = twin_analyses.twin_analyses(miller_array=fc_twin, out=out) tw2 = twin_analyses.twin_analyses(miller_array=fc_twin, out=out, d_hkl_for_l_test=[3,2,3]) # Wilson moments wm = tw.wilson_moments assert ([wm.centric_i_ratio, wm.centric_f_ratio, wm.centric_e_sq_minus_one] == [None, None, None]) assert approx_equal(wm.acentric_i_ratio, 2.878383) assert approx_equal(wm.acentric_f_ratio, 0.717738) assert approx_equal(wm.acentric_abs_e_sq_minus_one, 0.808899) assert (not wm.centric_present) # Overall analyses out = StringIO() tw.show(out=out) assert ("significantly different than is expected" in out.getvalue()) summary = tw.twin_summary assert approx_equal(summary.l_mean, 0.4989738) assert approx_equal(summary.patterson_height, 47.152352) for k, twin_r_factor in enumerate(summary.r_obs) : if (k == 6) : assert twin_r_factor < 0.11 else : assert twin_r_factor > 0.3 out2 = StringIO() tw.l_test.show(out=out2) assert ("""\ Mean |L| :0.499 (untwinned: 0.500; perfect twin: 0.375) Mean L^2 :0.372 (untwinned: 0.333; perfect twin: 0.200) """ in out2.getvalue()), out2.getvalue() out3 = StringIO() tw2.l_test.show(out=out3) assert not show_diff(out2.getvalue(), out3.getvalue()) if (verbose) : print out.getvalue() # twin_results_interpretation object via cctbx.miller.array API extension # XXX I get slightly different numbers here versus running through the # twin_analyses call above - this seems to be caused by the resolution # limits passed here. Need to confirm these with PHZ. result = fc_twin.analyze_intensity_statistics() assert approx_equal(result.maha_l, 27.580674) assert approx_equal(result.r_obs, [0.514901, 0.514901, 0.397741, 0.580353, 0.579294, 0.420914, 0.114999]) assert approx_equal(result.h_alpha, [0.019980, 0.019980, 0.211788, 0.073926, 0.079920, 0.150849, 0.389610]) assert result.has_twinning()
def exercise_twin_detection(verbose=False): # simple model with translational pseudosymmetry # XXX one big disadvantage: no centric reflections! pdb_str = """\ CRYST1 12.000 8.000 12.000 90.02 89.96 90.05 P 1 1 ATOM 39 N ASN A 6 5.514 2.664 4.856 1.00 11.99 N ATOM 40 CA ASN A 6 6.831 2.310 4.318 1.00 12.30 C ATOM 41 C ASN A 6 7.854 2.761 5.324 1.00 13.40 C ATOM 42 O ASN A 6 8.219 3.943 5.374 1.00 13.92 O ATOM 43 CB ASN A 6 7.065 3.016 2.993 1.00 12.13 C ATOM 44 CG ASN A 6 5.961 2.735 2.003 1.00 12.77 C ATOM 45 OD1 ASN A 6 5.798 1.604 1.551 1.00 14.27 O ATOM 46 ND2 ASN A 6 5.195 3.747 1.679 1.00 10.07 N ATOM 47 N TYR A 7 8.292 1.817 6.147 1.00 14.70 N ATOM 48 CA TYR A 7 9.159 2.144 7.299 1.00 15.18 C ATOM 49 C TYR A 7 10.603 2.331 6.885 1.00 15.91 C ATOM 50 O TYR A 7 11.041 1.811 5.855 1.00 15.76 O ATOM 51 CB TYR A 7 9.061 1.065 8.369 1.00 15.35 C ATOM 52 CG TYR A 7 7.665 0.929 8.902 1.00 14.45 C ATOM 53 CD1 TYR A 7 6.771 0.021 8.327 1.00 15.68 C ATOM 54 CD2 TYR A 7 7.210 1.756 9.920 1.00 14.80 C ATOM 55 CE1 TYR A 7 5.480 -0.094 8.796 1.00 13.46 C ATOM 56 CE2 TYR A 7 5.904 1.649 10.416 1.00 14.33 C ATOM 57 CZ TYR A 7 5.047 0.729 9.831 1.00 15.09 C ATOM 58 OH TYR A 7 3.766 0.589 10.291 1.00 14.39 O ATOM 59 OXT TYR A 7 11.358 2.999 7.612 1.00 17.49 O TER ATOM 1 N ASN B 6 1.414 5.113 6.019 1.00 12.99 N ATOM 2 CA ASN B 6 2.720 4.776 5.445 1.00 13.30 C ATOM 3 C ASN B 6 3.763 5.209 6.438 1.00 14.40 C ATOM 4 O ASN B 6 4.125 6.391 6.507 1.00 14.92 O ATOM 5 CB ASN B 6 2.922 5.513 4.131 1.00 13.13 C ATOM 6 CG ASN B 6 1.798 5.250 3.160 1.00 13.77 C ATOM 7 OD1 ASN B 6 1.629 4.129 2.686 1.00 15.27 O ATOM 8 ND2 ASN B 6 1.022 6.266 2.875 1.00 11.07 N ATOM 9 N TYR B 7 4.222 4.248 7.230 1.00 15.70 N ATOM 10 CA TYR B 7 5.113 4.552 8.370 1.00 16.18 C ATOM 11 C TYR B 7 6.547 4.754 7.929 1.00 16.91 C ATOM 12 O TYR B 7 6.964 4.259 6.878 1.00 16.76 O ATOM 13 CB TYR B 7 5.042 3.449 9.417 1.00 16.35 C ATOM 14 CG TYR B 7 3.659 3.296 9.977 1.00 15.45 C ATOM 15 CD1 TYR B 7 2.756 2.398 9.402 1.00 16.68 C ATOM 16 CD2 TYR B 7 3.224 4.098 11.023 1.00 15.80 C ATOM 17 CE1 TYR B 7 1.476 2.267 9.896 1.00 14.46 C ATOM 18 CE2 TYR B 7 1.929 3.975 11.545 1.00 15.33 C ATOM 19 CZ TYR B 7 1.063 3.065 10.959 1.00 16.09 C ATOM 20 OH TYR B 7 -0.207 2.910 11.443 1.00 15.39 O ATOM 21 OXT TYR B 7 7.316 5.408 8.654 1.00 18.49 O END """ pdb_in = iotbx.pdb.hierarchy.input(pdb_string=pdb_str) xrs = pdb_in.input.xray_structure_simple() fc = abs(xrs.structure_factors(d_min=2.5).f_calc()) fc = fc.set_observation_type_xray_amplitude() sigf = flex.double(fc.size(), 0.1) + (fc.data() * 0.03) fc = fc.customized_copy(sigmas=sigf) # and now add twinning fc_twin = fc.twin_data(twin_law='-l,-k,-h', alpha=0.4) fc_twin.as_mtz_dataset( column_root_label="F").mtz_object().write("tmp_xtriage_twinned.mtz") # twin_laws laws = twin_analyses.twin_laws(miller_array=fc_twin) assert (len(laws.operators) == 7) delta_santoro = [tl.delta_santoro for tl in laws.operators] assert approx_equal( delta_santoro, [0.104655, 0.104655, 0.066599, 0.104655, 0.076113, 0.066599, 0.028542]) delta_le_page = [tl.delta_le_page for tl in laws.operators] assert approx_equal( delta_le_page, [0.053839, 0.053839, 0.053839, 0.064020, 0.044706, 0.049480, 0.021221]) delta_lebedev = [tl.delta_lebedev for tl in laws.operators] assert approx_equal( delta_lebedev, [0.000787, 0.000787, 0.000767, 0.000912, 0.000637, 0.000705, 0.000302]) # TNCS tps = twin_analyses.detect_pseudo_translations(miller_array=fc_twin, out=null_out()) assert ([tps.mod_h, tps.mod_k, tps.mod_l] == [3, 2, 3]) assert approx_equal(tps.high_peak, 47.152352) assert approx_equal(tps.high_p_value, 0.000103) # L test fc_norm_acentric = twin_analyses.wilson_normalised_intensities( miller_array=fc_twin, normalise=True, out=null_out()).acentric ltest = twin_analyses.l_test(miller_array=fc_norm_acentric, parity_h=3, parity_l=3) assert approx_equal(ltest.mean_l, 0.498974) assert approx_equal(ltest.mean_l2, 0.371674) # we need to go through the wrapper class for a lot of these... out = StringIO() tw = twin_analyses.twin_analyses(miller_array=fc_twin, out=out) tw2 = twin_analyses.twin_analyses(miller_array=fc_twin, out=out, d_hkl_for_l_test=[3, 2, 3]) # Wilson moments wm = tw.wilson_moments assert ([ wm.centric_i_ratio, wm.centric_f_ratio, wm.centric_e_sq_minus_one ] == [None, None, None]) assert approx_equal(wm.acentric_i_ratio, 2.878383) assert approx_equal(wm.acentric_f_ratio, 0.717738) assert approx_equal(wm.acentric_abs_e_sq_minus_one, 0.808899) assert (not wm.centric_present) # Overall analyses out = StringIO() tw.show(out=out) assert ("significantly different than is expected" in out.getvalue()) summary = tw.twin_summary assert approx_equal(summary.l_mean, 0.4989738) assert approx_equal(summary.patterson_height, 47.152352) for k, twin_r_factor in enumerate(summary.r_obs): if (k == 6): assert twin_r_factor < 0.11 else: assert twin_r_factor > 0.3 out2 = StringIO() tw.l_test.show(out=out2) assert ("""\ Mean |L| :0.499 (untwinned: 0.500; perfect twin: 0.375) Mean L^2 :0.372 (untwinned: 0.333; perfect twin: 0.200) """ in out2.getvalue()), out2.getvalue() out3 = StringIO() tw2.l_test.show(out=out3) assert not show_diff(out2.getvalue(), out3.getvalue()) if (verbose): print out.getvalue() # twin_results_interpretation object via cctbx.miller.array API extension # XXX I get slightly different numbers here versus running through the # twin_analyses call above - this seems to be caused by the resolution # limits passed here. Need to confirm these with PHZ. result = fc_twin.analyze_intensity_statistics() assert approx_equal(result.maha_l, 27.580674) assert approx_equal( result.r_obs, [0.514901, 0.514901, 0.397741, 0.580353, 0.579294, 0.420914, 0.114999]) assert approx_equal( result.h_alpha, [0.019980, 0.019980, 0.211788, 0.073926, 0.079920, 0.150849, 0.389610]) assert result.has_twinning()
def run(args): from iotbx.reflection_file_reader import any_reflection_file from xia2.Modules.Analysis import phil_scope interp = phil_scope.command_line_argument_interpreter() params, unhandled = interp.process_and_fetch( args, custom_processor='collect_remaining') params = params.extract() n_bins = params.resolution_bins args = unhandled intensities = None batches = None scales = None dose = None reader = any_reflection_file(args[0]) assert reader.file_type() == 'ccp4_mtz' arrays = reader.as_miller_arrays(merge_equivalents=False) for ma in arrays: if ma.info().labels == ['BATCH']: batches = ma elif ma.info().labels == ['DOSE']: dose = ma elif ma.info().labels == ['I', 'SIGI']: intensities = ma elif ma.info().labels == ['I(+)', 'SIGI(+)', 'I(-)', 'SIGI(-)']: intensities = ma elif ma.info().labels == ['SCALEUSED']: scales = ma assert intensities is not None assert batches is not None mtz_object = reader.file_content() indices = mtz_object.extract_original_index_miller_indices() intensities = intensities.customized_copy( indices=indices, info=intensities.info()) batches = batches.customized_copy(indices=indices, info=batches.info()) from iotbx import merging_statistics merging_stats = merging_statistics.dataset_statistics( intensities, n_bins=n_bins) merging_acentric = intensities.select_acentric().merge_equivalents() merging_centric = intensities.select_centric().merge_equivalents() multiplicities_acentric = {} multiplicities_centric = {} for x in sorted(set(merging_acentric.redundancies().data())): multiplicities_acentric[x] = merging_acentric.redundancies().data().count(x) for x in sorted(set(merging_centric.redundancies().data())): multiplicities_centric[x] = merging_centric.redundancies().data().count(x) headers = [u'Resolution (Å)', 'N(obs)', 'N(unique)', 'Multiplicity', 'Completeness', 'Mean(I)', 'Mean(I/sigma)', 'Rmerge', 'Rmeas', 'Rpim', 'CC1/2', 'CCano'] rows = [] for bin_stats in merging_stats.bins: row = ['%.2f - %.2f' %(bin_stats.d_max, bin_stats.d_min), bin_stats.n_obs, bin_stats.n_uniq, '%.2f' %bin_stats.mean_redundancy, '%.2f' %(100*bin_stats.completeness), '%.1f' %bin_stats.i_mean, '%.1f' %bin_stats.i_over_sigma_mean, '%.3f' %bin_stats.r_merge, '%.3f' %bin_stats.r_meas, '%.3f' %bin_stats.r_pim, '%.3f' %bin_stats.cc_one_half, '%.3f' %bin_stats.cc_anom] rows.append(row) from xia2.lib.tabulate import tabulate merging_stats_table_html = tabulate(rows, headers, tablefmt='html') merging_stats_table_html = merging_stats_table_html.replace( '<table>', '<table class="table table-hover table-condensed">') unit_cell_params = intensities.unit_cell().parameters() headers = ['', 'Overall', 'Low resolution', 'High resolution'] stats = (merging_stats.overall, merging_stats.bins[0], merging_stats.bins[-1]) rows = [ [u'Resolution (Å)'] + [ '%.2f - %.2f' %(s.d_max, s.d_min) for s in stats], ['Observations'] + ['%i' %s.n_obs for s in stats], ['Unique reflections'] + ['%i' %s.n_uniq for s in stats], ['Multiplicity'] + ['%.1f' %s.mean_redundancy for s in stats], ['Completeness'] + ['%.2f%%' %(s.completeness * 100) for s in stats], #['Mean intensity'] + ['%.1f' %s.i_mean for s in stats], ['Mean I/sigma(I)'] + ['%.1f' %s.i_over_sigma_mean for s in stats], ['Rmerge'] + ['%.3f' %s.r_merge for s in stats], ['Rmeas'] + ['%.3f' %s.r_meas for s in stats], ['Rpim'] + ['%.3f' %s.r_pim for s in stats], ['CC1/2'] + ['%.3f' %s.cc_one_half for s in stats], ] rows = [[u'<strong>%s</strong>' %r[0]] + r[1:] for r in rows] overall_stats_table_html = tabulate(rows, headers, tablefmt='html') overall_stats_table_html = overall_stats_table_html.replace( '<table>', '<table class="table table-hover table-condensed">') #headers = ['Crystal symmetry', ''] #rows = [ #[u'Unit cell: a (Å)', '%.3f' %unit_cell_params[0]], #[u'b (Å)', '%.3f' %unit_cell_params[1]], #[u'c (Å)', '%.3f' %unit_cell_params[2]], #[u'α (°)', '%.3f' %unit_cell_params[3]], #[u'β (°)', '%.3f' %unit_cell_params[4]], #[u'γ (°)', '%.3f' %unit_cell_params[5]], #['Space group', intensities.space_group_info().symbol_and_number()], #] #symmetry_table_html = tabulate(rows, headers, tablefmt='html') symmetry_table_html = """ <p> <b>Filename:</b> %s <br> <b>Unit cell:</b> %s <br> <b>Space group:</b> %s </p> """ %(os.path.abspath(reader.file_name()), intensities.space_group_info().symbol_and_number(), str(intensities.unit_cell())) if params.anomalous: intensities = intensities.as_anomalous_array() batches = batches.as_anomalous_array() from xia2.Modules.PyChef2.PyChef import remove_batch_gaps new_batch_data = remove_batch_gaps(batches.data()) new_batches = batches.customized_copy(data=new_batch_data) sc_vs_b = scales_vs_batch(scales, new_batches) rmerge_vs_b = rmerge_vs_batch(intensities, new_batches) intensities.setup_binner(n_bins=n_bins) merged_intensities = intensities.merge_equivalents().array() from mmtbx.scaling import twin_analyses normalised_intensities = twin_analyses.wilson_normalised_intensities( miller_array=merged_intensities) nz_test = twin_analyses.n_z_test( normalised_acentric=normalised_intensities.acentric, normalised_centric=normalised_intensities.centric) from mmtbx.scaling import data_statistics if not intensities.space_group().is_centric(): wilson_scaling = data_statistics.wilson_scaling( miller_array=merged_intensities, n_residues=200) # XXX default n_residues? acentric = intensities.select_acentric() centric = intensities.select_centric() if acentric.size(): acentric.setup_binner(n_bins=n_bins) second_moments_acentric = acentric.second_moment_of_intensities(use_binning=True) if centric.size(): centric.setup_binner(n_bins=n_bins) second_moments_centric = centric.second_moment_of_intensities(use_binning=True) d_star_sq_bins = [ (1/bin_stats.d_min**2) for bin_stats in merging_stats.bins] i_over_sig_i_bins = [ bin_stats.i_over_sigma_mean for bin_stats in merging_stats.bins] cc_one_half_bins = [ bin_stats.cc_one_half for bin_stats in merging_stats.bins] cc_anom_bins = [ bin_stats.cc_anom for bin_stats in merging_stats.bins] from xia2.Modules.PyChef2 import PyChef if params.chef_min_completeness: d_min = PyChef.resolution_limit( mtz_file=args[0], min_completeness=params.chef_min_completeness, n_bins=8) print 'Estimated d_min for CHEF analysis: %.2f' %d_min sel = flex.bool(intensities.size(), True) d_spacings = intensities.d_spacings().data() sel &= d_spacings >= d_min intensities = intensities.select(sel) batches = batches.select(sel) if dose is not None: dose = dose.select(sel) if dose is None: dose = PyChef.batches_to_dose(batches.data(), params.dose) else: dose = dose.data() pychef_stats = PyChef.Statistics(intensities, dose) pychef_dict = pychef_stats.to_dict() def d_star_sq_to_d_ticks(d_star_sq, nticks): from cctbx import uctbx d_spacings = uctbx.d_star_sq_as_d(flex.double(d_star_sq)) min_d_star_sq = min(d_star_sq) dstep = (max(d_star_sq) - min_d_star_sq)/nticks tickvals = list(min_d_star_sq + (i*dstep) for i in range(nticks)) ticktext = ['%.2f' %(uctbx.d_star_sq_as_d(dsq)) for dsq in tickvals] return tickvals, ticktext tickvals, ticktext = d_star_sq_to_d_ticks(d_star_sq_bins, nticks=5) tickvals_wilson, ticktext_wilson = d_star_sq_to_d_ticks( wilson_scaling.d_star_sq, nticks=5) second_moment_d_star_sq = [] if acentric.size(): second_moment_d_star_sq.extend(second_moments_acentric.binner.bin_centers(2)) if centric.size(): second_moment_d_star_sq.extend(second_moments_centric.binner.bin_centers(2)) tickvals_2nd_moment, ticktext_2nd_moment = d_star_sq_to_d_ticks( second_moment_d_star_sq, nticks=5) json_data = { 'multiplicities': { 'data': [ { 'x': multiplicities_acentric.keys(), 'y': multiplicities_acentric.values(), 'type': 'bar', 'name': 'Acentric', 'opacity': 0.75, }, { 'x': multiplicities_centric.keys(), 'y': multiplicities_centric.values(), 'type': 'bar', 'name': 'Centric', 'opacity': 0.75, }, ], 'layout': { 'title': 'Distribution of multiplicities', 'xaxis': {'title': 'Multiplicity'}, 'yaxis': { 'title': 'Frequency', #'rangemode': 'tozero' }, 'bargap': 0, 'barmode': 'overlay', }, }, 'scale_rmerge_vs_batch': { 'data': [ { 'x': sc_vs_b.batches, 'y': sc_vs_b.data, 'type': 'scatter', 'name': 'Scale', 'opacity': 0.75, }, { 'x': rmerge_vs_b.batches, 'y': rmerge_vs_b.data, 'yaxis': 'y2', 'type': 'scatter', 'name': 'Rmerge', 'opacity': 0.75, }, ], 'layout': { 'title': 'Scale and Rmerge vs batch', 'xaxis': {'title': 'N'}, 'yaxis': { 'title': 'Scale', 'rangemode': 'tozero' }, 'yaxis2': { 'title': 'Rmerge', 'overlaying': 'y', 'side': 'right', 'rangemode': 'tozero' } }, }, 'cc_one_half': { 'data': [ { 'x': d_star_sq_bins, # d_star_sq 'y': cc_one_half_bins, 'type': 'scatter', 'name': 'CC-half', }, ({ 'x': d_star_sq_bins, # d_star_sq 'y': cc_anom_bins, 'type': 'scatter', 'name': 'CC-anom', } if not intensities.space_group().is_centric() else {}), ], 'layout':{ 'title': 'CC-half vs resolution', 'xaxis': { 'title': u'Resolution (Å)', 'tickvals': tickvals, 'ticktext': ticktext, }, 'yaxis': { 'title': 'CC-half', 'range': [min(cc_one_half_bins + cc_anom_bins + [0]), 1] }, }, }, 'i_over_sig_i': { 'data': [{ 'x': d_star_sq_bins, # d_star_sq 'y': i_over_sig_i_bins, 'type': 'scatter', 'name': 'Scales vs batch', }], 'layout': { 'title': '<I/sig(I)> vs resolution', 'xaxis': { 'title': u'Resolution (Å)', 'tickvals': tickvals, 'ticktext': ticktext, }, 'yaxis': { 'title': '<I/sig(I)>', 'rangemode': 'tozero' }, } }, 'second_moments': { 'data': [ ({ 'x': list(second_moments_acentric.binner.bin_centers(2)), # d_star_sq 'y': second_moments_acentric.data[1:-1], 'type': 'scatter', 'name': '<I^2> acentric', } if acentric.size() else {}), ({ 'x': list(second_moments_centric.binner.bin_centers(2)), # d_star_sq 'y': second_moments_centric.data[1:-1], 'type': 'scatter', 'name': '<I^2> centric', } if centric.size() else {}) ], 'layout': { 'title': 'Second moment of I', 'xaxis': { 'title': u'Resolution (Å)', 'tickvals': tickvals_2nd_moment, 'ticktext': ticktext_2nd_moment, }, 'yaxis': { 'title': '<I^2>', 'rangemode': 'tozero' }, } }, 'cumulative_intensity_distribution': { 'data': [ { 'x': list(nz_test.z), 'y': list(nz_test.ac_obs), 'type': 'scatter', 'name': 'Acentric observed', 'mode': 'lines', 'line': { 'color': 'rgb(31, 119, 180)', }, }, { 'x': list(nz_test.z), 'y': list(nz_test.c_obs), 'type': 'scatter', 'name': 'Centric observed', 'mode': 'lines', 'line': { 'color': 'rgb(255, 127, 14)', }, }, { 'x': list(nz_test.z), 'y': list(nz_test.ac_untwinned), 'type': 'scatter', 'name': 'Acentric theory', 'mode': 'lines', 'line': { 'color': 'rgb(31, 119, 180)', 'dash': 'dot', }, 'opacity': 0.8, }, { 'x': list(nz_test.z), 'y': list(nz_test.c_untwinned), 'type': 'scatter', 'name': 'Centric theory', 'mode': 'lines', 'line': { 'color': 'rgb(255, 127, 14)', 'dash': 'dot', }, 'opacity': 0.8, }, ], 'layout': { 'title': 'Cumulative intensity distribution', 'xaxis': {'title': 'z'}, 'yaxis': { 'title': 'P(Z <= Z)', 'rangemode': 'tozero' }, } }, 'wilson_intensity_plot': { 'data': ([ { 'x': list(wilson_scaling.d_star_sq), 'y': list(wilson_scaling.mean_I_obs_data), 'type': 'scatter', 'name': 'Observed', }, { 'x': list(wilson_scaling.d_star_sq), 'y': list(wilson_scaling.mean_I_obs_theory), 'type': 'scatter', 'name': 'Expected', }, { 'x': list(wilson_scaling.d_star_sq), 'y': list(wilson_scaling.mean_I_normalisation), 'type': 'scatter', 'name': 'Smoothed', }] if not intensities.space_group().is_centric() else []), 'layout': { 'title': 'Wilson intensity plot', 'xaxis': { 'title': u'Resolution (Å)', 'tickvals': tickvals_wilson, 'ticktext': ticktext_wilson, }, 'yaxis': { 'type': 'log', 'title': 'Mean(I)', 'rangemode': 'tozero', }, }, }, } json_data.update(pychef_dict) from dials.report import html_report report = html_report.html_report() page_header = html_report.page_header('xia2 report') report.add_content(page_header) overall_panel = html_report.panel('Overall', 'overall', show=True) overall_table = html_report.table_responsive( overall_stats_table_html, width=800) overall_panel.add_content(overall_table) merging_stats_panel = html_report.panel('Resolution shells', 'merging_stats') merging_stats_table = html_report.table_responsive(merging_stats_table_html) merging_stats_panel.add_content(merging_stats_table) merging_stats_panel_group = html_report.panel_group( [overall_panel, merging_stats_panel]) div = html_report.div() div.add_content(html_report.raw_html('<h2>Merging statistics</h2>')) div.add_content(html_report.raw_html(symmetry_table_html)) div.add_content(merging_stats_panel_group) report.add_content(div) resolution_plots_panel = html_report.panel('Analysis by resolution', 'resolution') for graph in ('cc_one_half', 'i_over_sig_i', 'second_moments', 'wilson_intensity_plot'): resolution_plots_panel.add_content(html_report.plotly_graph( json_data[graph], graph)) batch_plots_panel = html_report.panel('Analysis by batch', 'batch') for graph in ('scale_rmerge_vs_batch', 'completeness_vs_dose', 'rcp_vs_dose', 'scp_vs_dose', 'rd_vs_batch_difference'): batch_plots_panel.add_content(html_report.plotly_graph( json_data[graph], graph)) misc_plots_panel = html_report.panel('Miscellaneous', 'misc') for graph in ('multiplicities', 'cumulative_intensity_distribution'): misc_plots_panel.add_content(html_report.plotly_graph( json_data[graph], graph)) analysis_plots_panel_group = html_report.panel_group( [resolution_plots_panel, batch_plots_panel, misc_plots_panel]) div = html_report.div() div.add_content(html_report.raw_html('<h2>Analysis plots</h2>')) div.add_content(analysis_plots_panel_group) report.add_content(div) html = report.html() import json json_str = json.dumps(json_data) with open('xia2-report.json', 'wb') as f: print >> f, json_str with open('xia2-report.html', 'wb') as f: print >> f, html.encode('ascii', 'xmlcharrefreplace') return