def l_function_maass_browse_page(): info = {"bread": get_bread(2, [("Maass Form", url_for('.l_function_maass_browse_page'))])} info["contents"] = [processMaassNavigation()] info["gl2spectrum0"] = [paintSvgMaass(1, 10, 0, 10, L="/L")] info["colorminus1"] = rgbtohex(signtocolour(-1)) info["colorplus1"] = rgbtohex(signtocolour(1)) return render_template("MaassformGL2.html", title='L-functions of GL(2) Maass Forms of Weight 0', **info)
def browse_graph(min_level, max_level, min_R, max_R): r""" Render a page with a graph with clickable dots for all with min_R <= R <= max_R and levels in the similar range. """ info = {} info['contents'] = [paintSvgMaass(min_level, max_level, min_R, max_R)] info['min_level'] = min_level info['max_level'] = max_level info['min_R'] = min_R info['max_R'] = max_R info['coloreven'] = rgbtohex(signtocolour(1)) info['colorodd'] = rgbtohex(signtocolour(-1)) bread = bread_prefix() + [('Browse graph', '')] info['bread'] = bread info['learnmore'] = learnmore_list() return render_template("maass_browse_graph.html", title='Browsing graph of Maass forms', **info)
def render_maass_browse_graph(min_level, max_level, min_R, max_R): r""" Render a page with a graph with clickable dots for all with min_R <= R <= max_R and levels in the similar range. """ info = {} info['contents'] = [paintSvgMaass(min_level, max_level, min_R, max_R)] info['min_level'] = min_level info['max_level'] = max_level info['min_R'] = min_R info['max_R'] = max_R info['coloreven'] = rgbtohex(signtocolour(1)) info['colorodd'] = rgbtohex(signtocolour(-1)) bread = [('Modular forms', url_for('mf.modular_form_main_page')), ('Maass waveforms', url_for('.render_maass_waveforms'))] info['bread'] = bread return render_template("mwf_browse_graph.html", title='Browsing graph of Maass forms', **info)
def render_maass_browse_graph(min_level, max_level, min_R, max_R): r""" Render a page with a graph with clickable dots for all with min_R <= R <= max_R and levels in the similar range. """ info = {} info['contents'] = [paintSvgMaass(min_level, max_level, min_R, max_R)] info['min_level'] = min_level info['max_level'] = max_level info['min_R'] = min_R info['max_R'] = max_R info['coloreven'] = rgbtohex(signtocolour(1)) info['colorodd'] = rgbtohex(signtocolour(-1)) bread = [('Modular Forms', url_for('mf.modular_form_main_page')), ('Maass Waveforms', url_for('.render_maass_waveforms'))] info['bread'] = bread return render_template("mwf_browse_graph.html", title='Browsing graph of Maass forms', **info)
def test_signtocolour(self): r""" Checking utility: signtocolour """ self.assertEqual(signtocolour(0), 'rgb(63,63,255)') self.assertEqual(signtocolour(1 + 2j), 'rgb(197,0,184)')
def test_signtocolour(self): r""" Checking utility: signtocolour """ self.assertEqual(signtocolour(0), 'rgb(63,63,255)') self.assertEqual(signtocolour(1+2j), 'rgb(197,0,184)')
def paintSvgMaass(min_level, max_level, min_R, max_R, weight=0, char=1, width=1000, heightfactor=20, L=""): ''' Returns the contents (as a string) of the svg-file for all Maass forms in the database. Takes all levels from min_level to max_level Spectral parameter in [min_R, max_R] Set L="/L" to make link go to the L-function ''' xMax = int(max_R) yMax = int(max_level) xMin = int(min_R) yMin = int(min_level) extraSpace = 40 length_R = xMax - xMin length_level = yMax - yMin + 1 if length_level < 15: heightfactor = heightfactor * 2 height = length_level * heightfactor + extraSpace xfactor = (width - extraSpace)/length_R yfactor = (height - extraSpace)/length_level ticlength = 4 radius = 3 xshift = extraSpace # Start of file and add coordinate system ans = "<svg xmlns='http://www.w3.org/2000/svg'" ans += " xmlns:xlink='http://www.w3.org/1999/xlink'" ans += " height='{0}' width='{1}'>\n".format(height + 20, width + 20) ans += paintCSMaass(width, height, xMin, xMax, yMin, yMax, xfactor, yfactor, ticlength, xshift) # Fetch Maass forms from database # NB although base.getDBConnection().PORT works it gives the # default port number of 27017 and not the actual one! if pymongo.version_tuple[0] < 3: host = base.getDBConnection().host port = base.getDBConnection().port else: host, port = base.getDBConnection().address db = MaassDB(host=host, port=port) search = {'level1': yMin, 'level2': yMax, 'char': char, 'R1': xMin, 'R2': xMax, 'Newform' : None, 'weight' : weight} fields = {'Eigenvalue', 'Level', 'Symmetry'} forms = db.get_Maass_forms(search, fields, do_sort=False, limit=10000) # Loop through all forms and add a clickable dot for each for f in forms: linkurl = L + "/ModularForm/GL2/Q/Maass/{0}".format(f['_id']) x = (f['Eigenvalue'] - xMin) * xfactor + xshift y = (f['Level'] - yMin + 1) * yfactor try: # Shifting even slightly up and odd slightly down if f['Symmetry'] == 0 or f['Symmetry'] == 'even': y -= 1 color = signtocolour(1) elif f['Symmetry'] == 1 or f['Symmetry'] == 'odd': y += 1 color = signtocolour(-1) else: color = signtocolour(0) except Exception: color = signtocolour(0) ans += "<a xlink:href='{0}' target='_top'>".format(linkurl) ans += "<circle cx='{0}' cy='{1}' ".format(str(x)[0:6],str(y)) ans += "r='{0}' style='fill:{1}'>".format(str(radius),color) ans += "<title>{0}</title></circle></a>\n".format(f['Eigenvalue']) ans += "</svg>" return ans
def paintSvgMaass(min_level, max_level, min_R, max_R, weight=0, char=1, width=1000, heightfactor=20, L=""): ''' Returns the contents (as a string) of the svg-file for all Maass forms in the database. Takes all levels from min_level to max_level Spectral parameter in [min_R, max_R] Set L="/L" to make link go to the L-function ''' xMax = int(max_R) yMax = int(max_level) xMin = int(min_R) yMin = int(min_level) extraSpace = 40 length_R = xMax - xMin length_level = yMax - yMin + 1 if length_level < 15: heightfactor = heightfactor * 2 height = length_level * heightfactor + extraSpace xfactor = (width - extraSpace) / length_R yfactor = (height - extraSpace) / length_level ticlength = 4 radius = 3 xshift = extraSpace # Start of file and add coordinate system ans = "<svg xmlns='http://www.w3.org/2000/svg'" ans += " xmlns:xlink='http://www.w3.org/1999/xlink'" ans += " height='{0}' width='{1}'>\n".format(height + 20, width + 20) ans += paintCSMaass(width, height, xMin, xMax, yMin, yMax, xfactor, yfactor, ticlength, xshift) # Fetch Maass forms from database search = { 'level1': yMin, 'level2': yMax, 'char': char, 'R1': xMin, 'R2': xMax, 'Newform': None, 'weight': weight } projection = ['maass_id', 'Eigenvalue', 'Level', 'Symmetry'] forms = maass_db.get_Maass_forms(search, projection, sort=[], limit=10000) # Loop through all forms and add a clickable dot for each for f in forms: linkurl = L + "/ModularForm/GL2/Q/Maass/{0}".format(f['maass_id']) x = (f['Eigenvalue'] - xMin) * xfactor + xshift y = (f['Level'] - yMin + 1) * yfactor try: # Shifting even slightly up and odd slightly down if f['Symmetry'] == 0 or f['Symmetry'] == 'even': y -= 1 color = signtocolour(1) elif f['Symmetry'] == 1 or f['Symmetry'] == 'odd': y += 1 color = signtocolour(-1) else: color = signtocolour(0) except Exception: color = signtocolour(0) ans += "<a xlink:href='{0}' target='_top'>".format(linkurl) ans += "<circle cx='{0}' cy='{1}' ".format(str(x)[0:6], str(y)) ans += "r='{0}' style='fill:{1}'>".format(str(radius), color) ans += "<title>{0}</title></circle></a>\n".format(f['Eigenvalue']) ans += "</svg>" return ans
def paintSvgHoloGeneral(Nmin, Nmax, kmin, kmax, imagewidth, imageheight): # the import must be here to avoid circular import from lmfdb.classical_modular_forms.web_newform import WebNewform from lmfdb.classical_modular_forms.web_space import WebGamma1Space xfactor = 90 yfactor = 30 extraSpace = 20 ticlength = 4 radius = 3.3 xdotspacing = 0.30 # horizontal spacing of dots ydotspacing = 0.11 # vertical spacing of dots # colourplus = signtocolour(1) # not used # colourminus = signtocolour(-1) # not used maxdots = 5 # max number of dots to display ans = svgBegin() xMax = int(Nmax) yMax = int(kmax) width = xfactor * xMax + extraSpace height = yfactor * yMax + extraSpace # make the coordinate system ans += paintCSHoloTMP(width, height, xMax, yMax, xfactor, yfactor, ticlength) alphabet = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'] # create appearanceinfo, common to all points appearanceinfo = [] # loop over levels and weights, using plotsector to put the appropriate dots at each lattice point for x in range(int(Nmin), int(Nmax) + 1): # x is the level for y in range(int(kmin), int(kmax) + 1, 2): # y is the weight # lid = "(" + str(x) + "," + str(y) + ")" # not used # linkurl = "/L/ModularForm/GL2/Q/holomorphic/" + str(y) + "/" + str(x) + "/1/" # not used WS = WebGamma1Space( level=x, weight=y) # space of modular forms of weight y, level x galois_orbits = WS.decomp # make a list of Galois orbits numlabels = len(galois_orbits) # one label per Galois orbit thelabels = alphabet[ 0: numlabels] # list of labels for the Galois orbits for weight y, level x # countplus = 0 # count how many Galois orbits have sign Plus (+ 1) (not used) # countminus = 0 # count how many Galois orbits have sign Minus (- 1) (not used) # ybaseplus = y # baseline y-coord for plus cases (not used) # ybaseminus = y # baseline y-coord for minus cases (not used) # numpluslabels = 0 # not used # numminuslabels = 0 # not used # plotsector requires three dictionaries: dimensioninfo, appearanceinfo, and urlinfo # create dimensioninfo dimensioninfo = {} dimensioninfo['offset'] = [0, height] dimensioninfo['scale'] = [xfactor, -1 * yfactor] dimensioninfo['vertexlocation'] = [x, y] dimensioninfo['maxdots'] = maxdots dimensioninfo['dotspacing'] = [xdotspacing, ydotspacing] dimensioninfo['edge'] = [[0, 1], [1, 0] ] # unit vectors defining edges of sector # dimensioninfo['edgelength'] = [float(dimensioninfo['scale'][0])/float(Nmax), float(dimensioninfo['scale'][1])/float(kmax)] #add comment dimensioninfo['edgelength'] = [0.5, 0.5] dimensioninfo['dotradius'] = radius dimensioninfo[ 'connectinglinewidth'] = dimensioninfo['dotradius'] / 1.5 dimensioninfo['firstdotoffset'] = [0.0, 0.0] # appearanceinfo = {} # appearanceinfo['edgewidth'] = dimensioninfo['dotspacing'][0]/1.0 #just a guess appearanceinfo['edgewidth'] = [0, 0] # remove the sector edges appearanceinfo['edgestyle'] = 'stroke-dasharray:3,3' appearanceinfo['edgecolor'] = 'rgb(202,202,102)' appearanceinfo['fontsize'] = 'font-size:11px' appearanceinfo['fontweight'] = "" # urlinfo = {'base': '/L/ModularForm/GL2/Q/holomorphic?'} urlinfo['space'] = {'weight': y} urlinfo['space']['level'] = x urlinfo['space']['character'] = 0 # # scale = 1 # not used # Symmetry types: +1 or -1 symmetrytype = [1, -1] for signtmp in symmetrytype: # urlinfo['space']['orbits'] = [ [] for label in thelabels ] # initialise # an empty list for each orbit urlinfo['space']['orbits'] = [] for label in thelabels: # looping over Galois orbit: one label per orbit # do '+' case first MF = WebNewform.by_label( label=label ) # one of the Galois orbits for weight y, level x numberwithlabel = MF.degree( ) # number of forms in the Galois orbit if x == 1: # For level 1, the sign is always plus signfe = 1 else: # signfe = -1 frickeeigenvalue = prod(MF.atkin_lehner_eigenvalues( ).values()) # gives Fricke eigenvalue signfe = frickeeigenvalue * (-1)**float( y / 2) # sign of functional equation if signfe == signtmp: # we find an orbit with sign of "signtmp" if signfe == 1: dimensioninfo['edge'] = [[0, 1], [1, 0]] # unit vectors defining edges of sector for signfe positive else: # dimensioninfo['edge'] = [[0,1],[-1,0]] # unit vectors defining edges # of sector for signfe negative dimensioninfo['edge'] = [[0, -1], [-1, 0]] # unit vectors defining edges of sector for signfe negative dimensioninfo['dotspacing'] = [ signfe * xdotspacing, ydotspacing ] dimensioninfo['firstdotoffset'] = [ 0.5 * (dimensioninfo['dotspacing'][0] * dimensioninfo['edge'][0][0] + dimensioninfo['dotspacing'][1] * dimensioninfo['edge'][1][0]), 0 ] signcolour = signtocolour(signfe) appearanceinfo['edgecolor'] = signcolour orbitdescriptionlist = [] for n in range(numberwithlabel): orbitdescriptionlist.append({ 'label': label, 'number': n, 'color': signcolour }) urlinfo['space']['orbits'].append(orbitdescriptionlist) # urlinfo['space']['orbits'][0][0]['color'] = signtocolour(-1) # appearanceinfo['orbitcolor'] = 'rgb(102,102,102)' ans += plotsector(dimensioninfo, appearanceinfo, urlinfo) ans += svgEnd() return (ans)
def paintSvgHolo(Nmin, Nmax, kmin, kmax): # the import must be here to avoid circular import from lmfdb.classical_modular_forms.web_space import WebGamma1Space xfactor = 90 yfactor = 30 extraSpace = 20 ticlength = 4 radius = 3.3 xdotspacing = 0.11 # horizontal spacing of dots ydotspacing = 0.28 # vertical spacing of dots colourplus = signtocolour(1) colourminus = signtocolour(-1) maxdots = 5 # max number of dots to display ans = svgBegin() xMax = int(Nmax) yMax = int(kmax) width = xfactor * xMax + extraSpace height = yfactor * yMax + extraSpace ans += paintCSHolo(width, height, xMax, yMax, xfactor, yfactor, ticlength) # alphabet = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'] # loop over levels and weights for x in range(int(Nmin), int(Nmax) + 1): # x is the level for y in range(int(kmin), int(kmax) + 1): # y is the weight # lid = "(" + str(x) + "," + str(y) + ")" # not used linkurl = "/L/ModularForm/GL2/Q/holomorphic/" + str(x) + "/" + str( y) + "/1/" try: WS = WebGamma1Space(level=x, weight=y) except ValueError: continue newspaces = WS.decomp # numlabels = len(WS.decomp) # one label per Galois orbit # thelabels = alphabet[0:numlabels] # list of labels for the Galois orbits for weight y, level x # countplus = 0 # count how many Galois orbits have sign Plus (+ 1) # not used # countminus = 0 # count how many Galois orbits have sign Minus (- 1) # not used ybaseplus = y # baseline y-coord for plus cases ybaseminus = y # baseline y-coord for minus cases numpluslabels = 0 numminuslabels = 0 for newsp in newspaces: # looping over Galois orbit for MF in newsp[1]: print(MF) linkurl = "/L/ModularForm/GL2/Q/holomorphic/%d/%d/%s/%s/" % ( x, y, MF['char_orbit_label'], cremona_letter_code(MF['hecke_orbit'] - 1)) numberwithlabel = MF[ 'dim'] # number of forms in the Galois orbit # frickeeigenvalue = prod(MF.atkin_lehner_eigenvalues().values()) # gives Fricke eigenvalue self_dual = MF['char_is_real'] * (-1)**float( y / 2) # sign of functional equation xbase = x - self_dual * (xdotspacing / 2.0) if self_dual > 0: # go to right in BLUE if plus ybase = ybaseplus ybaseplus += ydotspacing thiscolour = colourplus numpluslabels += 1 else: # go to the left in RED of minus ybase = ybaseminus ybaseminus += ydotspacing thiscolour = colourminus numminuslabels += 1 if numberwithlabel > maxdots: # if more than maxdots in orbit, use number as symbol xbase += 1.5 * self_dual * xdotspacing if self_dual < 0: # move over more to position numbers on minus side. xbase += self_dual * xdotspacing ybase += -0.5 * ydotspacing if (self_dual > 0 and numpluslabels > 1) or ( self_dual < 0 and numminuslabels > 1): ybase += ydotspacing ans += "<a xlink:href='" + url_for( 'not_yet_implemented') + "' target='_top'>\n" # TODO: Implement when there is more than maxdots forms ans += ("<text x='" + str(float(xbase) * xfactor)[0:7] + "' y='" + str(height - float(ybase) * yfactor)[0:7] + "' style='fill:" + thiscolour + ";font-size:14px;font-weight:bold;'>" + str(numberwithlabel) + "</text>\n") ans += "</a>\n" if self_dual < 0: ybaseminus += 1.5 * ydotspacing else: ybaseplus += 1.5 * ydotspacing else: # otherwise, use one dot per form in orbit, connected with a line if numberwithlabel > 1: # join dots if there are at least two # add lines first and then dots to prevent line from hiding link firstcenterx = xbase + self_dual * xdotspacing firstcentery = ybase lastcenterx = xbase + (numberwithlabel * self_dual * xdotspacing) lastcentery = ybase ans += "<line x1='%s' " % str( float(firstcenterx) * xfactor)[0:7] ans += "y1='%s' " % str( float(height - firstcentery * yfactor))[0:7] ans += "x2='%s' " % str( float(lastcenterx) * xfactor)[0:7] ans += "y2='%s' " % str( float(height - lastcentery * yfactor))[0:7] ans += "style='stroke:%s;stroke-width:2.4'/>" % thiscolour for number in range(0, numberwithlabel): xbase += self_dual * xdotspacing ans += "<a xlink:href='" + linkurl + str( number + 1) + "/' target='_top'>\n" ans += "<circle cx='" + str( float(xbase) * xfactor)[0:7] ans += "' cy='" + str(height - float(ybase) * yfactor)[0:7] ans += "' r='" + str(radius) ans += "' style='fill:" + thiscolour + "'>" ans += "<title>" + str((x, y)).replace( "u", "").replace("'", "") + "</title>" ans += "</circle></a>\n" ans += svgEnd() return ans
def paintSvgFileAll(glslist): # list of group and level xfactor = 20 yfactor = 20 extraSpace = 20 ticlength = 4 radius = 3 ans = svgBegin() paralist = [] xMax = 0 yMax = 0 for gls in glslist: group = gls[0] level = gls[1] for l in db.lfunc_lfunctions.search( { 'group': group, 'conductor': level }, ['origin', 'root_number']): splitOrigin = l['origin'].split('/') char = splitOrigin[5] R = splitOrigin[6] ap_id = splitOrigin[7] splitId = R.split('_') paralist.append((splitId[0], splitId[1], l['origin'], group, level, char, R, ap_id, l['root_number'])) if float(splitId[0]) > xMax: xMax = float(splitId[0]) if float(splitId[1]) > yMax: yMax = float(splitId[1]) xMax = int(math.ceil(xMax)) yMax = int(math.ceil(yMax)) width = xfactor * xMax + extraSpace height = yfactor * yMax + extraSpace ans += paintCS(width, height, xMax, yMax, xfactor, yfactor, ticlength) for (x, y, lid, group, level, char, R, ap_id, sign) in paralist: if float(x) > 0 and float(y) > 0: # Only one of dual pair try: linkurl = url_for('.l_function_maass_gln_page', group=group, level=level, char=char, R=R, ap_id=ap_id) except Exception: # catch when running a test linkurl = lid ans += "<a xlink:href='" + linkurl + "' target='_top'>\n" ans += "<circle cx='" + str(float(x) * xfactor)[0:7] ans += "' cy='" + str(height - float(y) * yfactor)[0:7] ans += "' r='" + str(radius) ans += "' style='fill:" + signtocolour(sign) + "'>" ans += "<title>" + str( (x, y)).replace("u", "").replace("'", "") + "</title>" ans += "</circle></a>\n" ans += svgEnd() return (ans)
def paintSvgMaass(min_level, max_level, min_R, max_R, width=1000, heightfactor=20, L=""): ''' Returns the contents (as a string) of the svg-file for all Maass forms in the database of the specified weight. Takes all levels from min_level to max_level Spectral parameter in [min_R, max_R] Set L="/L" to make link go to the L-function ''' xMax = int(max_R) yMax = int(max_level) xMin = int(min_R) yMin = int(min_level) extraSpace = 40 length_R = xMax - xMin length_level = yMax - yMin + 1 if length_level < 30: heightfactor = heightfactor * 2 height = length_level * heightfactor + extraSpace xfactor = (width - extraSpace) / length_R yfactor = (height - extraSpace) / length_level ticlength = 4 radius = 3 xshift = extraSpace # Start of file and add coordinate system ans = "<svg xmlns='http://www.w3.org/2000/svg'" ans += " xmlns:xlink='http://www.w3.org/1999/xlink'" ans += " height='{0}' width='{1}'>\n".format(height + 20, width + 20) ans += paintCSMaass(width, height, xMin, xMax, yMin, yMax, xfactor, yfactor, ticlength, xshift) # Fetch Maass forms from database forms = db.maass_newforms.search( { 'spectral_parameter': { '$gte': xMin, '$lte': xMax }, 'level': { '$gte': yMin, '$lte': yMax } }, ["maass_id", "spectral_parameter", "level", "symmetry"], sort=[("level", 1), ("symmetry", -1), ("spectral_parameter", 1), ("maass_id", 1)]) # Loop through all forms and add a clickable dot for each for f in forms: linkurl = L + url_for("maass.by_label", label=f['maass_id']) x = (f['spectral_parameter'] - xMin) * xfactor + xshift y = (f['level'] - yMin + 1) * yfactor s = f.get('symmetry', 0) y -= s # Shifting even slightly up and odd slightly down color = signtocolour(s) ans += "<a xlink:href='{0}' target='_top'>".format(linkurl) ans += "<circle cx='{0}' cy='{1}' ".format(str(x)[0:6], str(y)) ans += "r='{0}' style='fill:{1}'>".format(str(radius), color) ans += "<title>{0}</title></circle></a>\n".format( f['spectral_parameter']) ans += "</svg>" return ans