def writeSvg(self, fileName=None): if fileName is None: fileName = QtGui.QFileDialog.getSaveFileName() fileName = str(fileName) PlotItem.lastFileDir = os.path.dirname(fileName) self.svg = QtSvg.QSvgGenerator() self.svg.setFileName(fileName) res = 120. view = self.scene().views()[0] bounds = view.viewport().rect() bounds = QtCore.QRectF(0, 0, bounds.width(), bounds.height()) self.svg.setResolution(res) self.svg.setViewBox(bounds) self.svg.setSize(QtCore.QSize(bounds.width(), bounds.height())) painter = QtGui.QPainter(self.svg) view.render(painter, bounds) painter.end() ## Workaround to set pen widths correctly import re data = open(fileName).readlines() for i in range(len(data)): line = data[i] m = re.match( r'(<g .*)stroke-width="1"(.*transform="matrix\(([^\)]+)\)".*)', line) if m is not None: #print "Matched group:", line g = m.groups() matrix = list(map(float, g[2].split(','))) #print "matrix:", matrix scale = max(abs(matrix[0]), abs(matrix[3])) if scale == 0 or scale == 1.0: continue data[i] = g[0] + ' stroke-width="%0.2g" ' % ( 1.0 / scale) + g[1] + '\n' #print "old line:", line #print "new line:", data[i] open(fileName, 'w').write(''.join(data))
def export(self, fileName=None): if fileName is None: self.fileSaveDialog(filter="Scalable Vector Graphics (*.svg)") return self.svg = QtSvg.QSvgGenerator() self.svg.setFileName(fileName) self.svg.setSize(QtCore.QSize(100,100)) #self.svg.setResolution(600) #self.svg.setViewBox() targetRect = QtCore.QRect(0, 0, self.params['width'], self.params['height']) sourceRect = self.getSourceRect() painter = QtGui.QPainter(self.svg) try: self.setExportMode(True) self.render(painter, QtCore.QRectF(targetRect), sourceRect) finally: self.setExportMode(False) painter.end() ## Workaround to set pen widths correctly data = open(fileName).readlines() for i in range(len(data)): line = data[i] m = re.match(r'(<g .*)stroke-width="1"(.*transform="matrix\(([^\)]+)\)".*)', line) if m is not None: #print "Matched group:", line g = m.groups() matrix = map(float, g[2].split(',')) #print "matrix:", matrix scale = max(abs(matrix[0]), abs(matrix[3])) if scale == 0 or scale == 1.0: continue data[i] = g[0] + ' stroke-width="%0.2g" ' % (1.0/scale) + g[1] + '\n' #print "old line:", line #print "new line:", data[i] open(fileName, 'w').write(''.join(data))
def exportdata(self): self.dialog = QtGui.QFileDialog() self.dialog.setOption(QtGui.QFileDialog.ShowDirsOnly) self.dialog.setFileMode(QtGui.QFileDialog.DirectoryOnly) folder_name = self.dialog.getSaveFileName(self, "Save Directory") filepath = os.path.join(os.path.abspath(os.sep), folder_name) if not os.path.exists(filepath): makedirs(filepath) # arr = QtCore.QByteArray() # buf = QtCore.QBuffer(arr) # svg = QtSvg.QSvgGenerator() # svg.setOutputDevice(buf) # dpi = QtGui.QDesktopWidget().physicalDpiX() # svg.setResolution(dpi) svg = QtSvg.QSvgGenerator() svg.setFileName("hh") svg.setSize(QtCore.QSize(2000, 2000)) svg.setViewBox(self.rect()) svg.setTitle("SVG svg Example Drawing") svg.setDescription("An SVG drawing created by the SVG Generator ") p = QtGui.QPainter() p.begin(svg) try: self.render(p) finally: p.end() # gen.setViewBox(QtGui.QRect(0, 0, 200, 200)); # gen.setTitle(tr("SVG Gen Example Drawing")); # gen.setDescription(tr("An SVG drawing created by the SVG Generator ""Example provided with Qt.")); lambda_data = os.path.join(filepath, "Lambda_data.csv") with open(lambda_data, "w") as output: try: writer = csv.writer(output, lineterminator='\n') for val in np.array(glo_var.lambdas)[:, 1]: writer.writerow([val]) except: pass summary = os.path.join(filepath, "Summary.csv") with open(summary, "w") as output: try: writer = csv.writer(output, delimiter='\t', lineterminator='\n') writer.writerow(["alpha", glo_var.alpha]) writer.writerow(["beta", glo_var.beta]) writer.writerow(["l", glo_var.l]) writer.writerow(["Phase", self.phas.pointer.region_aft]) except: pass # for name, pitem in self.pltlist: # self.exportimg(pitem,os.path.join(filepath,name + ".svg")) # # self.exportimg(pitem,os.path.join(filepath,name + ".png")) currentanddensity = os.path.join(filepath, "Current & Density.csv") with open(currentanddensity, "w") as output: writer = csv.writer(output, delimiter='\t', lineterminator='\n') # combine alpha, beta pre and post. Do it here to lessen the computation alpha_x_data = np.concatenate([ np.array(self.jalph.alphas_pre), np.linspace(self.jalph.trans_point, 1, 2) ]) alpha_j_data = np.concatenate( [self.jalph.j_l_values, np.array([self.jalph.jpost] * 2)]) alpha_rho_data = np.array(self.jalph.rho_avg_pre + self.jalph.rho_avg_post) beta_x_data = np.concatenate([ np.array(self.jbet.betas_pre), np.linspace(self.jbet.trans_point, 1, 2) ]) beta_j_data = np.concatenate( [self.jbet.j_r_values, np.array([self.jbet.jpost] * 2)]) beta_rho_data = np.array(self.jbet.rho_avg_pre + self.jbet.rho_avg_post) alpha_data = np.vstack( [alpha_x_data, alpha_j_data, alpha_rho_data]) beta_data = np.vstack([beta_x_data, beta_j_data, beta_rho_data]) writer.writerow([ "alpha", "Current", "Average Density", '\t', '\t', "beta", "Current", "Average Density" ]) for i in range(len(alpha_x_data)): writer.writerow( list(alpha_data[:, i]) + [''] * 2 + list(beta_data[:, i])) writer.writerow('\n') writer.writerow( ['beta', glo_var.beta, '', '', '', 'alpha', glo_var.alpha, '']) writer.writerow([ 'transition point', self.jalph.trans_point, '', '', '', 'transition point', self.jbet.trans_point, '' ]) self.pdfgroup1 = ['Lambda_fig', 'Density_fig'] self.pdfgroup2 = ['Current_alpha_fig', 'Current_beta_fig'] for name, pitem in self.pltlist: # self.exportimg(pitem,os.path.join(filepath,name + ".png")) path = os.path.join(filepath, name + ".svg") # if name == 'Current_alpha_fig': # self.jalph.p3.setLabel('right',"\u2329\u03c1 \u232a",**glo_var.labelstyle) # self.jalph.p3main.plotItem.legend.items=[] # self.jalph.p3.plot(pen=self.jalph.jpen, name='J') # self.jalph.p3.plot(pen=self.jalph.rho_dash, name='\u2329\u03c1 \u232a') # elif name == 'Current_beta_fig': # self.jbet.p4.setLabel('right',"\u2329\u03c1 \u232a",**glo_var.labelstyle) # self.jbet.p4main.plotItem.legend.items=[] # self.jbet.p4.plot(pen=self.jbet.jpen, name='J') # self.jbet.p4.plot(pen=self.jbet.rho_dash, name='\u2329\u03c1 \u232a') self.exportimg(pitem, path) if name in self.pdfgroup1: self.makepdf(path, os.path.join(filepath, name + ".pdf"), 500, 260, 20, 240) elif name == 'Current_alpha_fig': self.makepdf(path, os.path.join(filepath, name + ".pdf"), 350, 280, 30, 230) # self.jalph.p3.setLabel('right',"\u2329 \u03c1 \u232a",**glo_var.labelstyle) # self.jalph.p3main.plotItem.legend.items=[] # self.jalph.p3.plot(pen=self.jalph.jpen, name='J') # self.jalph.p3.plot(pen=self.jalph.rho_dash, name='\u2329 \u03c1 \u232a') elif name == 'Current_beta_fig': self.makepdf(path, os.path.join(filepath, name + ".pdf"), 350, 280, 30, 230) # self.jbet.p4.setLabel('right',"\u2329 \u03c1 \u232a",**glo_var.labelstyle) # self.jbet.p4main.plotItem.legend.items=[] # self.jbet.p4.plot(pen=self.jbet.jpen, name='J') # self.jbet.p4.plot(pen=self.jbet.rho_dash, name='\u2329 \u03c1 \u232a') else: self.makepdf(path, os.path.join(filepath, name + ".pdf"), 410, 330, 10, 300) os.remove(path)
def _generateItemSvg(item, nodes=None, root=None): ## This function is intended to work around some issues with Qt's SVG generator ## and SVG in general. ## 1) Qt SVG does not implement clipping paths. This is absurd. ## The solution is to let Qt generate SVG for each item independently, ## then glue them together manually with clipping. ## ## The format Qt generates for all items looks like this: ## ## <g> ## <g transform="matrix(...)"> ## one or more of: <path/> or <polyline/> or <text/> ## </g> ## <g transform="matrix(...)"> ## one or more of: <path/> or <polyline/> or <text/> ## </g> ## . . . ## </g> ## ## 2) There seems to be wide disagreement over whether path strokes ## should be scaled anisotropically. ## see: http://web.mit.edu/jonas/www/anisotropy/ ## Given that both inkscape and illustrator seem to prefer isotropic ## scaling, we will optimize for those cases. ## ## 3) Qt generates paths using non-scaling-stroke from SVG 1.2, but ## inkscape only supports 1.1. ## ## Both 2 and 3 can be addressed by drawing all items in world coordinates. profiler = debug.Profiler() if nodes is None: ## nodes maps all node IDs to their XML element. ## this allows us to ensure all elements receive unique names. nodes = {} if root is None: root = item ## Skip hidden items if hasattr(item, 'isVisible') and not item.isVisible(): return None ## If this item defines its own SVG generator, use that. if hasattr(item, 'generateSvg'): return item.generateSvg(nodes) ## Generate SVG text for just this item (exclude its children; we'll handle them later) tr = QtGui.QTransform() if isinstance(item, QtGui.QGraphicsScene): xmlStr = "<g>\n</g>\n" doc = xml.parseString(xmlStr) childs = [i for i in item.items() if i.parentItem() is None] elif item.__class__.paint == QtGui.QGraphicsItem.paint: xmlStr = "<g>\n</g>\n" doc = xml.parseString(xmlStr) childs = item.childItems() else: childs = item.childItems() tr = itemTransform(item, item.scene()) ## offset to corner of root item if isinstance(root, QtGui.QGraphicsScene): rootPos = QtCore.QPoint(0, 0) else: rootPos = root.scenePos() tr2 = QtGui.QTransform() tr2.translate(-rootPos.x(), -rootPos.y()) tr = tr * tr2 arr = QtCore.QByteArray() buf = QtCore.QBuffer(arr) svg = QtSvg.QSvgGenerator() svg.setOutputDevice(buf) dpi = QtGui.QDesktopWidget().logicalDpiX() svg.setResolution(dpi) p = QtGui.QPainter() p.begin(svg) if hasattr(item, 'setExportMode'): item.setExportMode(True, {'painter': p}) try: p.setTransform(tr) item.paint(p, QtGui.QStyleOptionGraphicsItem(), None) finally: p.end() ## Can't do this here--we need to wait until all children have painted as well. ## this is taken care of in generateSvg instead. #if hasattr(item, 'setExportMode'): #item.setExportMode(False) if USE_PYSIDE: xmlStr = str(arr) else: xmlStr = bytes(arr).decode('utf-8') doc = xml.parseString(xmlStr.encode('utf-8')) try: ## Get top-level group for this item g1 = doc.getElementsByTagName('g')[0] ## get list of sub-groups g2 = [ n for n in g1.childNodes if isinstance(n, xml.Element) and n.tagName == 'g' ] defs = doc.getElementsByTagName('defs') if len(defs) > 0: defs = [ n for n in defs[0].childNodes if isinstance(n, xml.Element) ] except: print(doc.toxml()) raise profiler('render') ## Get rid of group transformation matrices by applying ## transformation to inner coordinates correctCoordinates(g1, defs, item) profiler('correct') ## make sure g1 has the transformation matrix #m = (tr.m11(), tr.m12(), tr.m21(), tr.m22(), tr.m31(), tr.m32()) #g1.setAttribute('transform', "matrix(%f,%f,%f,%f,%f,%f)" % m) #print "=================",item,"=====================" #print g1.toprettyxml(indent=" ", newl='') ## Inkscape does not support non-scaling-stroke (this is SVG 1.2, inkscape supports 1.1) ## So we need to correct anything attempting to use this. #correctStroke(g1, item, root) ## decide on a name for this item baseName = item.__class__.__name__ i = 1 while True: name = baseName + "_%d" % i if name not in nodes: break i += 1 nodes[name] = g1 g1.setAttribute('id', name) ## If this item clips its children, we need to take care of that. childGroup = g1 ## add children directly to this node unless we are clipping if not isinstance(item, QtGui.QGraphicsScene): ## See if this item clips its children if int(item.flags() & item.ItemClipsChildrenToShape) > 0: ## Generate svg for just the path #if isinstance(root, QtGui.QGraphicsScene): #path = QtGui.QGraphicsPathItem(item.mapToScene(item.shape())) #else: #path = QtGui.QGraphicsPathItem(root.mapToParent(item.mapToItem(root, item.shape()))) path = QtGui.QGraphicsPathItem(item.mapToScene(item.shape())) item.scene().addItem(path) try: #pathNode = _generateItemSvg(path, root=root).getElementsByTagName('path')[0] pathNode = _generateItemSvg( path, root=root)[0].getElementsByTagName('path')[0] # assume <defs> for this path is empty.. possibly problematic. finally: item.scene().removeItem(path) ## and for the clipPath element clip = name + '_clip' clipNode = g1.ownerDocument.createElement('clipPath') clipNode.setAttribute('id', clip) clipNode.appendChild(pathNode) g1.appendChild(clipNode) childGroup = g1.ownerDocument.createElement('g') childGroup.setAttribute('clip-path', 'url(#%s)' % clip) g1.appendChild(childGroup) profiler('clipping') ## Add all child items as sub-elements. childs.sort(key=lambda c: c.zValue()) for ch in childs: csvg = _generateItemSvg(ch, nodes, root) if csvg is None: continue cg, cdefs = csvg childGroup.appendChild( cg ) ### this isn't quite right--some items draw below their parent (good enough for now) defs.extend(cdefs) profiler('children') return g1, defs