def __call__(self, config): plot = Plot(**config) callbacks.trigger('before_plot', plt=plt, mpl=matplotlib) # plot each object id_regex = config.get('plot_id', '') if isinstance(id_regex, basestring) or not isinstance(id_regex, collections.Iterable): id_regex = [id_regex] items = ([(x, config['objects'][x]) for x in config.get('plot_order', []) if x in config['objects'].keys()] + [(x, config['objects'][x]) for x in config['objects'].keys() if x not in config.get('plot_order', [])]) for id, item in items: item['id'] = id if item.get('no_plot', False): log.debug('Omitting id {0} since no_plot setting was set.'.format(id)) continue if not any([re.match(regex, id) for regex in id_regex]): log.debug('Omitting id {0} since it does not match the regex.'.format(id)) continue if not item.get('obj', None): log.warning('Not obj found for id {0}. Skipping this id.'.format(id)) continue log.info('Drawing id {0}'.format(id)) artist = plot.plot(**item) # Save plot plot.finish()
def build_config(self, input_config=None, log_level='info'): """ Parse arguments. To set log level, load additional module parsers etc. the sys.args[1:] are parsed multiple times. :return: dict of parsed args """ base_parser = SettingParser(add_help=False) base_parser_group = base_parser.add_argument_group(title='Base Parser', description='') base_parser_group.add_argument("--log-level", default=log_level, help="Set the log level.") base_parser_group.add_argument("--list-modules", action='store_true', help="List all available modules.") base_parser_group.add_argument("-l", "--load-config", default=[], nargs='+', help="Load json configs, with decreasing precedence, or a python scripts from file.") # Parse only log level to set it as early as possible args = vars(base_parser.parse_known_args()[0]) # Set log level log_level = getattr(logging, args['log_level'].upper(), None) if not isinstance(log_level, int): raise ValueError('Invalid log level: %s' % log_level) logging.basicConfig(format='%(message)s', level=log_level) # Discover all available modules self._all_modules = discover_modules() # If module list requested, print it and exit program if args['list_modules']: for label, module in self._all_modules.iteritems(): print label sys.exit(0) # Load configs/python scripts from files if requested file_config = ConfigDict() for item in args.pop('load_config', []): if item.endswith('.json'): merge(file_config, read_config(item)) elif item.endswith('.py'): log.info('Running python file {}'.format(item)) runpy.run_path(item) else: raise ValueError('The file type of {0} is not supported.'.format(item)) base_parser_group.add_argument("--input-modules", nargs='+', default=['RootModule'], help="Input modules .") base_parser_group.add_argument("--ana-modules", nargs='+', default=[], help="Analysis modules.") base_parser_group.add_argument("--output-modules", nargs='+', default=['PlotModule'], help="Output modules.") # Parse also the modules to add their parsers args = vars(base_parser.parse_known_args()[0]) module_parsers = [self._all_modules[name]().parser for name in args['input_modules'] + args['ana_modules'] + args['output_modules']] # Additional arguments for complete parser base_parser_group.add_argument("-p", "--print-config", default=False, action="store_true", help="Print out the JSON config before running Artus.") base_parser_group.add_argument("--store-json", type='bool', default=True, help="Save the config as json file.") base_parser_group.add_argument("--merge-args", nargs='+', default=[], help=("If json file configs and command line configs are provided the settings are " "merged for the provided args. Works only for list arguments.")) base_parser_group.add_argument('--output-path', default='plot.png', help='Path to output file.') base_parser_group.add_argument('--output-prefix', default='plots/', help='Prefix to output paths.') # Final parser consists of baseparser + active module parsers parser = SettingParser(parents=[base_parser] + module_parsers, description='''Plotting tool to read, manipulate and plot root objects.''') # Triggers before actual parameters are parsed. callbacks.trigger('before_parsing', config=file_config) # Final parsing of parameters args = vars(parser.parse_args()) # If a config was loaded, merge it with the args if file_config: provided_args = args.pop('provided_args') merge_args = args.pop('merge_args') merge(file_config, args, precedence_keys=provided_args, merge_keys=merge_args) config = file_config if input_config: merge(input_config, config, precedence_keys=provided_args, merge_keys=merge_args) config = input_config else: config = args # ConfigDict is just a simple wrapper around a dict with some helper functions. return ConfigDict(config)
def __call__(self, config=None, log_level=None): # Prepare configs from parsed args and provided input configs/python files config = self.build_config(config, log_level=log_level) # Triggered after config built callbacks.trigger('after_config', config=config) # At this point the config is 'complete' # While modules may add settings/etc to the config later on, the actual config is feature complete now # and can be saved to disk. if config.get('store_json', False): path = os.path.splitext(os.path.join('configs', config['output_path']))[0] write_config(config, path + '.json') # Replace values with lookup values perform_lookup_replacement(config) # Replace all environment variables walk_dic(config, os.path.expandvars) # Replace all symlinks with the real path walk_dic(config, relpath_replace) # Run all modules # Input modules for module in [self._all_modules[name]() for name in config['input_modules']]: log.info("Processing {0}...".format(module.label)) callbacks.trigger('before_module_{0}'.format(module), config=config) module(config) callbacks.trigger('after_module_{0}'.format(module), config=config) update_with_default(config['objects']) # Triggered after all input modules processed. callbacks.trigger('after_input_modules', config=config) # Ana modules for module in [self._all_modules[name]() for name in config['ana_modules']]: log.info("Processing {0}...".format(module.label)) callbacks.trigger('before_module_{0}'.format(module), config=config) module(config) callbacks.trigger('after_module_{0}'.format(module), config=config) update_with_default(config['objects']) # Triggered after all ana modules processed. callbacks.trigger('after_ana_modules', config=config) # Output modules for module in [self._all_modules[name]() for name in config['output_modules']]: log.info("Processing {0}...".format(module.label)) callbacks.trigger('before_module_{0}'.format(module), config=config) module(config) callbacks.trigger('after_module_{0}'.format(module), config=config) update_with_default(config['objects']) # Triggered after all output modules processed. callbacks.trigger('after_ana_modules', config=config) path = os.path.splitext(os.path.join(config['output_prefix'], config['output_path']))[0] write_config(config, path + '.json')
def finish(self): # Add colorbar if there is a mappable if self.colorbar_mappable: cb = self.fig.colorbar(self.colorbar_mappable, ax=self.ax) cb.ax.minorticks_on() cb.solids.set_rasterized(True) if self.z_label: cb.set_label(self.z_label) # Add axis texts for text in self.texts: text = get_lookup_val('ax_texts', text) default_text_kwargs = {'x': 0.05, 'y': 0.95, 'va': 'top', 'ha': 'left'} text_kwargs = parse_query(text) default_text_kwargs.update(text_kwargs) ax_name = default_text_kwargs.pop('axis', 'ax') s = default_text_kwargs.pop('s') r = re.compile(r'\$([^$]*)\$') s = r.sub(lambda m: m.group().replace('.', '.\!'), s) try: cax = getattr(self, ax_name) except AttributeError as e: log.critical('The axis name {0} does not exist.'.format(ax_name)) log.critical(e) raise cax.text(s=s, transform=cax.transAxes, **default_text_kwargs) # Add horizontal lines to ax for hline_kwargs in self.hlines: ax_name = hline_kwargs.pop('axis', 'ax') try: cax = getattr(self, ax_name) except AttributeError as e: log.critical('The axis name {0} does not exist.'.format(ax_name)) log.critical(e) raise cax.axhline(**hline_kwargs) # Add vertical lines to ax for vline_kwargs in self.vlines: ax_name = vline_kwargs.pop('axis', 'ax') try: cax = getattr(self, ax_name) except AttributeError as e: log.critical('The axis name {0} does not exist.'.format(ax_name)) log.critical(e) raise cax.axvline(**vline_kwargs) # a specified position of the label can be set via label?json_dict x_label_kwargs = {'position': (1.0, 0.0), 'ha': 'right', 'va': 'top'} x_label, user_x_label_kwargs = parse_optionstring(self.x_label) x_label_kwargs.update(user_x_label_kwargs) if self.ax1: self.ax1.set_xlabel(x_label, **x_label_kwargs) else: self.ax.set_xlabel(x_label, **x_label_kwargs) y_label_kwargs = {'position': (0.0, 1.0), 'ha': 'right', 'va': 'bottom'} y_label, user_y_label_kwargs = parse_optionstring(self.y_label) y_label_kwargs.update(user_y_label_kwargs) self.ax.set_ylabel(y_label, **y_label_kwargs) if self.ax1: y_subplot_label, y_subplot_label_kwargs = parse_optionstring(self.y_subplot_label) self.ax1.set_ylabel(y_subplot_label, **y_subplot_label_kwargs) if self.x_log: self.ax.set_xscale('log') if self.x_axis_formatter == 'scalar': xfmt = ScalarFormatter() self.ax.xaxis.set_major_formatter(xfmt) elif self.x_axis_formatter == 'scalar2': xfmt = ScalarFormatter() self.ax.xaxis.set_minor_formatter(plt.FuncFormatter(log_locator_filter)) self.ax.xaxis.set_major_formatter(xfmt) if self.ax1: self.ax1.set_xscale('log') if self.x_axis_formatter == 'scalar': xfmt = ScalarFormatter() self.ax1.xaxis.set_major_formatter(xfmt) elif self.x_axis_formatter == 'scalar2': xfmt = ScalarFormatter() self.ax1.xaxis.set_minor_formatter(plt.FuncFormatter(log_locator_filter)) self.ax1.xaxis.set_major_formatter(xfmt) else: self.ax.set_xscale('linear') if self.y_log: self.ax.set_yscale('log', nonposy='clip') if self.y_axis_formatter == 'scalar': xfmt = ScalarFormatter() self.ax.yaxis.set_major_formatter(xfmt) elif self.y_axis_formatter == 'scalar2': xfmt = ScalarFormatter() self.ax.yaxis.set_major_formatter(xfmt) self.ax.yaxis.set_minor_formatter(plt.FuncFormatter(log_locator_filter)) else: self.ax.set_yscale('linear') # By default set a 10% margin plot_tools.set_margin(margin=self.margin) self.ax.set_ylim(ymin=self.y_lims[0], ymax=self.y_lims[1]) self.ax.set_xlim(xmin=self.x_lims[0], xmax=self.x_lims[1]) if self.show_legend: # handles, labels = self.ax.get_legend_handles_labels() no_legend_ids = ['nolegend', '_nolegend_', '__nolegend__','none', ''] # handles = self._legend_handles # labels = self._legend_labels # TODO combine legend entries for id, id2 in self.combine_legend_entries: log.debug('Combining legend entries {0} and {1}'.format(id, id2)) if id in self._ids and id2 in self._ids: self._legend_handles[self._ids.index(id)] = (self._legend_handles[self._ids.index(id2)],self._legend_handles[self._ids.index(id)]) leg_entry_dict = OrderedDict(zip(self._legend_labels, self._legend_handles)) for key in leg_entry_dict.keys(): if key.lower() in no_legend_ids: del leg_entry_dict[key] if leg_entry_dict: labels, handles = zip(*leg_entry_dict.items()) if 'outside' in self.legend_loc: if self.legend_bbox_anchor: bbox_to_anchor = self.legend_bbox_anchor else: bbox_to_anchor = (1, 1) self.legend_loc = self.legend_loc.replace('outside', '').strip() else: bbox_to_anchor = None legend = self.ax.legend(handles, labels, loc=self.legend_loc, ncol=self.legend_ncol, bbox_to_anchor=bbox_to_anchor) legend.get_frame().set_alpha(0.0) # [obj.set_rasterized(True) for obj in legend.get_patches()] # for obj in legend.get_patches(): # obj.set_rasterized(True) # legend.draw() # self.ax.legend_ = None # self.ax.add_artist(legend) else: log.debug('Omit legend since all labels are empty.') if self.ax1: self.ax1.set_ylim(ymin=self.y_subplot_lims[0], ymax=self.y_subplot_lims[1]) plt.setp(self.ax.get_xticklabels(), visible=False) plt.setp(self.ax.get_xticklabels(minor=True), visible=False) # self.ax1.set_xscale(self.ax.get_xscale()) self.ax1.set_xlim(self.ax.get_xlim()) plt.subplots_adjust(hspace=0.15) callbacks.trigger('after_plot', plt=self) self.save_fig() plt.close(self.fig)