Skip to content

Instantly share code, notes, and snippets.

@coronin
Last active August 29, 2015 14:12
Show Gist options
  • Save coronin/5f62753a8978460680a7 to your computer and use it in GitHub Desktop.
Save coronin/5f62753a8978460680a7 to your computer and use it in GitHub Desktop.
for parsing micro-manager metadata
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>MM Metadata Viewer</title>
<style type="text/css" media="screen"><!--
body{margin:25px;padding:0;font-family:Arial,Helvetica,sans-serif;font-size:100%}
article,aside,figcaption,figure,footer,header,hgroup,nav,section{display:block}
h1,h2,h3,h4{font-weight:700}
h1{font-size:2em}
h2{font-size:1.5em}
h3{font-size:1.2em}
h4{font-size:1em}
a{text-decoration:underline}
a:link{color:#00E}
a:visited{color:#551A8B}
a:active{color:#E00}
a:active,a:hover{outline:0}
a img{border:none}
sub,sup{line-height:0}
--></style>
<link rel="stylesheet" href="jsontree.css"><!-- from https://github.com/jurka/jsontree -->
</head>
<body>
<h1>Micro-Manager Metadata Viewer <sup style="color:purple">&nbsp;&copy; Liang Cai</sup></h1>
<p>
<span id="action_area"><input type="file" id="fileInput" /> <input type="submit" value="view" id="view" /></span>
<span style="float:right;font-size:0.75em">Last updated on <script language="JavaScript" type="">document.write(document.lastModified)</script></span>
</p>
<div id="jsondata"><span style="color:red;background:yellow">For file size over 4M, do run it inside Chrome on a powerful computer.</span></div>
</body>
<script src="jquery-2.1.3.min.js"></script>
<script>window.jQuery || document.write('<script src="jquery-2.1.3.min.js"><\/script>')</script>
<script>
var DEBUG = false, mm_file, mm_html, mm_frames, timer_start,
NonShowKeys = ['UUID',
'UserName',
'Date',
'MetadataVersion',
'MicroManagerVersion',
'ROI',
'Prefix',
'Source',
'ComputerName',
'KeepShutterOpenChannels',
'KeepShutterOpenSlices',
'ChContrastMax',
'Directory',
'-TransposeMirrorX',
'-TransposeMirrorY',
'-TransposeXY',
'-Description',
'-Name',
'-Model',
'-Mode',
'-Initialize',
'-FocusWheel',
'-PixelType',
'-AnswerTimeout',
'-FanMode',
'-DelayBetweenCharsMs',
'-State',
'-Trigger',
'-Parity',
'-Verbose',
'-StopBits',
'-BaudRate',
'-Advanced | Snap Image Additional Delay (ms)',
'-VerticalClockVoltage',
'-SearchRange',
'-TransposeCorrection',
'-Camera',
'Core-SLM',
'-Delay_ms',
'-Handshaking',
'-FarLimit',
'-NearLimit',
'-Region of Interest',
'-OptAcquireMode',
'-OptAcquireMode Description',
'-1. Camera Information : | Type | Model | Serial No. |',
'-2. Camera Information : | Type | Model | Serial No. |',
'-DataBits',
'-FocusSensitivity',
'-TimeOut',
'Core-Galvo',
'Core-Focus',
'-Port',
'-Shutter Closing Time',
'-Shutter Opening Time',
'LightPath-Label',
'-KeepCleanTime',
'-Shutter TTL Value',
'-MaxSpeed',
'-VerticalSpeed',
'-CoolerMode',
'-NDSetting',
'-CCDTemperature',
'-CCDTemperatureSetPoint',
'SimpleAutofocus-',
'-ReadoutMode',
'-EMSwitch',
'-Busy',
'-Speed',
'-BaselineClamp',
'-Isolated Crop Mode',
'Core-ChannelGroup',
'Core-AutoShutter',
'Core-XYStage',
'-Shutter',
'-TimeoutMs',
'-FrameTransfer Help',
'-Voltage',
'-ActualInterval-ms',
'-SCurve',
'-StepSizeX_um',
'-StepSizeY_um',
'-Control',
'-Controller Info',
'InitialPositionList',
'Depth',
'PixelType',
'BitDepth',
'ChContrastMin',
'Width',
'Height',
'PixelAspect',
'IJType',
'GridRow',
'Comment',
'GridColumn',
'PixelSize_um',
'-ClosedPosition',
'-Exposure',
'-CCDTemperature Help',
'-FrameTransfer',
'OlympusHub-Version',
'Core-ImageProcessor',
'-Gain',
'-Pre-Amp-Gain',
'CustomIntervals_ms',
'ChColors',
'SlicePosition',
'AxisPositions',
'-ObjectiveTypeSetting',
'-Acceleration',
'PixelSizeUm',
'Binning',
'-ReadoutTime',
'-Advanced | Snap Image Timing Mode',
'-Binning',
'ElapsedTime-ms',
'Core-AutoFocus',
'-ContinuousMode',
'-Offset',
'Camera',
'-AD_Converter',
'-CountConvertWavelength',
'-Shutter (External)',
'-Shutter (Internal)',
'-SpuriousNoiseFilterThreshold',
'Interval_ms',
'XPositionUm',
'YPositionUm',
'Positions',
'PositionIndex',
'-CountConvert',
'-SpuriousNoiseFilterDescription',
'-SpuriousNoiseFilter',
'Slice',
'NextFrame',
'Frame',
'ChannelIndex',
'TransmittedLamp-Label',
'WaitInterval',
'-Position',
'CameraChannelIndex',
'-PiezoRange',
'-PiezoPosition',
'-Output_Amplifier',
'-CameraName',
'-TriggerMode',
'-SensorTemperature',
'-PixelReadoutRate',
'-CameraID',
'-PixelEncoding',
'-Overlap',
'-CurrentSoftware',
'-FanSpeed',
'-AccumulateCount',
'-CameraModel',
'-Sensitivity/DynamicRange',
'-TemperatureControl',
'-AuxiliaryOutSource (TTL I/O)',
'-FrameRateLimits',
'-SensorCooling',
'-CameraFirmware',
'-TemperatureStatus',
'-Ext (Exp) Trigger Timeout[ms]'
],
HighlightKeys = ['Slices',
'Frames',
'Channels'
];
function check_obj(obj, parent_obj, keyNameClean) {
var keyNamePos = 0;
if (keyNameClean.indexOf('10-3') === 0) {
keyNamePos = keyNameClean.replace('10-3', '10~3').indexOf('-');
} else if (keyNameClean.indexOf('Wheel-A') === 0) {
keyNamePos = keyNameClean.replace('Wheel-A', 'Wheel~A').indexOf('-');
} else {
keyNamePos = keyNameClean.indexOf('-');
}
if (keyNameClean === 'Slices' && typeof obj[keyNameClean] === 'number' && obj[keyNameClean] > 1) {
HighlightKeys.push('z-step_um'); // only works, if Slices preceeds z-step_um
HighlightKeys.push('SliceIndex');
HighlightKeys.push('ZPositionUm');
} else if (keyNameClean === 'Frames' && typeof obj[keyNameClean] === 'number' && obj[keyNameClean] > 1) {
HighlightKeys.push('FrameIndex');
} else if (keyNameClean === 'Channels' && typeof obj[keyNameClean] === 'number' && obj[keyNameClean] > 1) {
HighlightKeys.push('Channel');
}
if ( HighlightKeys.indexOf(keyNameClean) > -1 ) {
return 2;
}
if ( NonShowKeys.indexOf(keyNameClean) > -1 ||
(keyNamePos > -1 && NonShowKeys.indexOf( keyNameClean.substr(keyNamePos) ) > -1) ||
(keyNamePos > -1 && NonShowKeys.indexOf( keyNameClean.substr(0, keyNamePos+1) ) > -1)
) {
DEBUG && console.log(keyNameClean);
return 0;
}
if (keyNameClean.indexOf('AndorLaserCombiner-') === 0) {
DEBUG && console.log(keyNameClean);
return 0;
}
if (keyNameClean.indexOf('CSUX-') === 0) {
DEBUG && console.log(keyNameClean);
return 0;
}
if (obj[keyNameClean] === null) {
DEBUG && console.log(keyNameClean);
return 0;
}
if (keyNameClean === 'Summary') {
var ele_fourUpID = parent_obj.parent().parent().parent().attr('id');
if (!ele_fourUpID) {
return 0;
} else if (ele_fourUpID === 'jsondata') {
return 2;
}
}
if (typeof obj[keyNameClean] === 'string' && obj[keyNameClean] === 'Default' && !parent_obj.hasClass('array')) {
DEBUG && console.log(keyNameClean);
return 0;
}
if (keyNameClean.indexOf('FrameKey-') === 0) {
return 9;
}
return 1;
}
function update_timer() {
setTimeout(function () {
$('#text_timer').text( 'time spent: ' + Math.round(100*(performance.now()-timer_start))/100 + 'ms' );
}, 10);
}
function jsontree_render(obj, parent_obj) {
var key, node_state, highLight, coma, aroval,
ic = 0,
count = 0,
key_array = new Array( obj.length );
for (key in obj) {
if (!key || !obj.hasOwnProperty(key)) {
continue;
}
key_array[count] = key;
count += 1;
}
for (ic; ic < count; ic += 1) {
key = key_array[ic];
node_state = check_obj(obj, parent_obj, key);
highLight = '';
coma = '';
if (ic < count-1) {
coma = ',';
}
if (!node_state) {
continue;
} else if (node_state === 2) {
highLight = ' style="background:cyan"';
}
if (obj[key] === null) {
mm_html.push('<li><span class="key"'+highLight+'>'+key+':</span><span class="null"> null </span>'+coma+'</li>');
} else if (typeof obj[key] === 'boolean') {
mm_html.push('<li><span class="key"'+highLight+'>'+key+':</span><span class="boolean">'+obj[key]+'</span>'+coma+'</li>');
} else if (typeof obj[key] === 'number') {
mm_html.push('<li><span class="key"'+highLight+'>'+key+':</span><span class="number">'+obj[key]+'</span>'+coma+'</li>');
} else if (typeof obj[key] === 'string') {
mm_html.push('<li><span class="key"'+highLight+'>'+key+':</span><span class="string">"'+obj[key]+'"</span>'+coma+'</li>');
} else if ( $.isArray(obj[key]) ) {
aroval = Math.round( 1000*performance.now() );
mm_html.push('<li><span class="key"'+highLight+'>'+key+':</span><span class="fold">[</span><ul class="array" id="ul'+aroval+'"></ul><span>]</span>'+coma+'</li>');
parent_obj.append( mm_html.join('') );
mm_html = [];
jsontree_render(obj[key], $('#ul'+aroval));
} else {
aroval = Math.round( 1000*performance.now() );
if (node_state === 9) {
mm_frames.push(aroval);
}
mm_html.push('<li><span class="key"'+highLight+'>'+key+':</span><span class="fold" id="span'+aroval+'">{</span><ul class="object" id="ul'+aroval+'"></ul><span>}</span>'+coma+'</li>');
parent_obj.append( mm_html.join('') );
mm_html = [];
jsontree_render(obj[key], $('#ul'+aroval));
}
}
if (mm_html.length > 0) {
parent_obj.append( mm_html.join('') );
mm_html = [];
}
update_timer();
return ic;
}
function receivedText() {
console.timeEnd('load');
update_timer();
$('#jsondata').html('');
mm_frames = [];
try {
console.time('parse');
var mm_json = $.parseJSON( mm_file.result );
console.timeEnd('parse');
update_timer();
console.time('paint');
// inspired by jsontree.js
$('#jsondata').append('<ul class="jsontree"></ul>');
mm_html = [];
jsontree_render([mm_json], $('#jsondata ul.jsontree'));
console.timeEnd('paint');
update_timer();
console.time('animate');
$(document).on('click', 'ul.jsontree span.fold', function (event) {
$(this).addClass('folded').next().slideUp();
event.preventDefault();
});
$(document).on('click', 'ul.jsontree span.fold.folded', function (event) {
$(this).removeClass('folded').next().slideDown();
event.preventDefault();
});
var a_frame = null;
while (mm_frames.length > 0) {
a_frame = mm_frames.shift();
$('#span'+a_frame).addClass('folded');
$('#ul'+a_frame).css({'display': 'none'});
}
console.timeEnd('animate');
update_timer();
$('#text_timer').css({'color': 'blue'});
} catch (err) {
$('#jsondata').text(mm_file.result);
alert(err);
}
return;
}
function upload_file(file_element) {
if ( !file_element.files ) {
alert('This browser does not seem to support the "files" property.');
} else if ( !file_element.files[0] ) {
alert('Please select a file before clicking "view"');
} else {
console.time('load');
var fi = file_element.files[0];
DEBUG && console.log(fi.name);
$('#action_area').html(fi.name + '<span style="color:green;padding-left:2em;font-size:0.8em" id="text_timer">...</span>');
mm_file = new FileReader();
mm_file.onload = receivedText;
mm_file.readAsText(fi);
}
return;
}
$(document).ready(function () {
$('#view').on('click', function (event) {
if (!window.File || !window.FileReader || !window.FileList || !window.Blob) {
alert('The File APIs are not fully supported in this browser.');
return false;
}
timer_start = performance.now();
upload_file( document.getElementById('fileInput') );
event.preventDefault();
});
});
</script>
</html>
@coronin
Copy link
Author

coronin commented Dec 28, 2014

ready for public preview

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment