MapInfo Pro Developers User Group

 View Only
Expand all | Collapse all

MapBasic Monday: Add thematic legend to a Layout / Presentation programmatically

  • 1.  MapBasic Monday: Add thematic legend to a Layout / Presentation programmatically

    Posted 20 days ago
    Edited by Peter Møller 15 days ago

    Hi everyone,
    I'm working with MapBasic and I'm generating a thematic map (Shade) on an already opened Map window. After creating the thematic layer, I create a Layout (presentation) by code and I want to automatically add the corresponding legend into the Layout as a legend frame/object.

    Right now, I can:

    • detect the active/open Map window (the one the user is viewing),

    • create/apply the thematic mapping by Run Command (e.g. Shade window ...),

    • create a Layout and place map frames/text frames.

    What I'm missing is the "best practice" / correct MapBasic approach to:

    1. create (or reference) the thematic legend for the active Map window, and

    2. insert that legend into the Layout as a legend frame (positioned and sized programmatically).

    Questions:

    • Is there a recommended MapBasic sequence to generate the legend object for a thematic layer and place it in a Layout?

    • Do I need to create a separate Legend window first, and then copy/insert it into the Layout, or can the legend frame be created directly in the Layout referencing the Map window/layer?

    • Which MapBasic statements/functions are typically used for this (e.g., Create Legend, Set Legend, Add Frame, Create Map Frame, etc.)?

    If useful, I'm currently creating the thematic map with something like:

    • Run Command "Shade window <mapWin> <layer> with <column> ..."

    Then I create the Layout and frames. I just don't know the proper way to attach the legend of that thematic to the layout automatically.

    Any sample code or guidance would be greatly appreciated (especially how to reference the correct map/layer and ensure the legend matches the current thematic).

    Thanks!

    Sub TEMATICO_INFRAESTR_VIARIA
    
    OnError GoTo errorTematicoViaria
    
    '1) Cargar configuración guardada
    '2) Cargar parámetros geométricos
    '3) Crear layout con tamaño correcto
    '4) Aplicar formato impresora
    '5) Insertar frames usando coordenadas parametrizadas
    
    Dim nMapID, nMapIDInLayout, nLayoutID, nLegendID, i As Integer
    Dim strStatement, cmdstr, str_tit_principal, str_tit_leyenda as string
    
    strTitulo = "MUNICIPIO: "+gblNOMBRE_MUNICIPIO+chr$(13)+"NÚCLEO:"+gblNOMBRE_NUCLEO
    
    Call CARGAR_PARAM_TEMATICOS
    
    'Set Printer Name gblThematicPrinter
    
    ''##### ASIGNANDO NOMBRE DEL MUNICIPIO ENCUESTADO Y RUTA DE ARCHIVOS ###############
    Call TEMATICO_CARGAR_PARAMETROS
    
    str_tit_principal = WindowInfo(FrontWindow(), WIN_INFO_NAME)
    
    '**Let's find a map window to insert
    For i = 1 To NumWindows()
        If WindowInfo(WindowID(i), WIN_INFO_TYPE) = WIN_MAPPER Then
          nMapID = WindowID(i)
          Exit For
        End If
    Next
    Print "Map: " & WindowInfo(nMapID, WIN_INFO_NAME)
    
    Dim strMapName As String
    Dim strMunicipio As String
    Dim strNucleo As String
    Dim strTematico As String
    Dim posGuion As Integer
    Dim posAsterisco As Integer
    
    strMapName = WindowInfo(nMapID, WIN_INFO_NAME)
    
    posGuion = InStr(1, strMapName, " - ")
    posAsterisco = InStr(1, strMapName, "*")
    
    If posGuion > 0 Then
        strMunicipio = Left$(strMapName, Len(posGuion) - 1)
    End If
    
    If posAsterisco > 0 Then
        strNucleo = Mid$(strMapName, posGuion + 3, posAsterisco - (Len(posGuion) + 3))
        strTematico = Mid$(strMapName, posAsterisco + 1, Len(strMapName) - posAsterisco)
    End If
    
    'Create Layout window
    Layout Designer
        Position (0.0,0.0) Units "in"
        Width pWidth  Height pHeight  Units "in"
    
    nLayoutID = FrontWindow()
    i_layout_id = FrontWindow()
    Set Layout
        Window nLayoutID
        Extents To Fit Zoom 100
    
    Set CoordSys Layout Units "in"
    Set Paper Units "In"
    
    Call TEMATICO_FORMATO_IMPRIMIR_PAPEL
     
    Dim ancho As Float
    Dim alto As Float
    
    ancho = LayoutInfo(nLayoutID, LAYOUT_INFO_WIDTH)
    alto  = LayoutInfo(nLayoutID, LAYOUT_INFO_HEIGHT)
    
    Dim margen As Float
    Dim franja As Float
    Dim banda As Float
    
    margen = ancho * 0.03          ' 3% margen
    franja = ancho * 0.18          ' 18% franja derecha
    banda  = alto * 0.10           ' 10% banda superior
    
    'Insert Map into Layout
    Create Frame Into Window nLayoutID (margen, margen)  (ancho-franja, alto-banda)
        'Pen (1,2,0) Brush (2, 16777215, 16777215)
        From Window nMapID
        FillFrame On
    
    nMapIDInLayout = WindowID(0)
    
    num_win_principal = nMapID
    
    Call TEMATICO_CAPAS_AUXILIARES
    
    Dim colX1 As Float
    Dim colX2 As Float
    Dim zonaY1 As Float
    Dim zonaY2 As Float
    Dim bloqueAltura As Float
    Dim logoY1 As Float
    Dim logoY2 As Float
    Dim textoY1 As Float
    Dim textoY2 As Float
    
    logoY1 = zonaY1
    logoY2 = zonaY2 - 2*bloqueAltura
    
    textoY1 = logoY2
    textoY2 = logoY2 + (bloqueAltura * 0.40)
    
    colX1 = ancho - franja + margen/2
    colX2 = ancho - margen/2
    
    zonaY1 = margen
    zonaY2 = alto - banda
    
    bloqueAltura = (zonaY2 - zonaY1) / 3
    
    Dim alturaTotal As Float
    Dim hLoc As Float
    Dim hNorte As Float
    Dim hLogo As Float
    Dim hTexto As Float
    
    colX1 = ancho - franja + margen/2
    colX2 = ancho - margen/2
    
    zonaY1 = margen
    zonaY2 = alto - banda
    
    alturaTotal = zonaY2 - zonaY1
    
    hLoc   = alturaTotal * 0.35
    hNorte = alturaTotal * 0.20
    hLogo  = alturaTotal * 0.25
    hTexto = alturaTotal * 0.20
    
    Dim yActual As Float
    yActual = zonaY2
    
    'LOCALIZACIÓN
    'Create Frame Into Window nLayoutID (colX1, zonaY2 - 2*bloqueAltura)  (colX2, zonaY2)
    Create Frame Into Window nLayoutID (colX1, yActual - hLoc) (colX2, yActual)
        Pen (1,2,0)
        Brush (2,16777215,16777215)
        From Window num_win_localizacion
        FillFrame On
    
    yActual = yActual - hLoc
    
    'NORTE
    'Create Frame Into Window nLayoutID (colX1, zonaY2 - 2*bloqueAltura)  (colX2, zonaY2 - bloqueAltura)
    Create Frame Into Window nLayoutID (colX1, yActual - hNorte) (colX2, yActual)
        Pen (1,2,0)
        Brush (2,16777215,16777215)
        From Window num_win_norte
        FillFrame On
    yActual = yActual - hNorte
    
    'LOGO
    'Create Frame Into Window nLayoutID  (colX1, zonaY1) (colX2, zonaY2 - 2*bloqueAltura)
    Create Frame Into Window nLayoutID (colX1, yActual - hLogo) (colX2, yActual)
        Pen (1,2,0)
        Brush (2,16777215,16777215)
        From Window num_win_logo
        FillFrame On
    
    yActual = yActual - hLogo 
    'MUNICIPIO
    
    Create Rect Into Window nLayoutID (colX1, zonaY1) (colX2, yActual)
        Pen (1,2,0)
        Brush (2,16777215,16777215)
        
    Create Text Into Window nLayoutID 
        "MAPA TEMÁTICO: " + UCase$(strTematico) + Chr$(13) + Chr$(13) + 
         "MUNICIPIO: " + gblNOMBRE_MUNICIPIO + Chr$(13) + 
        "NÚCLEO: " + gblNOMBRE_NUCLEO 
        (colX1, zonaY1) (colX2, yActual)
        Font ("Arial",1,9,1)
        Justify Center
     
    'Set Map Window nMapIDInLayout Zoom Entire Layer Selection
    
    If WindowInfo(nMapIDInLayout, WIN_INFO_TYPE) <> WIN_MAPPER Then
        Note "La ventana activa no es un mapa"
        Exit Sub
    End If
    
    DONE:
      Exit Sub
    
    errorTematicoViaria:
      Note "ERROR:" + Chr$(13) + Error$()
      Exit Sub
    
    End Sub



    ------------------------------
    Mayca González Pérez
    COMUNIDAD. AUT. REG MURCIA
    ------------------------------



  • 2.  RE: MapBasic Monday: Add thematic legend to a Layout / Presentation programmatically

    Employee
    Posted 19 days ago

    Hey Mayca

    I have an example here that uses a map in a frame in a layout and adds legends for all the layers.

    The legend is created at the top-left of the frame, inside the map window. You can change this to start anywhere you prefer.

    You can grab the frame ID of the frame with the map after creating this, and from this, get the map ID.

    Include "MapBasic.Def"
    
    Declare Sub Main
    
    Sub Main
    
    Dim	nLayer, nMapWID, nLayoutWID, nLegendWID, nMapFrameID, nNumLayers As Integer
    Dim	fFrameX, fFrameY, fFramePositionY, fFrameWidth, fFrameHeight, fLegendWidth, fLegendWidthMax As Float
    Dim	sLayerAlias As String
    
    	nLayoutWID = FrontWindow()
    	If nLayoutWID = 0 Then
    		Note "Please open a layout window!"
    		Exit Sub
    	End If
    	If not WindowInfo(nLayoutWID, WIN_INFO_TYPE) = WIN_LAYOUT_DESIGNER Then
    		Note "Please make a layout window the active window!"
    		Exit Sub
    	End If
    
    	nMapFrameID	= LayoutItemID(nLayoutWID, "", LAYOUT_ITEM_TYPE_MAPPER)
    	If nMapFrameID = -1 Then
    		Note "The frame with the map not found."
    		Exit Sub
    	End If
    
    	Set Paper Units "in"
    	Set CoordSys Layout Units "in"
    
    	nMapWID	= LayoutItemInfo(nLayoutWID, nMapFrameID, LAYOUT_ITEM_INFO_WIN)
    
    	fFrameX		= LayoutItemInfo(nLayoutWID, nMapFrameID, LAYOUT_ITEM_INFO_POS_X)
    	fFrameY		= LayoutItemInfo(nLayoutWID, nMapFrameID, LAYOUT_ITEM_INFO_POS_Y)
    	fFrameWidth	= LayoutItemInfo(nLayoutWID, nMapFrameID, LAYOUT_ITEM_INFO_WIDTH)
    	fFrameHeight	= LayoutItemInfo(nLayoutWID, nMapFrameID, LAYOUT_ITEM_INFO_HEIGHT)
    
    	fFramePositionY	= fFrameY
    
    	nNumLayers	= MapperInfo(nMapWID, MAPPER_INFO_LAYERS)
    	For nLayer = 1 to nNumLayers
    		If LayerInfo(nMapWID, nLayer, LAYER_INFO_TYPE) In (LAYER_INFO_TYPE_NORMAL, LAYER_INFO_TYPE_THEMATIC) Then
    			sLayerAlias	= LayerInfo(nMapWID, nLayer, LAYER_INFO_ALIAS)
    			Print nLayer & ". Layer Alias:  " & sLayerAlias
    
    			'Create Designer Legend
    			'	From Window 3018
    			'	Portrait
    			'	Default Frame Style "Stores" Font ("Arial",0,8,0)
    			'	Frame
    			'		From Layer 1 Using column object label default
    
    			If nLegendWID = 0 Then
    				Create Designer Legend
    					From Window nMapWID
    					Default Frame Style "#" Font ("Arial",0,8,0)
    					Custom
    					Frame From Layer nLayer
    						Position (fFrameX, fFramePositionY) Units "in"
    						Using Column Object Label default
    				nLegendWID =  LayoutItemInfo(nLayoutWID, LayoutInfo(nLayoutWID, LAYOUT_INFO_NUM_ITEMS), LAYOUT_ITEM_INFO_LEGEND_DESIGNER_WINDOW)
    			Else
    				Add Designer Frame
    					Window nLegendWID
    					Custom
    					Frame From Layer nLayer
    						Position (fFrameX, fFramePositionY) Units "in"
    						Using Column Object Label default
    			End If
    
    			fFramePositionY	= fFramePositionY + LayoutItemInfo(nLayoutWID, LayoutInfo(nLayoutWID, LAYOUT_INFO_NUM_ITEMS), LAYOUT_ITEM_INFO_HEIGHT)
    			fLegendWidth		= LayoutItemInfo(nLayoutWID, LayoutInfo(nLayoutWID, LAYOUT_INFO_NUM_ITEMS), LAYOUT_ITEM_INFO_WIDTH)
    			fLegendWidthMax	= Maximum(fLegendWidthMax, fLegendWidth)
    			print nLayer & ". Max Legend width:  " & fLegendWidthMax & " in"
    		End If
    	Next  'nLayer
    
    	print ("Created Legend...creating frame")
    
    ' // Create frame to sit behind legend and create white space
    	Create Rect (fFrameX, fFrameY) (fFrameX + fLegendWidthMax, fFramePositionY)
    		Pen (1,2,0)
    		Brush (2,16777215,16777215)
    		Priority 1
    
    	print ("Collected layer/map info")
    
    End Sub


    ------------------------------
    Peter Horsbøll Møller
    Principal Presales Consultant | Distinguished Engineer
    Precisely | Trust in Data
    ------------------------------