List of posts:
Showing posts 1 - 18 of 18.
View more »
|
Tips, tricks and notes
List of posts: |
How to organize your digital working environment: two principles and one example for beginners
How to create a clean netcdf file using the built-in toolbox of Matlab
A while ago I wrote a post on how to create a clean netcdf file from Matlab using the Unidata netcdf toolbox. Starting from release 2010a, Matlab is now delivered with a built-in netcdf toolbox. And the API is not quite similar. So, I thought it would be nice top update the how-to as well. Here it is…
This is a Matlab script showing how to create a clean netcdf (4) file, including groups. Create dummy data to put into the netcdf file
File standard set-upOpen file and insert dimensionsNote I exclude the temporal axis for now. So let’s create a new netCDF4 file:
I call the netcdf pointer a
Insert global attributesThese are just my stuff, you need to customize. But note attributes related to the convention. This is very useful for you netcdf file to be read by anybody else than you.
Check what we’ve just doneWe can now close the netcdf file (optional):
and go in a terminal to look at it with:
or simply from Matlab display a minimum of informations:
or a maximum:
Note that the Insert a 3D fieldIf the file was closed, we need to reopen it:
The variable we want to record is in the Matlab field C but we have to give it a name and define metadata for the netcdf file:
And now we can write it:
We can now close the netcdf file (optional):
and from Matlab:
and see the new variable we just added ! Insert a 2D fieldThe procedure is similar to the 3D case, except that when defining the new variable the dimensions are different:
Handling the time axisYou probably use the native Matlab format for your date/time information: datenum. But this is not how conventional netcdf handles time. Insert the new dimensionUsually, I define my netcdf time axis as the days (can be fractional) since 1900–01–01. So let’s reopen the file:
and add the new time axis. First, define the dimension:
Then add the variable:
NOTE THAT THIS IS ONLY MY CHOICE, YOU NEED TO CUSTOMIZE WITH YOUR REQUIREMENTS Insert a time varying fieldNow we create a dummy variable, supposedly a timeserie of an horizontal 2D fields:
And record it:
We can now close the netcdf file (optional):
and from Matlab:
Variant with groupsThis is one of the main new possibility of netCDF4: you can put some structure into the netcdf file itself. I won’t go into the details, but this simply like
and try:
wait ! this throw an error:
Ok, this was simply to show you that there is a difference between what Matlab knows or wants to do with the actual file state on disk. We need to synchronize both with a sync:
which returns:
this is where the
Now, each group can contain its own dimensions and variables, and filling in the data, is as simple as with the previous case, we just need to specify the correct
Now, let’s put data into the second group. Image we performed an EOF analysis only over the first 40 snapshots of the variable named SST and recorded in the
Note how a dimension and a variable can be defined in 2 groups and have different properties. Before netCDF4 this would have forced us to create a dimension and a variable with a different name. So the final structure of our netCDF4 file is:
|
Vi editor help
I don't use the vi/vim editor much and I found myself constantly looking for useful commands. Here they are, thanks to lagmonster.org. |
jQuery UI widget template/snippet for TextMate
In a recent project I came to write a couple of jQuery UI widgets to build the user interface of a web API.
I thus set up a clean jQuery UI widget snippet for my favorite text editor TextMate to easily create widgets.
Note that you can easily modify the source code to create a template instead a of snippet.
To install the new snippet, simply doucle click on the following tmSnippet file:
Note:
The scope selector is
source.js.jquery
provided by the excellent jQuery TextMate bundle (by K. Swedberg and J. Chaffer), but you could prefer source.js
...Otherwise, here is the code (for some reasons tabulations do not appear bellow, but the snippet file is fully tabulated):
/*
jQuery UI Widget Plugin
Namespace: ${1:namespace}
Widget: ${2:widgetname}
Version: ${3:version}
Create a widget instance via:
\$( "#something" ).$2()
The plugin instance is accessible via:
\$( "#something" ).data("$2")
Widget public methods accessible via:
\$( "#something" ).$2("SomePublicMethod")
\$( "#something" ).data("$2").SomePublicMethod()
Set-up Widget options via:
\$( "#something" ).$2("option","OptionName",OptionValue)
\$( "#something" ).$2("option",{OptionName: OptionValue, OptionName: OptionValue})
Standard Methods:
\$( "#something" ).$2("destroy")
\$( "#something" ).$2("widget")
Creation date: `date +%Y-%m-%d`
Author: ${TM_SHORT_NAME} (${TM_AFFILL})
Contact: ${TM_COORD}
*/
(function( ) {
\$.widget( "$1.$2", {
/* ------------------------------------
WIDGET DEFAULTS OPTIONS
------------------------------------ */
options: {
OptionName: 'OptionValue', // Standard option with a value
//
OptionNameCallBack: {function(){}} // Option with a callback function
},
/* ------------------------------------
WIDGET SET UP METHOD
------------------------------------ */
_create: function() {
var self = this,
options = self.options,
titleId = \$.$1.$2.getTitleId(self.element);
// Simple set-up for the widget container:
self.uiContainer = \$('<div></div>')
.appendTo(document.body) // Append the Widget to the Document
//
.appendTo(self.element) // Or Append it to the caller element
.hide()
.attr({
role: '$1-$2',
'aria-labelledby': titleId
});
return self;
},
/* ------------------------------------
WIDGET PRIVATE METHODS
Insert your private methods with an underscore
------------------------------------ */
_PrivateMethod: function(){
var self = this,
options = self.options;
// Code here
return self;
},
/* ------------------------------------
WIDGET PUBLIC METHODS
------------------------------------ */
// Insert your public methods here:
SomePublicMethod: function(){
var self = this,
options = self.options;
// Code here
return self;
},
/* ------------------------------------
OPTIONS HANDLERS (PRIVATE METHODS)
------------------------------------ */
// Use the _setOption method to respond to changes to options
_setOption: function( key, value ) {
switch( key ) {
case "OptionName":
// Handle changes to OptionName
break;
}
// In jQuery UI 1.8, you have to manually invoke the _setOption method from the base widget
\$.Widget.prototype._setOption.apply( this, arguments );
// In jQuery UI 1.9 and above, you use the _super method instead
// this._super( "_setOption", key, value );
},
_setOptions: function( options ) {
var self = this;
\$.each( options, function( key, value ) {
self._setOptiosn( key, value );
});
},
/* ------------------------------------
WIDGET REQUIRED PUBLIC METHODS
------------------------------------ */
// Use the destroy method to clean up any modifications your widget has made to the DOM
destroy: function() {
// In jQuery UI 1.8, you must invoke the destroy method from the base widget
\$.Widget.prototype.destroy.call( this );
// In jQuery UI 1.9 and above, you would define _destroy instead of destroy and not call the base method
},
// Return the widget object:
widget: function() {
// Method to gain access to the widget created container:
return this.uiContainer;
}
});
/* ------------------------------------
WIDGET VERSION
------------------------------------ */
\$.extend(\$.$1.$2, {
version: "$3",
uuid: 0,
getTitleId: function(\$el) {
var id = \$el.attr('id');
if (!id) {
this.uuid += 1;
id = this.uuid;
}
return 'data-$2-id-' + id;
},
});
}( jQuery ) );
How to download and map Argo profiles for an ocean using Matlab ?
This tutorial will describe how to download and plot Argo profiles (and a density map) for a given ocean.
This tutorial is for people who have a very small experience with Matlab.
This tutorial assumes that you want to plot Argo profiles for one of the given oceanic basin available on GDAC ftp servers under the geo folder: Atlantic, Pacific and Indian oceans.
This tutorial is for people who have a very small experience with Matlab.
This tutorial assumes that you want to plot Argo profiles for one of the given oceanic basin available on GDAC ftp servers under the geo folder: Atlantic, Pacific and Indian oceans.
Step 0: Setting-up your working environnement
Ok, open a terminal window, move to your favorite working folder and create a new folder, let's say '
argo_work
':mkdir argo_work
cd argo_work
Step 1: Download the Argo netcdf files (c-shell script)
We're going to use the
wget
program and for later reuse we're going to put all this step into a single c-shell script. The script is as follow:#!/bin/csh
# Download all Argo netcdf profiles for a given ocean
# Define here which GDAC to use:
set gdac = 'ftp.ifremer.fr/ifremer/argo' # Use the French GDAC ftp server
#set gdac = 'usgodae.org/pub/outgoing/argo' # You can also use the US GDAC ftp server
# Define here which ocean to load:
set basin = 'indian_ocean'
# Define here where to put the data:
set folder = 'data'
# Download files:
wget -c -x -P./$folder -r -N ftp://$gdac'/geo/'$basin
# Done
exit 0
The script starts by defining some parameters to indicate where to get the data and for which ocean, here the Indian Ocean. Note that this script will load ALL the data !
Copy/paste the code into a text editor, save the script as '
download_this
' in the 'argo_work
' folder, make it executable and launch it:chmod ugo+x download_this
./download_this
All the data will go under the sub-folder named '
data
'. The folder structure will depend on the GDAC you used, for the Ifremer one you'll get something like:
data/ftp.ifremer.fr/ifremer/argo/geo/indian_ocean/<YEAR>/<MONTH>/<YEAR><MONTH><DAY>_prof.nc
and for the US one:
data/usgodae.org/pub/outgoing/argo/geo/indian_ocean/
<YEAR>/<MONTH>/<YEAR><MONTH><DAY>_prof.nc
where <YEAR>, <MONTH> and <DAY> are the list of available years and months while the end file is an Argo multiprofile netcdf with all profiles for a given day
Step 2: Read Argo profiles coordinates (matlab function)
Ok, so now that we have the raw material under the '
data
' folder, we're going to move to Matlab scripting to do all the rest of the work.Let's create a matlab function which is going to read all profiles coordinates (latitude,longitude,time).
To keep a clean folder architecture, in the '
argo_work
' folder, creates a sub-folder where we'll put all Matlab scripts:mkdir matlab
cd matlab
Now let's write the Matlab function.
To do this, we create a file named like the function we want to set-up. Let's then create a file named '
read
_data
.m' and open it in your favorite text editor.In the file, we need to tell Matlab that we're going to create a function. The way to do this is to embed all the code into:
function varargout = read_data(varargin)
% All the function code goes here !
end% end function
We first need to declare variables to set a couple of informations:
%- DECLARE LOCAL VARIABLES
% Define where is the data folder relative to the Matlab script:
data_folder = fullfile('..','data');
% Define which ftp server we used to download the data.
% Un-comment by removing the % sign the correct line:
ftp_server = 'ifremer';
%ftp_server = 'us';
% Define which oceanic basin we downloaded the data for:
basin = 'indian_ocean'; % In this case the Indian ocean
% And now adjust the folder names down to basin folders:
switch ftp_server
case 'ifremer',
data_folder = fullfile(
data_folder,'ftp.ifremer.fr','ifremer','argo','geo',basin);
case 'us',
data_folder = fullfile(
data_folder,'usgodae.org','pub','outgoing','argo','geo',basin);
end% switch
Ok, with this piece of code, we know where are the YEAR/MONTH folders. Note that we used the Matlab function
fullfile
to create a correct path string whatever the platform we're working on. This allows to get rid of / or \ issues ...Now we're facing multiple choices in the design of the code to scan the years/months folders. We can either:
- look for any folder (whatever their names) or
- declare a list of years and months to look for in the data folder.
I prefer the second approach for two reasons:
- it's an implicit method to ensure that we're going to look and analyse data coming from the ftp server (its structure is preserved) and
- it provides an easy handling method if at some points we only want to load data for a given month or year.
But this choice is up to you. It is always a compromise between flexibility and security design.
To implement the second choice we then need to declare a list of years and months we want to list the netcdf for:
% Define the list of years to scan:
year_list = [2010:2012];
% Define the list of months to scan:
month_list = [1:12];
Now that we have declared where to start the scan and some kind of iteration process, we can start to loop:
%- FILE SCANNING LOOP:
for iy = 1 : length(year_list)
for im = 1 : length(month_list)
% Define folder to be scanned:
scan_folder = fullfile(data_folder,sprintf('%0.4d',year_list(iy)),sprintf('%0.2d',month_list(im)));
end%for im
end%for iy
At this point, these two loops (over years and months) don't do anything, we'll add codes step by step.
In the
scan_folder
declaration we used the Matlab function sprintf
in order to control the way years and months are written as string in the folder path. This is important for month's name, because for month numbers lower than 10 (January to September), the string must begins with a 0 like: '02' for February and not only '2'.For each
scan_folder
, we can now use the Matlab function dir
to list files present in the folder. If we find a file corresponding to an Argo Netcdf multiprofile, then we'll read the coordinates.We scan the content of the folder with the Matlab function
dir
and store the result in the variable raw_file_list
. This variable is a Matlab structure. A structure is not like double or cell arrays, it can contains a lot of different variable types which can be retrieved or set using an object oriented syntax. In our case, the structure returned by the function dir
is a structure array (which means it's a list of elements with similar content pattern) with some useful properties like: name
, dates
, bytes
, isdir
, ... (see Matlab help for more details). We are going to use the name
property to check if it's a Netcdf file we can expect in this folder:%- FILE SCANNING LOOP:
for iy = 1 : length(year_list)
for im = 1 : length(month_list)
% Define folder to be scanned:
scan_folder = fullfile(data_folder,sprintf('%0.4d',year_list(iy)),sprintf('%0.2d',month_list(im)));
disp(scan_folder); % Print on screen the folder we're scanning.
% List correct files in the folder:
raw_file_list = dir(scan_folder);
for ifile = 1 : length(raw_file_list)
% Is this file looking like an Argo Netcdf multiprofile ?
read_this = false;
% Perform tests:
if length(raw_file_list(ifile).name) == 16
if raw_file_list(ifile).name(end-2:end) == '.nc'
if raw_file_list(ifile).name(1:4) == sprintf('%0.4d',year_list(iy))
if raw_file_list(ifile).name(5:6) == sprintf('%0.2d',month_list(im))
read_this = true;
end%if
end%if
end%if
end%if
% Read profiles coordinates out of this file:
switch read_this
case false
% Nothing to do then
case true
% Let's read coordinates:
end%swtich
end%for ifile
end%for im
end%for iy
Once the list of files in
scan_folder
is retrieved, we loop through all files in order to perform a couple of tests to verify the Netcdf file can be expected. We initiated a variable called
read_this
to false. We'll set it to true for a correct file. We could implement the file name test list in many different form. Here we used a very simple serie of embedded 'if
' statements, we test the following:- file name is 16 characters long (it must be ! otherwise it couldn't be of the form:
<YEAR><MONTH><DAY>_prof.nc
- file extension correspond to the Argo Netcdf extension '
.nc'
- the first 4 characters correspond to the folder year
- the 5th and 6th characters correspond the the folder month.
If these 4 tests are passed successfully, the variable
read_this
is set to true because it looks good. Inside the
ifile
loop, if the read_this
variable is set to true, we then need to open the Netcdf file and get profiles coordinates out of it. The piece of code is as follow:% Let's read coordinates:
% Open the Netcdf file:
ncid = netcdf.open(fullfile(scan_folder,raw_file_list(ifile).name),'NC_NOWRITE');
% Read profiles latitude:
varid = netcdf.inqVarID(ncid,'LATITUDE');
LATITUDE = netcdf.getVar(ncid,varid,'double');
% Read profiles longitude:
varid = netcdf.inqVarID(ncid,'LONGITUDE');
LONGITUDE = netcdf.getVar(ncid,varid,'double');
% Read profiles time:
% Get the time reference:
varid = netcdf.inqVarID(ncid,'REFERENCE_DATE_TIME');
REFERENCE_DATE_TIME = netcdf.getVar(ncid,varid)';
ref = datenum(str2num(REFERENCE_DATE_TIME(1:4)),...
str2num(REFERENCE_DATE_TIME(5:6)),...
str2num(REFERENCE_DATE_TIME(7:8)),...
str2num(REFERENCE_DATE_TIME(9:10)),...
str2num(REFERENCE_DATE_TIME(11:12)),...
str2num(REFERENCE_DATE_TIME(13:14)));
% then the relative time axis:
varid = netcdf.inqVarID(ncid,'JULD');
JULD = netcdf.getVar(ncid,varid);
% and finally the absolute time axis:
TIME = ref + JULD;
% Close the Netcdf file:
netcdf.close(ncid);
% Add those profiles coordinates to the function output variables:
X = [X; LONGITUDE];
Y = [Y; LATITUDE];
T = [T; TIME];
This syntax implies that you're using a recent Matlab version, one with a built-in Netcdf api. First we open the file which is then referred to as the
ncid
variable pointer. Reading latitude and longitude is fairly easy as you can see. For time it's a little bit more complicated because we have to recompute the asbolute time axis from a reference and relative time axis. I won't go into details here, check out the Argo documentation for that.In the end, we close the netcdf file (you must do this, otherwise Matlab we'll keep 'connection' open to files and at some point it will blow up your session if too many files are open) and finally concat the new profiles coordinates (LATITUDE,LONGITUDE,TIME) to variables used to output the results out of the function (X,Y,T). Those variables needs to be initiated before the time looping like:
% Initiate coordinates arrays:
X = [];
Y = [];
T = [];
%- FILE SCANNING LOOP:
...
We're only left with function output set up, just before the end function tag, we can insert:
% Output
varargout(1) = {X};
varargout(2) = {Y};
varargout(3) = {T};
This says that if one is requesting for outputs, we'll serve X then Y then T.
And that's it, save the file 'read_data' and you're all set.
Oh wait ! What if we want to load profiles for a given year, or month ? We don't want to edit this function every time, we prefer to use parameters when calling it !
How can we do that ? Well, my favorite method is to insert a block of code after the
'DECLARE LOCAL VARIABLES'
section of the function which is going to read variables from the function arguments and possibly overwrite some values. This can simply be achieved with:%- LOAD USER PARAMETERS:
if nargin > 0
if mod(nargin,2) ~= 0
error('Please provide options as: ''OPTIONS NAME'',VALUE pair(s)');
end% if
for in = 1 : 2 : nargin
eval(sprintf('%s = varargin{in+1};',varargin{in}));
end% for in
clear in
end% if
This syntax usage is simple. For instance, by default we're loading all months of any year because the variable
month_list
is set to 1:12. With the previous peace of code, we can call the function from the Matlab prompt (or another script) like:>> [X,Y,T] = read_data('month_list',[12 1 2]);
and the variable
month_list
will be overwritten so that in this case only Dec/Jan/Feb months are loaded.The final
read_data.m
file can be downloaded at the end the tutorial.Step 3: Plot locations and compute a density map (matlab script)
Let's move on to the fun part: plotting ! Now we're going to write all the code in a Matlab file which is not a function. This means that all variables declared in the script are going to be available in the Matlab workspace.
Requirements:
- We are going to use the
m_map
Matlab toolbox to plot map easily (download the m_map package here). So first you need to install the toolbox (see their webpage). - The profile density map will be computed using the very nice function bin2mat created by A. Stevens and distributed on the Matlab Central file exchange platform. So next you need to put the
bin2mat.m
function file in your matlab folder.
First create a file named '
plot_data.m
' and open it in your favorite text editor. Let's load the data (profiles coordinates) for the year 2010, then enter the line:[X,Y,T] = read_data('year_list',2010);
You may want to start the file by a '
clear
' statement so that the workspace is clear of any variables. You really don't want to enter a 'clear all
' to also delete global variables.If you now look at your workspace you have the following variables available:
>> whos
Name Size Bytes Class Attributes
T 27385x1 219080 double
X 27385x1 219080 double
Y 27385x1 219080 double
At the time of writing this tutorial (I just downloaded profiles for the Indian Ocean), we can see that 27,385 profiles were sampled in 2010 for this ocean. And this is the smallest ocean ! so be careful if you try to load profiles for multiple years or a bigger ocean, numbers can get very large and your computer may don't like it.
Number of profiles per week
First we're going to plot a very simple diagram showing the number of profiles per week (this time frame is appropriate because we loaded a single year of data).
This simplest way to do this is to use the Matlab function
hist
and ask the function to compute the number of profile for 52 bins (hence 52 weeks in a year). [nw tw] = hist(T,52);
figure;
plot(tw,nw,'.-');
grid on, box on,datetick('x')
xlabel('Time');ylabel('# of profiles');title('Number of Argo profiles per week in the Indian Ocean for 2010');
We then open a new figure, plot the number of profiles per week (nw) using the time axis returned by hist (tw), format the grid, the time axis and put some labels and a title. You should have something like:
There are about 520 profiles sampled every week in the Indian Ocean, at least in 2010. Very impressive network !
Map of profiles locations
We're going to plot a map with all the profiles locations now. We first need to initiate a projection using the m_map function
m_proj
:m_proj('equid','lon',[min(X) max(X)]+[-1 1],'lat',[min(Y) max(Y)]+[-1 1]/2);
This line set up an equidistant projection system centered over a rectangular area specified by the options 'lon' and 'lat'. Note that here we're using the range of coordinates of profiles to fit the map correctly. If you're curious you can now open a new figure, type in
m_grid;m_coast;
at the prompt, and here we go: a map of the Indian Ocean ! The m_map toolbox is smart enough so that to plot a coastline and the grid you don't have to worry about anything as long as you're not customizing the look.Note that the
m_proj
function defines global variables and needs to be called only once, you don't have to call it every time you plot a map.How do we plot profiles locations ? Well, simply using the
m_plot
function:figure;
hp = m_plot(X,Y,'+');
m_coast;m_grid;
title('Argo profiles for 2010');
And that's it.
Wait, wait, this standard figure is really ugly, we want to customize it so that profiles markers are not so big, etc ... Let's try again:
figure
hp = m_plot(X,Y,'+');
set(hp,'markersize',2,'color',[1 .5 0]);
m_coast('patch',[1 1 1]/3);
m_grid('box','fancy','xtick',[-180:30:180],'ytick',[-90:10:90]);
title('Argo profiles locations for 2010','fontweight','bold');
These are the figures I get from the two previous plots:
See how you can customize the map by looking at all the options for
m_coast
and m_grid
. The profiles marker design is up to you as well ...Map of profiles density
Ok, plotting profiles locations with a marker is very simple but as soon as the number of profiles increases maps become totally useless. One method out of this visualization issue is to compute and plot what we call a profile density map: ie the number of profiles for a given area, usually a rectangular cell of a couple of degrees wide.
To do such a thing we need to define a grid like for instance:
% Define a 1x1 degree grid:
dxi = 1; dyi = 1; % Grid size in longitude and latitude
xi = min(X)-1:dxi:max(X)+1; % Define grid point longitude
yi = min(Y)-.5:dyi:max(Y)+0.5; % Define grid point latitude
[Xi,Yi] = meshgrid(xi,yi); % Create the meshed grid.
And now here comes the magic ! Using the
bin2mat
function computing a profile density map is as simple as:dens = bin2mat(X,Y,ones(size(X)),Xi,Yi,@sum);
The 1st/2nd arguments of
bin2mat
are the longitude and latitude axis of profiles, the 3rd argument is the quantity we want to bin (here we take 1 because we simply want to compute the number of points), 4th/5th arguments are the grid points coordinates and the 6th argument is the function handle you want to use. Here this command literrally means sum 1 each time you get a value in X/Y falling into a grid cell defined by Xi/Yi. And now we can plot the density map using
m_pcolor
:figure
m_pcolor(xi,yi,dens);
m_coast('patch',[1 1 1]/3);
m_grid('box','fancy','xtick',[-180:30:180],'ytick',[-90:10:90]);
title('Argo profiles density map for 2010','fontweight','bold');
But this figure isn't showing much because one area (the Arabian Sea) has a very large number of profiles compared to the rest of the basin. So we may want to tune the color axis to highlight those poor regions as well. We can do it using the
caxis
Matlab function which set the range of the color axis, meaning if we use:caxis([1 10]);
then all grid points with values higher or equal to 10 will have the same color (the last one from the colormap) while all grid points with values smaller or equal to 1 will also have the same color (the first one from the colormap). In this case, I think it would be a good practice to set-up a colorbar where the highest value color (more than 10) is significantly different than the one just smaller to clearly indicate that the color axis is saturated and that some informations are not visible in the map. If we use the standard '
jet
' colormap, the last color is red. So we can change it to black and keep a nice look:cmap = jet(64);
cmap(end,:) = [0 0 0]; % Replace the last color (red) by black
colormap(cmap);
Below are the two figures before and after the color axis and color map adjustment:


Using a density grid of 1x1 degree may not the best choice here. Let's try the map with a 3x3 degree grid. The only thing to change in the previous code is the dxi/dyi line:
dxi = 3; dyi = 3; % Grid size in longitude and latitude
and the color axis because we're going to have 9 times the number of initial profiles per grid cell. So now the density map looks like:
That's it for today. We've learn how to download profiles from a GDAC ftp server, to read those data from Matlab and plot some stuff about them. Many improvements could be added, like a test on the profiles coordinates quality or a more flexible method to list files to get the data from.
I hope you found this tutorial helpful. Feel free to post a comment if you have questions or issues...
Multiple pages PDF document with Preview version 5.0.3
I've been using a Mac and Preview to visualize PDF documents. I loved taking advantage of the sidebar to create/cut/mix pages in documents. As easy as a simple drag/drop of any page.
Unfortunately when I update to Mac OS 10.6.6 a couple of weeks ago, I noticed a change of behavior of Preview. In previous versions you could drag and drop a new page to a pdf document and save as something new the augmented document. Doing this with the new Preview version simply add the new page to the sidebar and when saving as, only the selected page (or initial document) was saved.
Well, today I finally found how the new Preview works. Instead of dragging and dropping the new page below or between pre-existing pages (when little horizontal blue line shows up) you have to drop the file on the pdf thumbnail and only then it will add a new page to the document and save it when using 'save as'...
You'll notice the difference in the window's title. It will change
from: "toto.pdf (1 page) (2 documents, 2 total pages)"
to: "toto.pdf (page 1 of 2)"
Google Chrome extension and web apps
I've been a Firefox user for several years, and to be honest, since I had my first Sun station to work with ! I moved to Mac OS and kept using Firefox because I never fell in love with Safari. But as new updates keep pilling up new functions and a bunch of other stuff, I started to find Firefox buggy, slow and unstable. So, I've been patient and as soon as Google released a Mac OS version of its navigator Chrome I gave it a try. What a charm ! It is fast, stable, works intuitively and on my small 13' MacBook screen optimizes the space taken by the webpage. Since a couple of months it is also highly customizable with the 'extensions' capability. I'll soon report here about a Chrome extension I'm writting for bibliography search based on JournArch. Before then I just want to share simple webapp crx files I packaged for my personal use (see here for a bunch of them). Download zip files and click on crx files. |
About Matlab figure export in pdf/eps
I export my Matlab figures in the pdf format and this produces a nice a4 or usletter size pdf document with my plot. In fact, Matlab creates a pdf of the size indicated in the 'papertype' or 'papersize' figure properties. Most of the time I don't care because my plots fit in a landscape or portrait a4/usletter page. But when comes the time to write a clean article or a report and embed my figure in a LaTeX document, I want to get rid of all the white space around the plot and have a nice pdf file fitting the plot. You probably noticed that exporting the figure in the eps format will produce an eps file fitting the plot without extra white spaces around it. With my Mac, opening the eps file (with Preview) creates a pdf file exactly as I want it (without white space) and then I just have to "Save as" the file and I'm done. But there's a more automatic way to do it, without relying on the Mac OS Preview software to produce directly the pdf file. Let's say your file name (without the file type extension) is : 'figure_output' Under Matlab, you can type the following: filo = 'img/figure_output'; This will create the eps file with Matlab and the pdf file with the system command 'ps2pdf'. I'm reporting this little trick here because I've been looking for the '-dEPSCrop' option to ps2pdf for a while now ! Without this option the pdf file is of the default paper size of the ps2pdf command. On a daily basis I use three Matlab functions to manage my figures. - figure_land/figure_tall: to set the figure's orientation and paper size correctly (this correspond to setting A4 landscape or portrait formats). It also modifies the figure's size and color, so that it looks more like what is expected. - exportp: this function allows one to simply manage figure export to pdf. Simply put it the figure's handle, a file name (no extension) and an orientation. This allows to export clean pdf to portrait, landscape and 'crop' formats |
GFD Search Engine (add to Firefox custom search)
I started aggregating a bunch of useful sites to look for GFD informations on the web, some kind of specialized Google search engine. You can find its homepage here: http://www.google.com/cse/home?cx=006346700993241352089:qyczjxt9rgc or here: http://www.ifremer.fr/lpo/files/gmaze/gfd_search.html If you want to insert it on your webpage, visit this page, or if you want to add it to your Google home page click on this button: But if you want to add it to your Firefox Custom Search Engines, visit this page (which will reveal the engine parameters) and simply try to change the search engine on your Firefox Search toolbar, you should see an Add "GFD Search" line, click on it and you're all set ! The xml file is here. |
Online access to articles with your library and proxy (bookmarklet to modify url)
MIT provides a very nice method to access articles from publishers. It's through their library proxy. I used to use a simple trick, simply adding .libproxy.mit.edu at the end of the article url hostname. For example I changed:
http://ams.allenpress.com.libproxy.mit.edu/perlserv/?request=get-abstract&doi=10.1175/2009JPO3985.1
and get access to the pdf.
But I get tired of constantly adding this extension when needed, so I created a very simple javascript which does the job for me by a simple click. The script splits the window.location variable and add .libproxy.mit.edu where it's needed.
I wish I could simply add a link on this page you would have to drag to your bookmark bar and click it when you want, but google apps doesn't allow it ;-(. Anyway, open your bookmark manager, create a new bookmark you'll probably place in your bookmark bar and in the bookmark url insert the code below: javascript:(function(){var newurl = window.location.protocol+'//'+window.location.host+'.libproxy.mit.edu'+window.location.pathname+window.location.search;window.location=newurl;})(); It should work fine (at least it does for me, on ams, agu and science direct so far) ps: for those with access to the Biblioplanet, you can use: javascript:(function(){var newurl =
window.location.protocol+'//'+window.location.host+'.biblioplanets.gate.inist.fr'+window.location.pathname+window.location.search;window.location=newurl;})(); ps: All of this is now explained on the MIT library webpage here: Update: My javascript is not the shortest one, MIT script is as follow in the bookmarlet: void(location.hostname = location.hostname + '.libproxy.mit.edu'); |
1-10 of 18