{"spec_id":"datamatrix-basic","library":"plotly","language":"python","code":"\"\"\" anyplot.ai\ndatamatrix-basic: Basic Data Matrix 2D Barcode\nLibrary: plotly 6.7.0 | Python 3.13.13\nQuality: 89/100 | Updated: 2026-05-20\n\"\"\"\n\nimport os\n\nimport numpy as np\nimport plotly.graph_objects as go\n\n\n# Theme tokens\nTHEME = os.getenv(\"ANYPLOT_THEME\", \"light\")\nPAGE_BG = \"#FAF8F1\" if THEME == \"light\" else \"#1A1A17\"\nINK = \"#1A1A17\" if THEME == \"light\" else \"#F0EFE8\"\nINK_SOFT = \"#4A4A44\" if THEME == \"light\" else \"#B8B7B0\"\nINK_MUTED = \"#6B6A63\" if THEME == \"light\" else \"#A8A79F\"\n\n# Barcode cell colors — inverted per theme for contrast\nCELL_ON = \"#1A1A17\" if THEME == \"light\" else \"#F0EFE8\"\nCELL_OFF = PAGE_BG\n\n# Data - encode a sample serial number into a 16×16 Data Matrix pattern\ncontent = \"SERIAL:12345678\"\nmatrix_size = 16\n\nmatrix = np.zeros((matrix_size, matrix_size), dtype=int)\n\n# L-shaped finder pattern (solid left column and bottom row)\nmatrix[:, 0] = 1\nmatrix[matrix_size - 1, :] = 1\n\n# Alternating timing patterns (top row and right column)\nfor i in range(matrix_size):\n    matrix[0, i] = i % 2\nfor i in range(matrix_size):\n    matrix[i, matrix_size - 1] = i % 2\n\n# Interior data cells — deterministic pattern based on content (simulated ECC 200)\ncontent_hash = sum(ord(c) for c in content)\nnp.random.seed(content_hash)\nfor i in range(1, matrix_size - 1):\n    for j in range(1, matrix_size - 1):\n        matrix[i, j] = np.random.randint(0, 2)\n\n# Flip for correct visual orientation (L-finder at left+bottom in display)\nmatrix = np.flipud(matrix)\n\n# Cell type labels for interactive hover (post-flipud: row 0=bottom=finder, row 15=top=timing)\ncell_type = np.empty((matrix_size, matrix_size), dtype=object)\nfor i in range(matrix_size):\n    for j in range(matrix_size):\n        if j == 0 or i == 0:\n            cell_type[i, j] = \"Finder\"\n        elif j == matrix_size - 1 or i == matrix_size - 1:\n            cell_type[i, j] = \"Timing\"\n        else:\n            cell_type[i, j] = \"Data\"\n\n# Plot\nfig = go.Figure()\n\nfig.add_trace(\n    go.Heatmap(\n        z=matrix,\n        x=np.arange(matrix_size),\n        y=np.arange(matrix_size),\n        customdata=cell_type,\n        hovertemplate=\"<b>%{customdata}</b><extra></extra>\",\n        colorscale=[[0, CELL_OFF], [1, CELL_ON]],\n        showscale=False,\n        xgap=1.5,\n        ygap=1.5,\n    )\n)\n\n# Quiet zone border — ISO/IEC 16022 requires at least 1 module of clear space\nfig.add_shape(\n    type=\"rect\",\n    x0=-0.5,\n    y0=-0.5,\n    x1=matrix_size - 0.5,\n    y1=matrix_size - 0.5,\n    xref=\"x\",\n    yref=\"y\",\n    line={\"color\": INK_MUTED, \"width\": 1, \"dash\": \"dot\"},\n    fillcolor=\"rgba(0,0,0,0)\",\n)\n\nfig.update_layout(\n    title={\n        \"text\": \"datamatrix-basic · python · plotly · anyplot.ai\",\n        \"font\": {\"size\": 16, \"color\": INK},\n        \"x\": 0.5,\n        \"xanchor\": \"center\",\n    },\n    xaxis={\n        \"showticklabels\": False,\n        \"showgrid\": False,\n        \"zeroline\": False,\n        \"scaleanchor\": \"y\",\n        \"scaleratio\": 1,\n        \"constrain\": \"domain\",\n    },\n    yaxis={\"showticklabels\": False, \"showgrid\": False, \"zeroline\": False, \"constrain\": \"domain\"},\n    plot_bgcolor=PAGE_BG,\n    paper_bgcolor=PAGE_BG,\n    margin={\"l\": 80, \"r\": 80, \"t\": 100, \"b\": 100},\n    annotations=[\n        {\n            \"text\": f\"Encoded: {content}\",\n            \"xref\": \"paper\",\n            \"yref\": \"paper\",\n            \"x\": 0.5,\n            \"y\": -0.08,\n            \"showarrow\": False,\n            \"font\": {\"size\": 12, \"color\": INK_SOFT},\n            \"xanchor\": \"center\",\n        },\n        {\n            \"text\": \"ECC 200 | 16×16 Matrix\",\n            \"xref\": \"paper\",\n            \"yref\": \"paper\",\n            \"x\": 0.5,\n            \"y\": -0.13,\n            \"showarrow\": False,\n            \"font\": {\"size\": 10, \"color\": INK_MUTED},\n            \"xanchor\": \"center\",\n        },\n        # L-Finder callout — arrow from margin into finder corner\n        {\n            \"text\": \"L-Finder\",\n            \"x\": 0.5,\n            \"y\": 0.5,\n            \"xref\": \"x\",\n            \"yref\": \"y\",\n            \"showarrow\": True,\n            \"arrowhead\": 2,\n            \"arrowwidth\": 1.2,\n            \"arrowcolor\": INK_SOFT,\n            \"ax\": -50,\n            \"ay\": 40,\n            \"font\": {\"size\": 8, \"color\": INK_SOFT},\n            \"xanchor\": \"center\",\n        },\n        # Timing callout — arrow from margin into timing corner\n        {\n            \"text\": \"Timing\",\n            \"x\": 14.5,\n            \"y\": 14.5,\n            \"xref\": \"x\",\n            \"yref\": \"y\",\n            \"showarrow\": True,\n            \"arrowhead\": 2,\n            \"arrowwidth\": 1.2,\n            \"arrowcolor\": INK_SOFT,\n            \"ax\": 50,\n            \"ay\": -40,\n            \"font\": {\"size\": 8, \"color\": INK_SOFT},\n            \"xanchor\": \"center\",\n        },\n    ],\n)\n\nfig.update_yaxes(scaleanchor=\"x\", scaleratio=1)\n\n# Save — square canvas (2400×2400 px) suits the symmetric barcode format\nfig.write_image(f\"plot-{THEME}.png\", width=600, height=600, scale=4)\nfig.write_html(f\"plot-{THEME}.html\", include_plotlyjs=\"cdn\")\n"}