function AttributedPlotHtml(Dim2Data,ImageName,Crux)
%DynamicPlotSource - Creates image, map and html page for attributed data.
% html page consists of title, plot, and list of sources for each
% data point on the plot
%
% Syntax: AttributedPlotHtml(Dim2Data,ImageName,Crux)
%
% Required Inputs:
% Dim2Data - Two-dimensional matrix with data to be plotted
% column 1 - x-axis
% column 2 - y-axis
%
% Optional Inputs:
% ImageName - String - title to be used for final image and htmlfile
% Crux - Object - contains properties that are used for attribution and
% style
%
% Recommended Crux Properties:
% Crux.blurbs - Array of strings with length equal to Dim2Data,
% - brief description of data source
% Crux.links - Array of strings with length equal to Dim2Data,
% - link to source of form: "http://www.google.com/"
% Crux.xlab - string with label for x-axis
% Crux.ylab - string with label for y-axis
% Crux.imagewidth - number - width of image in inches (rec:5)
% Crux.imageheight - number - height of image in inches (rec:3)
% Optional Crux Properties:
% Crux.plottitle - string title for plot
% Crux.title - string title for page
% Crux.linksx - Array of strings with length equal to Dim2Data,
% - link to source of x data (if different than y)
% - of form: "http://www.google.com/"
% Crux.slinkFormat - string for sprintf to represent y data magnitude
% - ex: '%0.0f' for '54' output from 54.367 input
% - ex: '%0.2f' for '54.36' output from 54.367 input
% Crux.slinkxFormat - string for sprintf to represent x data magnitude
% Crux.plotfun - anonymous function that defines plot
% - see help function_handle for use syntax
% - must have only two inputs, xdata and ydata
% Example
% Crux.plotfun = @(xx,yy) plot(xx,yy,'.','MarkerSize',13);
%
%
% Outputs:
% 1) generates png file of data plot with name: ImageName.png
% 2) generates html file with plot and attributions: ImageName.html
% 3) generates txt file with html code of image and map: ImageName.txt
%
% Example:
% Dim2Data = [10 2004;
% 11 2005;
% 12 2006];
% ImageName = 'AttributedData';
% Crux -- Example properties for Crux are listed in the nargin<1 section
% below
%
% Other m-files required: none
% Subfunctions: none
% MAT-files required: none
% Hardware: none
%
% OS & MatLab version control
% tested and developed on: Windows 7 & MatLab 2012b
%
% See also: OTHER_FUNCTION_NAME1, OTHER_FUNCTION_NAME2
% Author: Emily Alden
% March 2013; Last revision: 05-March-2013
%------------- BEGIN CODE --------------
%% Check Input Data
% sanitize and fill in excluded optional elements
if nargin < 1
Dim2Data = [2000 11;
2001 13;
2001.3 8;
2005 5;
2008.2 2];
Crux.xlab = 'Time [years]';
Crux.ylab = 'Data [units]';
end
%Confirm Two-dimensional input
datasize = size(Dim2Data);
if length(datasize) ~= 2,
error('Choose 2D data set to plot.')
end
if sum(datasize==2)<1,
error(['Two dimensions of data required. Your data matrix has size: ['...
num2str(datasize) ']. One dimension should be 2.']);
end
if datasize(2) ~=2, Dim2Data = Dim2Data';end
%detemine number of data points in source
lenData = size(Dim2Data,1);
%create an array of tags for mouseover reference
refs = cell(lenData,1);
for ii = 1:lenData
if lenData>9
%adds leading zeros as needed to distinguish ref1 from ref11
order = floor(log(abs(lenData))./log(10));
oformat = ['ref%0' num2str(order+1) 'd'];
refs{ii} = sprintf(oformat,ii);
else
refs{ii} = sprintf('ref%d',ii);
end
end
if nargin < 2
ImageName = 'AttributedData';
end
% Crux - the source and formatting info for the attributed data plot
if nargin < 3
Crux.title = 'Attributed Data';
end
%CruxElect = fieldnames(Crux);
%% Input Audit - The Optional Crux Object
if ~isfield(Crux,'title')||~ischar(Crux.title)
Crux.title = '';
end
if ~isfield(Crux,'blurbs')
blurbs = cell(lenData,1);
for ii = 1:lenData
blurbs{ii} = sprintf('blurb%d a brief detail about the data',ii);
end
Crux.blurbs = blurbs;
elseif length(Crux.blurbs) < lenData;
disp 'Insufficient number of blurbs, using generic blurb#'
for ii = length(Crux.blurbs)+1:lenData
Crux.blurbs{ii} = sprintf('blurb%d a brief comment about the data point',ii);
end
end
if ~isfield(Crux,'links')
links = cell(lenData,1);
for ii = 1:lenData
links{ii} = sprintf('http://www.google.com/search?q=%d',ii);
end
Crux.links = links;
elseif length(Crux.links) < lenData;
disp 'Insufficient number of links, using generic link'
for ii = length(Crux.links)+1:lenData
Crux.links{ii} = sprintf('http://www.google.com/search?q=%d',ii);
end
end
if ~isfield(Crux,'xlab')
Crux.xlab = '';
end
if ~isfield(Crux,'ylab')
Crux.ylab = '';
end
if ~isfield(Crux,'imagewidth')
Crux.imagewidth = 5;
end
if Crux.imagewidth > 13
disp 'are you sure you want your final picture to be more than 13" wide? Please input the width in inches'
end
if ~isfield(Crux,'imageheight')
Crux.imageheight = 2;
end
if ~isfield(Crux,'plottitle')
Crux.plottitle = '';
end
%format of x data links text
if ~isfield(Crux,'slinkFormat')
Crux.slinkFormat = '%0.2f';
end
%format of y data links text
if ~isfield(Crux,'slinkxFormat')
Crux.slinkxFormat = '%0.2f';
end
%plot function style, default is basic MatLab plot
% tests to make sure input exists, is a function, and has two input
% arguments (AttributedPlotHtml.m will only execute this function with two
% input arguments (both vectors):xdata and ydata.
if ~isfield(Crux,'plotfun')||~isa(Crux.plotfun,'function_handle')||nargin(Crux.plotfun)<2
Crux.plotfun = @(xx,yy) plot(xx,yy,'.','MarkerSize',13);
% Examples of other plot functions
% %% line plot
% Crux.plotfun = @(xx,yy) line(xx(:),yy(:),'Marker','.','MarkerSize',13);
% %% errorbar plot
% yyunc = 0.3.*ones(lenData,1);
% Crux.plotfun = @(xx,yy) errorbar(xx(:),yy(:),yyunc,'.');
end
%build the html link syntax
s1 = '<a href="';
s2 = '" target="_blank">'; %opens link in new tab/window
%s2 = '">'; %To open link in same tab/window, uncomment here
s3 = '</a>';
htmllinks = cell(lenData,1);
for iMkLink = 1:lenData
ylink = [s1 Crux.links{iMkLink} s2 sprintf(Crux.slinkFormat,Dim2Data(iMkLink,2)) s3];
if isfield(Crux,'linksx')
% if there is an x source link,
xlink = ['  ' s1 Crux.linksx{iMkLink} s2 sprintf(Crux.slinkxFormat,Dim2Data(iMkLink,1)) s3];
else
xlink = ['  ' sprintf(Crux.slinkxFormat,Dim2Data(iMkLink,1))];
end
htmllinks{iMkLink} = ['(' xlink ' , ' ylink ' )'];
end
%% Plot Function
%sets the font size of the plot labels
fontsz = 6;
%sets the click radius (in pixels) of the html imagemap
clickrad = 10;
fWidthIn = Crux.imagewidth;
fHeightIn = Crux.imageheight;
%300dpi is the ultimate, high resolution image, but we use 150dpi ratios
%for screen display during the execution of this code and to define the
%pixel size displayed in the final html page
resDPI = 300;
dispPix = 150;
fWidthPix = fWidthIn*dispPix;
fHeightPix = fHeightIn*dispPix;
h = figure(137);
clf;
units = 'Pixels';
fig_handle = gcf;
set(fig_handle,'units',units);
start_fig = get(fig_handle,'position');
set(fig_handle,'position',[start_fig(1), start_fig(2), fWidthPix, fHeightPix]);
%make the figure's print dimensions match the desired size for file saving
save_screenDPI = get(0,'ScreenPixelsPerInch');
set(0,'ScreenPixelsPerInch',dispPix);
%DELME get(0,'ScreenPixelsPerInch')
set(gcf,'PaperUnits','inches','PaperPosition',[0 0 fWidthIn fHeightIn])
% pull the data for plotting
xx = Dim2Data(:,1);
yy = Dim2Data(:,2);
Crux.plotfun(xx,yy)
xlabel(Crux.xlab,'fontsize',fontsz)
ylabel(Crux.ylab,'fontsize',fontsz)
title(Crux.plottitle,'fontsize',fontsz)
set(gca, 'fontsize', fontsz)
%save the figure to a png file
ImageFile = [ImageName '.png'];
print(h,'-dpng',ImageFile,['-r' num2str(resDPI)])
%% Create Image Map -- find the pixel locations of the data in the figure
%The following code is derived from adam@bigbro.biophys.cornell.edu
%(Adam C. Finnefrock)
%http://www.mathworks.com/matlabcentral/newsreader/view_thread/12571
units = 'Pixels';
%Axes locations
axes_handle = gca;
xlim = get(axes_handle, 'XLim');
ylim = get(axes_handle, 'YLim');
save_axes_units = get(axes_handle, 'Units');
set(axes_handle, 'Units', units);
axes_position_in_units = get(axes_handle,'Position');
set(axes_handle, 'Units', save_axes_units)
originx = xlim(1);
originy = ylim(1);
cornerx = xlim(2);
cornery = ylim(2);
scalex = cornerx-originx;
scaley = cornery-originy;
normalized_position(:,1) = (Dim2Data(:,1) - originx) ./ scalex;
normalized_position(:,2) = (Dim2Data(:,2) - originy) ./ scaley;
unitsoriginx = axes_position_in_units(1)-1;
unitsoriginy = axes_position_in_units(2);
unitsscalex = axes_position_in_units(3);
unitsscaley = axes_position_in_units(4);
% %% Create Pixel Map of PNG with respect to data points
% xdata
TheMAP(:,1) = (normalized_position(:,1) .* unitsscalex) + unitsoriginx;
% ydata
% html imagemaps start from the top, so location is total height - position
TheMAP(:,2) = fHeightPix-((normalized_position(:,2) .* unitsscaley) + unitsoriginy)+1;
TheMAP = round(TheMAP);
%restore screen DPI
set(0,'ScreenPixelsPerInch',save_screenDPI);
%% Create HTML file
% %% Create html header
filename = [ImageName '.html'];
%using 'w' here allows me to overwrite possible pre-existing file
fid = fopen(filename,'w');
fprintf(fid,'%s',['<!DOCTYPE html><html><head><title>' ImageName '</title></head><body>']);
fclose(fid);
fid = fopen(filename,'a');
% %% Write javascript for imagemap highlighting and html style
%When the users mouseover the image with image-map links, the links trigger
%the javascript. The links have syntax 'ref1', 'ref2', etc....
%The javascript function first renders the background of every link as
%white, then it pick the clicked link and highlights its background.
%read the clicked link (text)
fprintf(fid,'%s\r\n','<SCRIPT>');
fprintf(fid,'%s\r\n',' function highlight(text){');
fprintf(fid,'%s\r\n','var txt = "tag"+text;');
%write all the blurbs and links background as white
for ii = 1:lenData
fprintf(fid,'%s\r\n',['document.getElementById(''','tag' refs{ii} '''',').style.backgroundColor = "white";']);
end
%write the chosen link's background as grey
fprintf(fid,'%s\r\n',' document.getElementById(txt).style.backgroundColor = "#bbbbcc"}');
%close java script code
fprintf(fid,'%s\r\n','</SCRIPT><style>');
%add style to html page (indent)
%<div> are the source list elements
fprintf(fid,'%s\r\n','div {margin-left:2cm;width:800px}');
%<h1> is the title
fprintf(fid,'%s\r\n','h1 {margin-left:2cm;width:800px}');
%<p> is the image
fprintf(fid,'%s\r\n','p {margin-left:2cm;}</style>');
% %% write html to display image & imagemap
fprintf(fid,'%s\r\n',['<h1>' Crux.title '</h1>']);
%display image in <p> element
fprintf(fid,'%s\r\n',['<p><img src="' ImageFile '" width="' num2str(fWidthPix) '" height="' num2str(fHeightPix) '" usemap="#' ImageName '"></p>']);
%space to make html more pleasing
fprintf(fid,'%s\r\n', '');
%write the imagemap
fprintf(fid,'%s\r\n',['<map name="' ImageName '">']);
%insert imagemap elements for each datapoint
for ii = 1:lenData
fprintf(fid,'%s\r\n',['<area shape="circle" coords="' num2str(TheMAP(ii,1)) ',' num2str(TheMAP(ii,2)) ',' num2str(clickrad) '" href="' Crux.links{ii} '" target="_blank" onMouseOver="highlight(''', refs{ii} '''',')" >']);
end
fprintf(fid,'%s\r\n','</map>');
% %% display list of attributed data references
% these occupy <div> elements, each with an id of syntax ['tag' refs{ii}]
% e.g. id="tagref1"
for ii = 1:lenData
fprintf(fid,'%s\r\n',['<div id="tag' refs{ii} '"> ' htmllinks{ii} ' ' Crux.blurbs{ii} ' </div>']);
end
% %% html footer
%close out the html page nicely
formatOut = 'mm/dd/yy';
fprintf(fid,'%s\r\n',['</br></br><hr><footer><div>This page was created on: ' datestr(now,formatOut) '</div></footer>']);
fprintf(fid,'%s\r\n',['</body>' '</html>']);
% %% close the html file just written
fclose(fid);
%% Create README txt file with only the imagemap html
txtfilename = ['README_' ImageName '.txt'];
%using 'w' here allows me to overwrite possible pre-existing file
tid = fopen(txtfilename,'w');
fprintf(tid,'%s\n','Instructions for using the outputs of AttributedPlotHtml');
fclose(tid);
% %% General instructions in README file
tid = fopen(txtfilename,'a');
fprintf(tid,'%s\r\n', '');
fprintf(tid,'%s\r\n', 'Your Unique Outputs:');
fprintf(tid,'%s\r\n', [' ' ImageFile]);
fprintf(tid,'%s\r\n', ' - a png file with the MatLab figure in png format with mapped pixels');
fprintf(tid,'%s\r\n', [' ' filename]);
fprintf(tid,'%s\r\n', [' - an html file with ' ImageFile ' displayed along with an active']);
fprintf(tid,'%s\r\n', ' imagemap that points to a list of sources with links.');
fprintf(tid,'%s\r\n', '');
fprintf(tid,'%s\r\n', '');
fprintf(tid,'%s\r\n', 'Instructions:');
fprintf(tid,'%s\r\n', [' - copy the two output files (' ImageFile ' & ' filename ')']);
fprintf(tid,'%s\r\n', ' into the same folder on your website. ');
fprintf(tid,'%s\r\n', [' When you open the new page (' filename ') it will display your']);
fprintf(tid,'%s\r\n', ' image with an active imagemap. You can preview it directly ');...
fprintf(tid,'%s\r\n', ' from MatLab by right-clicking the mouse and');
fprintf(tid,'%s\r\n', ' selecting ''Open outside MatLab''.');
fprintf(tid,'%s\r\n', '');
fprintf(tid,'%s\r\n', '');
fprintf(tid,'%s\r\n', ' If you want to manipulate the image and image map yourself,');
fprintf(tid,'%s\r\n', ' here is the html code for displaying the image <img>');
fprintf(tid,'%s\r\n', ' and the html code for the imagemap <map>.');
fprintf(tid,'%s\r\n', [' You must still copy the image file: ' ImageFile ' into your page`s folder.']);
fprintf(tid,'%s\r\n', '');
fprintf(tid,'%s\r\n', 'HTML code:');
fprintf(tid,'%s\r\n', '');
% %% html code to display image & imagemap
%display image in <p> element
fprintf(tid,'%s\r\n',['<p><img src="' ImageFile '" width="' num2str(fWidthPix) '" height="' num2str(fHeightPix) '" usemap="#' ImageName '"></p>']);
%space to make html more pleasing
fprintf(tid,'%s\r\n', '');
%write the imagemap
fprintf(tid,'%s\r\n',['<map name="' ImageName '">']);
%insert imagemap elements for each datapoint
for ii = 1:lenData
fprintf(tid,'%s\r\n',['<area shape="circle" coords="' num2str(TheMAP(ii,1)) ',' num2str(TheMAP(ii,2)) ',' num2str(clickrad) '" href="' Crux.links{ii} '" alt="">']);
end
fprintf(tid,'%s\r\n','</map>');
fclose(tid);
%------------- END OF CODE --------------
end