def plot(self, template): plot_area_height = template['plot-area']['height'] plot_area_width = template['plot-area']['width'] # set up major axis if self._ycontinuous: self.ymax = self._get_ymax() if self.ymax is None else self.ymax self.ymin = self._get_ymin() if self.ymin is None else self.ymin self._yscale = float(plot_area_height) / (self.ymax - self.ymin) if self._has_ytics: ytics = None if self._auto_ytics: if not self._ycontinuous: raise RuntimeError('Auto requires continuity') if self.ymax <= self.ymin: raise RuntimeError('Invalid y-range') ytics = gen_tics(self.ymin, self.ymax, self.ystep, self.opt_tics) if ytics is None: ytics = self._get_ytics() if not self._ytics_all: ytics = ytics[1:-1] # set up minor axis if self._xcontinuous: self.xmax = self._get_xmax() if self.xmax is None else self.xmax self.xmin = self._get_xmin() if self.xmin is None else self.xmin self._xscale = float(plot_area_width) / (self.xmax - self.xmin) if self._has_xtics: xtics = None if self._auto_xtics: if not self._xcontinuous: raise RuntimeError('Auto requires continuity') if self.xmax <= self.xmin: raise RuntimeError('Invalid y-range') xtics = gen_tics(self.xmin, self.xmax, self.xstep) if xtics is None: xtics = self._get_xtics() if not self._xtics_all: xtics = xtics[1:-1] if not template['xtics']['display']: self._has_xtics = False # general styles nopadding = tikz_style('no padding') nopadding.set_option('inner sep', '0') nopadding.set_option('outer sep', '0') nopadding.space_before = 1 nopadding.space_after = 1 nopadding.comment = 'Style for no padding' self._definitions.append(nopadding) # add general defs plot_height_def = latex_length('plotheight', '%scm' % template['plot-area']['height']) plot_width_def = latex_length('plotwidth', '%scm' % template['plot-area']['width']) if self._ycontinuous: ymin = ffloat(self.ymin) ymax = ffloat(self.ymax) else: ymin = '0' ymax = '\\plotheight' if self._xcontinuous: xmin = ffloat(self.xmin) xmax = ffloat(self.xmax) else: xmin = '0' xmax = '\\plotwidth' ymin_def = latex_def('ymin', ymin) ymax_def = latex_def('ymax', ymax) xmax_def = latex_def('xmax', xmax) xmin_def = latex_def('xmin', xmin) self._definitions.append(plot_height_def) self._definitions.append(plot_width_def) self._definitions.append(ymin_def) self._definitions.append(ymax_def) self._definitions.append(xmin_def) self._definitions.append(xmax_def) # title related defs if self.title is not None: title_def = latex_def('plottitle', self.title) title_font_def = latex_def('titlefontsize', lfm[template['title']['font-size']]) title_def.comment = 'Plot title defs' title_def.space_before = 1 self._definitions.append(title_def) self._definitions.append(title_font_def) # ylabel related defs if self.ylabel is not None: ylabel_def = latex_def('plotylabel', self.ylabel) ylabel_font_def = latex_def('ylabelfontsize', lfm[template['ylabel']['font-size']]) ylabel_def.comment = 'Plot Y-label defs' ylabel_def.space_before = 1 self._definitions.append(ylabel_def) self._definitions.append(ylabel_font_def) # xlabel related defs if self.xlabel is not None: xlabel_def = latex_def('plotxlabel', self.xlabel) xlabel_font_def = latex_def('xlabelfontsize', lfm[template['xlabel']['font-size']]) xlabel_def.comment = 'Plot X-label defs' xlabel_def.space_before = 1 self._definitions.append(xlabel_def) self._definitions.append(xlabel_font_def) # ytics related defs if self._has_ytics and template['ytics']['display']: ytics_font_def = latex_def('yticsfontsize', lfm[template['ytics']['font-size']]) ytics_font_def.comment = 'Plot ytics defs' ytics_font_def.space_before = 1 ytics_width_def = latex_def('yticswidth', '%smm' % template['ytics']['width']) ytic_style = tikz_style('ytic') ytic_style.set_option('xshift', '-%smm' % template['ytics']['label-shift']) ytic_style.set_option('anchor', 'east') ytic_style.set_option('inner xsep', '0.75mm') self._definitions.append(ytics_font_def) self._definitions.append(ytics_width_def) self._definitions.append(ytic_style) if template['ytics']['help-lines']: help_line_style = tikz_style('y-help-line') help_line_style.set_option('thin') help_line_style.set_option('densely dotted') self._definitions.append(help_line_style) # xtics related defs if self._has_xtics and template['xtics']['display']: xtics_font_def = latex_def('xticsfontsize', lfm[template['xtics']['font-size']]) xtics_font_def.comment = 'Plot xtics defs' xtics_font_def.space_before = 1 xtics_width_def = latex_def('xticswidth', '%smm' % template['xtics']['width']) xtic_style = tikz_style('xtic') xtic_style.set_option('inner ysep', '0.75mm') if template['xtics']['rotate'] is None or template['xtics']['rotate'] == 0: xtic_style.set_option('anchor', 'base') xtic_style.set_option('yshift', '-%smm' % (template['xtics']['label-shift'] + 1)) else: xtic_style.set_option('anchor', 'east') xtic_style.set_option('xshift', '-%smm' % template['xtics']['label-shift']) xtic_style.set_option('rotate', template['xtics']['rotate']) self._definitions.append(xtics_font_def) self._definitions.append(xtics_width_def) self._definitions.append(xtic_style) if template['xtics']['help-lines']: help_line_style = tikz_style('x-help-line') help_line_style.set_option('thin') help_line_style.set_option('densely dotted') self._definitions.append(help_line_style) # plot area picture plot_area_picture = tikz_picture() plot_area_picture.set_option('yscale', self._yscale) plot_area_picture.set_option('xscale', self._xscale) # anchors swanchor = '(\\xmin, \\ymin)' neanchor = '(\\xmax, \\ymax)' south_west_anchor = tikz_line(swanchor, swanchor) north_east_anchor = tikz_line(neanchor, neanchor) plot_area_picture.add_element(south_west_anchor) plot_area_picture.add_element(north_east_anchor) # help lines if self._has_ytics and template['ytics']['help-lines']: for loc, label in ytics: help_line = tikz_line('(\\xmin, %s)' % loc, '(\\xmax, %s)' % loc) help_line.set_option('y-help-line') plot_area_picture.add_element(help_line) if self._has_xtics and template['xtics']['help-lines'] and template['xtics']['display']: for loc, label in xtics: help_line = tikz_line('(%s, \\ymin)' % loc, '(%s, \\ymax)' % loc) help_line.set_option('x-help-line') plot_area_picture.add_element(help_line) # append plot elements self._get_plot_area(template) for element in self._plot_elements: plot_area_picture.add_element(element) plot_area_node = tikz_node(name='plotarea', content=plot_area_picture) plot_area_node.location = '(0, 0)' plot_area_node.set_option('anchor', 'south west') plot_area_node.set_option('no padding') plot_area_node.comment = 'Plot area node' plot_area_node.space_before = 1 # legend defs if self._has_legend and template['legend']['display']: legends = self._get_legends() ltemplate = template['legend'] legend = Legend(self._legend_type, legends, ltemplate) legend_defs, legend_picture = legend.legend_picture() self._definitions += legend_defs legend_node = tikz_node(name='legend', content=legend_picture) leg_location = ltemplate['location'] leg_relative = ltemplate['relative'] leg_xshift = '%smm' % ltemplate['xshift'] leg_yshift = '%smm' % ltemplate['yshift'] hpadding = '%smm' % ltemplate['hpadding'] vpadding = '%smm' % ltemplate['vpadding'] legend_node.location = plot_area_node.position(leg_location) if leg_relative == 'inside': legend_node.set_option('anchor', leg_location) if leg_location == 'north west': leg_yshift = '-' + leg_yshift elif leg_location == 'north east': leg_yshift = '-' + leg_yshift leg_xshift = '-' + leg_xshift elif leg_location == 'south east': leg_xshift = '-' + leg_xshift elif leg_location == 'south west': pass else: raise RuntimeError('Invalid legend positioning') elif leg_relative == 'outside-h': leg_yshift = '0' if leg_location == 'north west': legend_node.set_option('anchor', 'north east') leg_xshift = '-' + leg_xshift elif leg_location == 'north east': legend_node.set_option('anchor', 'north west') elif leg_location == 'south east': legend_node.set_option('anchor', 'south west') elif leg_location == 'south west': legend_node.set_option('anchor', 'south east') leg_xshift = '-' + leg_xshift else: raise RuntimeError('Invalid legend positioning') elif leg_relative == 'outside-v': leg_xshift = '0' if leg_location == 'north west': legend_node.set_option('anchor', 'south west') elif leg_location == 'north east': legend_node.set_option('anchor', 'south east') elif leg_location == 'south east': legend_node.set_option('anchor', 'north east') leg_yshift = '-' + leg_yshift elif leg_location == 'south west': legend_node.set_option('anchor', 'north west') leg_yshift = '-' + leg_yshift else: raise RuntimeError('Invalid legend positioning') else: raise RuntimeError('Invalid relative position of legend') legend_node.set_option('xshift', leg_xshift) legend_node.set_option('yshift', leg_yshift) legend_node.set_option('outer sep', '0') legend_node.set_option('inner xsep', hpadding) legend_node.set_option('inner ysep', vpadding) legend_node.set_option('fill=white') legend_node.set_option('draw') # ytics node if self._has_ytics: ytics_picture = tikz_picture() ytics_picture.set_option('yscale', self._yscale) ytics_bottom = '(0, \\ymin)' ytics_top = '(0, \\ymax)' ytics_bottom_anchor = tikz_line(ytics_bottom, ytics_bottom) ytics_top_anchor = tikz_line(ytics_top, ytics_top) ytics_picture.add_element(ytics_bottom_anchor) ytics_picture.add_element(ytics_top_anchor) tic_shift = '++(-\\yticswidth,0)' for loc, label in ytics: tic_loc = '(0, %s)' % loc tic = tikz_line(tic_loc, tic_shift) ytics_picture.add_element(tic) label = label + '\\%' if self.ypercent else label label_text = latex_text(label, '\\yticsfontsize') tic_label = tikz_node(content=label_text, oneline=True) tic_label.location = '(-\\yticswidth, %s)' % loc tic_label.set_option('ytic') ytics_picture.add_element(tic_label) ytics_node = tikz_node(name='ytics', content=ytics_picture) ytics_node.location = '(0, 0)' ytics_node.set_option('anchor', 'south east') ytics_node.set_option('no padding') # xtics node if self._has_xtics and template['xtics']['display']: xtics_picture = tikz_picture() xtics_picture.set_option('xscale', self._xscale) xtics_left = '(\\xmin, 0)' xtics_right = '(\\xmax, 0)' xtics_left_anchor = tikz_line(xtics_left, xtics_left) xtics_right_anchor = tikz_line(xtics_right, xtics_right) xtics_picture.add_element(xtics_left_anchor) xtics_picture.add_element(xtics_right_anchor) tic_shift = '++(0,-\\xticswidth)' for loc, label in xtics: tic_loc = '(%s, 0)' % loc tic = tikz_line(tic_loc, tic_shift) xtics_picture.add_element(tic) label_text = latex_text(label, '\\xticsfontsize') tic_label = tikz_node(content=label_text, oneline=True) tic_label.location = '(%s, -\\xticswidth)' % loc tic_label.set_option('xtic') xtics_picture.add_element(tic_label) xtics_node = tikz_node(name='xtics', content=xtics_picture) xtics_node.location = '(0, 0)' xtics_node.set_option('anchor', 'north west') xtics_node.set_option('no padding') # ylabel node if self.ylabel is not None: ylabel_text = latex_minipage('\\plotylabel', '\\ylabelfontsize', '\\plotheight') ylabel_node = tikz_node(name='ylabel', content=ylabel_text) if self._has_ytics: ylabel_node.location = ytics_node.west() ylabel_node.set_option('no padding') else: ylabel_node.location = plot_area_node.west() ylabel_node.set_option('inner ysep', '0.75mm') ylabel_node.set_option('rotate', '90') ylabel_node.set_option('anchor', 'south') if template['ylabel']['xshift'] is not None: ylabel_node.set_option('yshift', '%gmm' % template['ylabel']['xshift']) # xlabel node if self.xlabel is not None: xlabel_text = latex_minipage('\\plotxlabel', '\\xlabelfontsize', '\\plotwidth') xlabel_node = tikz_node(name='xlabel', content=xlabel_text) if self._has_xtics and template['xtics']['display']: xlabel_node.location = xtics_node.south() xlabel_node.set_option('no padding') else: xlabel_node.location = plot_area_node.south() xlabel_node.set_option('inner ysep', '0.75mm') xlabel_node.set_option('anchor', 'north') if template['xlabel']['yshift'] is not None: xlabel_node.set_option('yshift', '-%gmm' % template['xlabel']['yshift']) # title node if self.title is not None: title_text = latex_minipage('\\plottitle', '\\titlefontsize', '\\plotwidth') title_node = tikz_node(name='title', content=title_text) title_node.location = plot_area_node.north() title_node.set_option('anchor', 'south') title_node.set_option('inner ysep', '0.75mm') if template['title']['yshift'] is not None: title_node.set_option('yshift', '%gmm' % template['title']['yshift']) outer_box = tikz_rectangle('(0, 0)', '(\\plotwidth, \\plotheight)') outer_box.comment = 'Outer box' outer_box.space_before = 1 # Finalize plot = tikz_picture() for definition in self._definitions: plot.add_element(definition) plot.add_element(outer_box) plot.add_element(plot_area_node) if self._has_legend and template['legend']['display']: plot.add_element(legend_node) if self._has_ytics: plot.add_element(ytics_node) if self._has_xtics: plot.add_element(xtics_node) if self.ylabel is not None: plot.add_element(ylabel_node) if self.xlabel is not None: plot.add_element(xlabel_node) if self.title is not None: plot.add_element(title_node) return plot
def legend_picture(self): legend_ids = ['legone', 'legtwo', 'legthree', 'legfour', 'legfive', 'legsix', 'legseven', 'legeight', 'legnine', 'legten', 'legelv', 'legtwl'] legend_defs = [] legends = self._legendify() num_legends = len(legends) rows = 0 columns = 0 template = self._template if template['arrange'] == 'horizontal': rows = int(template['rows']) columns = int(ceil(float(num_legends) / rows)) elif template['arrange'] == 'vertical': columns = int(template['columns']) rows = int(ceil(float(num_legends) / columns)) else: raise RuntimeError('Unknown legend arrangement') longest_legends = [] for j in range(columns): longest = 0 for i in range(rows): index = i*columns + j if index >= num_legends: continue length = len(legends[index][1]) longest = max(longest, length) longest_legends.append(longest) legend_fontsize_def = latex_def('legendfontsize', lfm[template['font-size']]) legend_fontsize_def.space_before = 1 legend_fontsize_def.comment = 'Legend defs' legend_defs.append(legend_fontsize_def) label_style = tikz_style('legend label') label_style.set_option('no padding') label_style.set_option('anchor', 'base west') legend_defs.append(label_style) legend_node_style = tikz_style('legend node') legend_node_style.set_option('outer sep', '0') legend_node_style.set_option('inner xsep', '%smm' % template['hpadding']) legend_node_style.set_option('inner ysep', '%smm' % template['vpadding']) legend_defs.append(legend_node_style) legend_nodes = [] for i, (symbol, name) in enumerate(legends): name_id = legend_ids[i] name_var = '\\' + name_id name_def = latex_def(name_id, name) legend_defs.append(name_def) label_name = name_var + '\\vphantom{yg}' label_text = latex_text(label_name, '\\legendfontsize\\sffamily') column = i % columns longest_legend = longest_legends[column] phantom_name = '\\phantom{%s}' % ('{--}' * longest_legend) phantom_text = latex_text(phantom_name, '\\legendfontsize') label_node = tikz_node(content=label_text, oneline=True, location='(0,0)') label_node.set_option('legend label') phantom_node = tikz_node(content=phantom_text, oneline=True, location='(0,0)') phantom_node.set_option('legend label') label_picture = tikz_picture() label_picture.add_element(label_node) if columns > 1 and rows > 1: label_picture.add_element(phantom_node) label_picture.add_element(symbol) legend_node = tikz_node(name='%s-node' % name_id, content = label_picture) legend_node.set_option('legend node') legend_nodes.append(legend_node) legend_picture = tikz_picture() # render first row next_location = '(0,0)' for j in range(columns): node = legend_nodes[j] node.location = next_location next_location = node.east() node.set_option('anchor', 'west') legend_picture.add_element(node) # render the other rows for i in range(1, rows): for j in range(columns): index = i*columns + j if index >= num_legends: continue node = legend_nodes[index] anchor_node = legend_nodes[index - columns] node.location = anchor_node.south_west() node.set_option('anchor', 'north west') legend_picture.add_element(node) return (legend_defs, legend_picture)