I have a list of figures and I want to create a text file (using python) with their names listed in a specific order (for a movie creation with mencoder). In particular here, the figure names include months (April, August...). I want the one for Januray first, then February and so on.
I know I could do it in an ugly way, but I am interested in a solution which would be both elegant (=pythonic?) and eventually more general.
My files are, in natural order:
cld_for_April_EISopt_1000.png cld_for_August_EISopt_1000.png cld_for_December_EISopt_1000.png cld_for_February_EISopt_1000.png cld_for_January_EISopt_1000.png cld_for_July_EISopt_1000.png cld_for_June_EISopt_1000.png cld_for_March_EISopt_1000.png cld_for_May_EISopt_1000.png cld_for_November_EISopt_1000.png cld_for_October_EISopt_1000.png cld_for_September_EISopt_1000.pngAnd I want to have a text file with this inside:
cld_for_January_EISopt_1000.png cld_for_February_EISopt_1000.png cld_for_March_EISopt_1000.png cld_for_April_EISopt_1000.png cld_for_May_EISopt_1000.png cld_for_June_EISopt_1000.png cld_for_July_EISo开发者_如何学编程pt_1000.png cld_for_August_EISopt_1000.png cld_for_September_EISopt_1000.png cld_for_October_EISopt_1000.png cld_for_November_EISopt_1000.png cld_for_December_EISopt_1000.pngOr more generally, if I have a list or an array or a dictionnay like:
{'pattern1': rank_in_output_list_1, ..., 'pattern12': rank_in_output_list_12} how should I do to use it to order my file names?So far I have played with: os.listdir, os.path.isfile, numpyp.ma.array, .compressed() or .compress() ; but I haven't been so successful.
Thanks a lot.
Christophe.As the key for the sort, split by _
and map the third element.
sorted(filenames, key=lambda x: monthdict[x.split('_')[2]])
Longer, but more flexible answer for ordering sequences:
import collections
def rearrange(seq, order, keyfunc):
if not isinstance(order, collections.Mapping):
order = {v: i for i,v in enumerate(order)}
return sorted(seq, key=lambda x: order[keyfunc(x)])
if __name__ == '__main__':
filenames = """
cld_for_April_EISopt_1000.png cld_for_August_EISopt_1000.png
cld_for_December_EISopt_1000.png cld_for_February_EISopt_1000.png
cld_for_January_EISopt_1000.png cld_for_July_EISopt_1000.png
cld_for_June_EISopt_1000.png cld_for_March_EISopt_1000.png
cld_for_May_EISopt_1000.png cld_for_November_EISopt_1000.png
cld_for_October_EISopt_1000.png cld_for_September_EISopt_1000.png
""".split()
months = ['January', 'February', 'March', 'April', 'May', 'June', 'July',
'August', 'September', 'October', 'November', 'December']
def get_month_name(filename):
return filename.split('_')[2]
for filename in rearrange(filenames, months, get_month_name):
print(filename)
Output:
cld_for_January_EISopt_1000.png
cld_for_February_EISopt_1000.png
cld_for_March_EISopt_1000.png
cld_for_April_EISopt_1000.png
...
Here is my final version.
I hope it is more pythonic.
Please feel free to comment on the general style.
#!/usr/bin/env python
"""Demonstrate how to animate multiple figures into a climatology movie."""
#
# Imports
#
from os import system
from os.path import exists
from numpy import ma
from glob import glob
from copy import deepcopy
from logging import warning
#
# Parameters
#
month_list = ['January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December']
#
month_dict = {'January': 0,
'February': 1,
'March': 2,
'April': 3,
'May': 4,
'June': 5,
'July': 6,
'August': 7,
'September': 8,
'October': 9,
'November': 10,
'December': 11}
#
param_dict_default = {'fig_folder': 'figures/era40_correlations/',
'output_name': 'output_sol_2.mp4',
'fig_criteria': '*climatology*isccp*.png',
'order': month_list,
'input_file': 'list_fig_for_movie.txt',
'splitor': '_',
'fps': 10}
#
# Functions
#
def reorder(seq, extractor, order):
"Reorder 'seq' using 'extractor' and according to 'order'."""
rank = dict((v,i) for i,v in enumerate(order))
return sorted(seq, key=lambda v: rank.get(extractor(v),-1))
def get_ordering_key(filename, splitor, ind):
"""Get ordering key in 'filename' at 'ind' position for 'splitor'."""
return filename.split(splitor)[ind]
def prepareMovie(param_dict={}):
"""Return the command line to create the movie and the output filename.
Input
-----
param_dict : dictionary with parameters for creating the movie.
Keys: Default values:
* fig_criteria = '*climatology*isccp*.png'
* input_file = 'list_fig_for_movie.txt'
* splitor = '_'
* fps = 10
* fig_folder = 'figures/era40_correlations/'
* output_name = 'output_sol_2.mp4'
* order = ['January', 'February', 'March', 'April',
'May', 'June', 'July', 'August', 'September',
'October', 'November', 'December']
from:
for key in param_dict_default.keys():
print ' * ', key, '=', repr(param_dict_default[key])
Output
------
Command line to create the movie and output filename.
"""
# Update parameters
param_new = deepcopy(param_dict_default)
param_new.update(param_dict)
# List all selected figures
file_names = glob(param_new['fig_folder'] + param_new['fig_criteria'])
# Find position of ordering key in name
for item in param_new['order']:
try:
ind = file_names[0].split(param_new['splitor']).index(item)
except:
pass
# Sort all selected figures
if isinstance(param_new['order'], list):
file_names = sorted(file_names, key=lambda x: param_new['order'].\
index(x.split(param_new['splitor'])[ind]))
elif isinstance(param_new['order'], dict):
file_names = sorted(file_names, key=lambda x: param_new['order']\
[x.split(param_new['splitor'])[ind]])
else:
raise ValueError("param_dict['order'] must be list or dictionary.")
# Remove input file for mencoder if already exists
if exists(param_new['input_file']):
warning(" '%s' existed and has been overwritten."
%param_new['input_file'])
system("rm %s" %param_new['input_file'])
# Write input file for mencoder
f = open(param_new['input_file'], "w")
for item in file_names:
f.write(item+'\n')
f.close()
# Create command for mencoder
command = ['mencoder',
'mf://@' + param_new['input_file'],
'-mf',
"type=png:w=800:h=600:fps=%s" %param_new['fps'],
'-ovc',
'lavc',
'-lavcopts',
'vcodec=mpeg4',
'-oac',
'copy',
'-o',
param_new['output_name']]
# Make it one line white-spaced and return it
command = ''.join([item + ' ' for item in command])
return command, param_new['output_name']
#
# Main
#
if __name__ == "__main__":
[command, output_name] = prepareMovie()
# Create the movie
system(command)
# Open it
system("mplayer %s" %output_name)
精彩评论