function tutorial_plot2svg_beta % First, let's look at the temperature in Germany depending on the month % (averaged 1961-1990, source http://de.wikipedia.org/wiki/Klima) name={'Januar','Februar','March','April','May','June','July','August','September','Oktober','November','December'}; avgT =[-0.5 0.5 3.7 7.6 12.2 15.5 17.1 16.9 13.8 9.4 4.2 0.9]; minT =[-3.0 -2.5 0.0 3.0 7.3 10.6 12.3 12.0 9.3 5.7 1.6 -1.5]; maxT =[ 2.0 3.4 7.5 12.1 17.2 20.4 22.0 21.9 18.4 13.1 6.9 3.2]; % Draw a new figure and set the default values for the text font fig = figure; set(fig,'DefaultAxesFontName','Arial') set(fig,'DefaultAxesFontSize', 16) % Let's plot the data h = plot( 1:12, maxT, 1:12, avgT, 1:12, minT); % Now we change the XTickLabels set(gca, 'XTick', 1:12); set(gca, 'XTickLabel', name); % We change the LineWidth ... set(h(2), 'LineWidth', 12); set(h([1 3]), 'LineWidth', 8); set(gca, 'LineWidth', 2); % ... and add a legend [h1,h2] = legend(h, {'Max T', 'Avg T', 'Min T'}); % Next we add a title, ylabel, grid, box on title('Temperature in Germany (1961-1990)'); ylabel('T [°C]'); grid on box on axis([1 12 -5 25]) % Up to here we have created a standard Matlab figure. % We create a svg plot as reference plot2svg_beta('temperature_standard.svg'); % Let's improve first the x-axis. The labels overlap. This doesn't look % nice. Unfortunately, the tickmark labels do not have the same Matlab % properties as standard text. Therfore, it is not possible to rotate them. setting.svg.XTickLabelAngle = -40; set(gca, 'UserData', setting); % Just turning the labels won't help, as they would be cut at the bottom. % Therfore, we shift the axes position up. set(gca, 'Position', [0.13 0.21 0.720 0.715]); % Now let's beautify the plot by adding some light and shadow drop_shadow_lighting(h); drop_shadow_lighting(h2(2:end)); plot2svg_beta('temperature_nicer.svg'); % But, this is not enough. To make it perfect we replace the line color by % a background pixel image (1px x 50px). This pixel image is scaled to cover % the whole axes region. colors = reshape(flipud(jet(50)),[50 1 3]); imwrite(colors, 'gradient.png', 'png') % To add the pixel image the used filter chain is modified. drop_shadow_lighting_background(h, 'gradient.png'); drop_shadow_lighting_background(h2(2:end), 'gradient.png'); plot2svg_beta('temperature_perfect.svg'); % Filters are a very powerful feature of SVG. Unfortunately, not all SVG % render tools give full support. The best browser for SVG filters at the % moment seems to be Opera directly followed by Firefox. For Inkscape I had % to add a workaround in the plot2svg as it does not correctly handle % feImage filters. IE + RENESIS will not work as it does not support % filters. IE + Adobe may work, but is not tested. The Safari browser may % also fully support filters (not tested). function drop_shadow_lighting(s) % Draws a shadow and adds light effects. % PRELIMINARY IMPLEMENTATION (Parameters may change) % Parameters: % s : Array of plot object handles svgBoundingBox(s, 'axes', 12, 'off'); svgGaussianBlur(s, 'SourceAlpha', 2, 'blur'); svgSpecularLightingDistant(s, 'blur', 1, 16, 2, 225, 45, 'lighting') svgComposite(s, 'lighting', 'SourceGraphic', 'atop', 'obj'); svgGaussianBlur(s, 'SourceAlpha', 5, 'blur2'); svgOffset(s, 'blur2', [8 7], 'shade'); svgComposite(s, 'obj', 'shade', 'over', 'final'); function drop_shadow_lighting_background(s, background) % Draws a shadow and adds light effects. The edge and face color of the % elements is replaced by a background pixel graphic that is scaled to % cover the axes % PRELIMINARY IMPLEMENTATION (Parameters may change) % Parameters: % s : Array of plot object handles svgBoundingBox(s, 'axes', 12, 'off'); svgGaussianBlur(s, 'SourceAlpha', 2, 'blur'); svgSpecularLightingDistant(s, 'blur', 1, 16, 2, 225, 45, 'lighting') svgImage(s, background, 'none', 'pic'); svgComposite(s, 'pic', 'SourceGraphic', 'atop', 'cut_pic'); svgComposite(s, 'lighting', 'cut_pic', 'atop', 'obj'); svgGaussianBlur(s, 'SourceAlpha', 5, 'blur2'); svgOffset(s, 'blur2', [8 7], 'shade'); svgComposite(s, 'obj', 'shade', 'over', 'final'); function svgBoundingBox(s, type, overlap, visible) % Configures the bounding box of a SVG filter % PRELIMINARY IMPLEMENTATION (Parameters may change) % Parameters: % s : Array of plot object handles % type : [axes, element, relative] % Sets the filter bounding box to cover the axis reagion (axes), the % element extension (element or relative). Axes gives usually the % best results but may be slower. % overlap : Many filters need an overlap to work correctly. % Typical values for type 'axes' and 'element' -> 10 % Typical values for type 'relative' -> 0.1 % visible : Debugging functionality to see the bounding box used for an % object for i = 1:length(s) userdata = get(s(i),'UserData'); userdata.svg.BoundingBox.Visible = visible; % Useful for debugging of bounding box for filters userdata.svg.BoundingBox.Type = type; % [axes, element, relative] userdata.svg.BoundingBox.Overlap = overlap; set(s(i),'UserData', userdata); end function svgSpecularLightingDistant(s, source, specularConstant, specularExponent, surfaceScale, azimuth, elevation, result) % Adds a feSpecularLighting SVG filter with distant light source % PRELIMINARY IMPLEMENTATION (Parameters may change) % Parameters: % s : Array of plot object handles % source : Any previous defined filter result string, 'SourceGraphic', % or 'SourceAlpha'. % specularConstant : Specular constant % specularExponent : Specular exponent % surfaceScale : Surface scaling factor % azimuth : Light azimuth angle [deg], typical 225. % elevation : Light elevation angle [deg], typical 45. % result : String that identifies the filter result for following filter % stages. for i = 1:length(s) userdata = get(s(i),'UserData'); if isfield(userdata, 'svg') && isfield(userdata.svg, 'Filter') next = length(userdata.svg.Filter) + 1; else next = 1; end userdata.svg.Filter(next).Subfilter.Type = 'feSpecularLighting'; userdata.svg.Filter(next).Subfilter.Source = source; userdata.svg.Filter(next).Subfilter.Result = result; userdata.svg.Filter(next).Subfilter.SpecularConstant = specularConstant; userdata.svg.Filter(next).Subfilter.SpecularExponent = specularExponent; userdata.svg.Filter(next).Subfilter.SurfaceScale = surfaceScale; userdata.svg.Filter(next).Subfilter.LightType = 'feDistantLight'; userdata.svg.Filter(next).Subfilter.Azimuth = azimuth; userdata.svg.Filter(next).Subfilter.Elevation = elevation; set(s(i),'UserData', userdata); end function svgImage(s, file, aspectRatio, result) % Adds a feImage SVG filter % PRELIMINARY IMPLEMENTATION (Parameters may change) % Parameters: % s : Array of plot object handles % file : Pixel graphics file name (png or jpeg) with extension. % aspectRatio: 'none' -> scale to bounding box limits % 'xMinYMin meet', 'xMinYMin slice', 'xMidYMid meet', ... % -> see SVG 1.1 specification % result : String that identifies the filter result for following filter % stages. for i = 1:length(s) userdata = get(s(i),'UserData'); if isfield(userdata, 'svg') && isfield(userdata.svg, 'Filter') next = length(userdata.svg.Filter) + 1; else next = 1; end userdata.svg.Filter(next).Subfilter.Type = 'feImage'; userdata.svg.Filter(next).Subfilter.File = file; userdata.svg.Filter(next).Subfilter.AspectRatio = aspectRatio; userdata.svg.Filter(next).Subfilter.Result = result; set(s(i),'UserData', userdata); end function svgGaussianBlur(s, source, deviation, result) % Adds a feGaussianBlur SVG filter % PRELIMINARY IMPLEMENTATION (Parameters may change) % Parameters: % s : Array of plot object handles % source : Any previous defined filter result string, 'SourceGraphic', % or 'SourceAlpha'. % deviation : Blur strength % result : String that identifies the filter result for following filter % stages. for i = 1:length(s) userdata = get(s(i),'UserData'); if isfield(userdata, 'svg') && isfield(userdata.svg, 'Filter') next = length(userdata.svg.Filter) + 1; else next = 1; end userdata.svg.Filter(next).Subfilter.Type = 'feGaussianBlur'; userdata.svg.Filter(next).Subfilter.Deviation = deviation; userdata.svg.Filter(next).Subfilter.Source = source; userdata.svg.Filter(next).Subfilter.Result = result; set(s(i),'UserData', userdata); end function svgOffset(s, source, offset, result) % Adds a feOffset SVG filter % PRELIMINARY IMPLEMENTATION (Parameters may change) % Parameters: % s : Array of plot object handles % source : Any previous defined filter result string, 'SourceGraphic', % or 'SourceAlpha'. % offset : Offset value [x y] % result : String that identifies the filter result for following filter % stages. for i = 1:length(s) userdata = get(s(i),'UserData'); if isfield(userdata, 'svg') && isfield(userdata.svg, 'Filter') next = length(userdata.svg.Filter) + 1; else next = 1; end userdata.svg.Filter(next).Subfilter.Type = 'feOffset'; userdata.svg.Filter(next).Subfilter.Source = source; userdata.svg.Filter(next).Subfilter.Offset = offset; userdata.svg.Filter(next).Subfilter.Result = result; set(s(i),'UserData', userdata); end function svgComposite(s, source1, source2, operator, result) % Adds a feComposite SVG filter % PRELIMINARY IMPLEMENTATION (Parameters may change) % Parameters: % s : Array of plot object handles % source1 : Any previous defined filter result string, 'SourceGraphic', % or 'SourceAlpha'. % source2 : Any previous defined filter result string, 'SourceGraphic', % or 'SourceAlpha'. % operator : Operator 'over','in','out','atop','xor','arithmetic' % -> see SVG 1.1 specification. 'arithmetic' is not yet % supported. % result : String that identifies the filter result for following filter % stages. for i = 1:length(s) userdata = get(s(i),'UserData'); if isfield(userdata, 'svg') && isfield(userdata.svg, 'Filter') next = length(userdata.svg.Filter) + 1; else next = 1; end userdata.svg.Filter(next).Subfilter.Type = 'feComposite'; userdata.svg.Filter(next).Subfilter.Source1 = source1; userdata.svg.Filter(next).Subfilter.Source2 = source2; userdata.svg.Filter(next).Subfilter.Operator = operator; userdata.svg.Filter(next).Subfilter.Result = result; set(s(i),'UserData', userdata); end