Skip to main content
cancel
Showing results for 
Search instead for 
Did you mean: 

The Power BI Data Visualization World Championships is back! It's time to submit your entry. Live now!

Reply
Ben1981
Helper III
Helper III

Model View layout bug?

Hi, Has anyone else started having a problem with the model view layout, I've noticed it for some time now but it's seems to be getting worse. 

I start a new report and model my data but over time and the more tables that get added the model will move down to the far bottom left and gets worse to the point that even when I zoom out to 10% it takes ages scrolling down to the model. I know I can click that button in the bottom right to re-centre but when a new table is added it gets added at the top and I have to drag it down which is taking ages!

 

I can probably create a new layout view and start over but it's just ridculous that it's got to that. I mean am I missing something in settings or is this just some weird bug in Power BI?

 

 

1 ACCEPTED SOLUTION
Poojara_D12
Super User
Super User

Hi @Ben1981 

What you're experiencing with the Power BI Model View layout shifting dramatically toward the bottom-left over time—especially as more tables are added—is a known and increasingly reported issue among users. This behavior isn't due to any setting you've missed; rather, it's generally considered a layout bug or usability flaw within the Model View canvas of Power BI Desktop. As you add tables, Power BI sometimes auto-places them far from the existing layout, often above and to the far left of your current model, forcing you to scroll extensively or drag them manually into view. The “Fit to screen” or “Center diagram” button can temporarily help, but as you've noticed, it doesn't solve the core issue of erratic table placement.

This problem tends to get worse with larger data models and is not something you can permanently fix via settings. While recreating the layout view or organizing objects into separate diagram layers (which Power BI allows via the model view tabs) may help manage complexity, the erratic placement behavior remains. Microsoft hasn’t officially acknowledged a fix for this yet, but it's worth submitting feedback or upvoting similar issues on the Power BI Ideas forum, as this helps prioritize improvements. Until then, careful use of diagram layers and manually maintaining layout discipline is the most practical workaround.

 

Did I answer your question? Mark my post as a solution, this will help others!
If my response(s) assisted you in any way, don't forget to drop me a "Kudos"

Kind Regards,
Poojara - Proud to be a Super User
Data Analyst | MSBI Developer | Power BI Consultant
Consider Subscribing my YouTube for Beginners/Advance Concepts: https://youtube.com/@biconcepts?si=04iw9SYI2HN80HKS

View solution in original post

5 REPLIES 5
Andrew_May
Frequent Visitor

So, out of frustration (and to see how far I can push copilot), I got copilot to write a pyton script for fix the position of the diagram.  If copilot (chatGPT) can do this in a few minutes, I don't know why Microsoft can't have a button to do the same in Power BI!

 

Simply:

1. save and close the power BI

2. rename the <Report>.pbix to <Report>.pbix.zip and extract DiagramLayout file

3. run the python similar to the following:

python RepositionPowerBIModelView.py "DiagramLayout" -o "DiagramLayout" --MinX 100 --MinY 100

4. Put the file back in <Report>.pbix.zip, overwriting the original

5. Rename the file back to <Report>.pbix

 

Python code (Provided with no promises or guarantees... USE AT YOUR OWN RISK!!!): 

import json
import argparse
from pathlib import Path
from typing import Any, Tuple, Optional


# -----------------------------
# Encoding-aware JSON load/save
# -----------------------------

def detect_encoding(raw: bytes) -> str:
    """
    Detect likely encoding for Power BI DiagramLayout files.
    - BOM UTF-16 LE/BE -> 'utf-16' (Python handles BOM)
    - NUL bytes early -> UTF-16LE without BOM (common for these files; your sample shows this) [1](https://openwayfood-my.sharepoint.com/personal/amay_openwayfood_com_au/Documents/Microsoft%20Copilot%20Chat%20Files/DiagramLayout.json?web=1)
    - Otherwise assume UTF-8 (with optional BOM via utf-8-sig)
    """
    if raw.startswith(b"\xff\xfe") or raw.startswith(b"\xfe\xff"):
        return "utf-16"
    if b"\x00" in raw[:200]:
        return "utf-16-le"
    return "utf-8-sig"


def load_json_file(path: Path) -> Tuple[dict[str, Any], str]:
    """
    Returns (data_dict, detected_output_encoding).
    detected_output_encoding is normalized to:
      - 'utf-16-le' if input is UTF-16-ish
      - 'utf-8' otherwise
    """
    raw = path.read_bytes()
    enc = detect_encoding(raw)

    text = raw.decode(enc)
    text = text.lstrip("\ufeff").lstrip()  # remove BOM char + whitespace if present
    data = json.loads(text)

    if not isinstance(data, dict):
        raise ValueError(f"Top-level JSON is not an object/dict. Got: {type(data)}")

    # Normalize "match" output encoding to utf-16-le or utf-8
    out_enc = "utf-16-le" if enc in ("utf-16", "utf-16-le") else "utf-8"
    return data, out_enc


def save_json_file_minified(path: Path, data: dict[str, Any], encoding: str) -> None:
    """
    Writes MINIFIED (compressed) JSON, no indentation.
    separators=(',', ':') removes unnecessary whitespace.
    ensure_ascii=False preserves any non-ASCII characters as-is.
    """
    text = json.dumps(data, ensure_ascii=False, separators=(",", ":"))
    path.write_text(text, encoding=encoding)


# -----------------------------
# Diagram operations
# -----------------------------

def list_diagram_names(data: dict[str, Any]) -> list[str]:
    diagrams = data.get("diagrams")
    if not isinstance(diagrams, list):
        return []
    return [str(d.get("name", "")) for d in diagrams]


def find_diagram(data: dict[str, Any], diagram_name: str) -> dict[str, Any]:
    diagrams = data.get("diagrams")
    if not isinstance(diagrams, list):
        raise ValueError("JSON does not contain a 'diagrams' array.")

    target = diagram_name.strip().lower()
    for d in diagrams:
        name = str(d.get("name", "")).strip().lower()
        if name == target:
            return d

    available = list_diagram_names(data)
    raise ValueError(f'No diagram named "{diagram_name}" found. Available: {available}')


def compute_min_xy(nodes: list[dict[str, Any]]) -> Tuple[float, float]:
    xs: list[float] = []
    ys: list[float] = []

    for n in nodes:
        loc = n.get("location", {})
        x = loc.get("x", None)
        y = loc.get("y", None)
        if isinstance(x, (int, float)):
            xs.append(float(x))
        if isinstance(y, (int, float)):
            ys.append(float(y))

    if not xs:
        raise ValueError("No numeric node.location.x values found in nodes.")
    if not ys:
        raise ValueError("No numeric node.location.y values found in nodes.")

    return min(xs), min(ys)


def shift_nodes(nodes: list[dict[str, Any]], delta_x: float, delta_y: float) -> int:
    changed = 0
    for n in nodes:
        loc = n.get("location")
        if isinstance(loc, dict):
            updated = False
            if isinstance(loc.get("x", None), (int, float)):
                loc["x"] = float(loc["x"]) + delta_x
                updated = True
            if isinstance(loc.get("y", None), (int, float)):
                loc["y"] = float(loc["y"]) + delta_y
                updated = True
            if updated:
                changed += 1
    return changed


def process_file(
    input_path: str,
    output_path: Optional[str],
    min_x: float,
    min_y: float,
    diagram_name: str,
    shift_scroll: bool,
    output_encoding_mode: str
) -> None:
    input_file = Path(input_path)
    if not input_file.exists():
        raise FileNotFoundError(f"Input file not found: {input_file}")

    output_file = Path(output_path) if output_path else input_file

    data, detected_out_enc = load_json_file(input_file)

    # Resolve output encoding
    if output_encoding_mode == "match":
        out_enc = detected_out_enc
    elif output_encoding_mode == "utf-16-le":
        out_enc = "utf-16-le"
    else:
        out_enc = "utf-8"

    diagram = find_diagram(data, diagram_name)

    nodes = diagram.get("nodes")
    if not isinstance(nodes, list) or len(nodes) == 0:
        raise ValueError(f'Diagram "{diagram_name}" has no nodes array (or it is empty).')

    current_min_x, current_min_y = compute_min_xy(nodes)

    # Shift so that new minimums become MinX and MinY:
    delta_x = float(min_x) - current_min_x
    delta_y = float(min_y) - current_min_y

    changed_nodes = shift_nodes(nodes, delta_x, delta_y)

    # Optional: shift scrollPosition too (keeps viewport aligned with moved nodes)
    if shift_scroll:
        sp = diagram.get("scrollPosition")
        if isinstance(sp, dict):
            if isinstance(sp.get("x", None), (int, float)):
                sp["x"] = float(sp["x"]) + delta_x
            if isinstance(sp.get("y", None), (int, float)):
                sp["y"] = float(sp["y"]) + delta_y

    # Write MINIFIED JSON
    save_json_file_minified(output_file, data, encoding=out_enc)

    print(f"Updated '{input_file}' -> '{output_file}'")
    print(f'Diagram processed: "{diagram_name}"')
    print(f"  currentMinX={current_min_x:.6f}, currentMinY={current_min_y:.6f}")
    print(f"  targetMinX={min_x:.6f}, targetMinY={min_y:.6f}")
    print(f"  deltaX={delta_x:.6f}, deltaY={delta_y:.6f}")
    print(f"  nodes shifted={changed_nodes}")
    print(f"  output encoding: {out_enc}")
    print("  output format: minified JSON")
    if shift_scroll:
        print("  scrollPosition shifted: yes")


def main():
    parser = argparse.ArgumentParser(
        description="Shift a Power BI diagram's node locations so minimum X/Y become specified values."
    )

    parser.add_argument("input", help="Input layout file path (e.g., DiagramLayout.json)")
    parser.add_argument("-o", "--output", default=None,
                        help="Output file path (defaults to overwrite input)")
    parser.add_argument("--MinX", type=float, required=False, help="New minimum X for nodes")
    parser.add_argument("--MinY", type=float, required=False, help="New minimum Y for nodes")
    parser.add_argument("--DiagramName", default="All tables",
                        help='Diagram name to process (default: "All tables")')
    parser.add_argument("--shift-scroll", action="store_true",
                        help="Also shift diagram.scrollPosition by the same deltaX/deltaY")
    parser.add_argument("--list-diagrams", action="store_true",
                        help="List diagram names in the file and exit")
    parser.add_argument(
        "--output-encoding",
        default="match",
        choices=["match", "utf-16-le", "utf-8"],
        help="Output encoding: match (default), utf-16-le, or utf-8"
    )

    args = parser.parse_args()

    if args.list_diagrams:
        data, _ = load_json_file(Path(args.input))
        names = list_diagram_names(data)
        print("Diagrams found:")
        for n in names:
            print(f"  - {n}")
        return

    if args.MinX is None or args.MinY is None:
        parser.error("--MinX and --MinY are required unless --list-diagrams is used.")

    process_file(
        input_path=args.input,
        output_path=args.output,
        min_x=args.MinX,
        min_y=args.MinY,
        diagram_name=args.DiagramName,
        shift_scroll=args.shift_scroll,
        output_encoding_mode=args.output_encoding
    )


if __name__ == "__main__":
	main()

 

Poojara_D12
Super User
Super User

Hi @Ben1981 

What you're experiencing with the Power BI Model View layout shifting dramatically toward the bottom-left over time—especially as more tables are added—is a known and increasingly reported issue among users. This behavior isn't due to any setting you've missed; rather, it's generally considered a layout bug or usability flaw within the Model View canvas of Power BI Desktop. As you add tables, Power BI sometimes auto-places them far from the existing layout, often above and to the far left of your current model, forcing you to scroll extensively or drag them manually into view. The “Fit to screen” or “Center diagram” button can temporarily help, but as you've noticed, it doesn't solve the core issue of erratic table placement.

This problem tends to get worse with larger data models and is not something you can permanently fix via settings. While recreating the layout view or organizing objects into separate diagram layers (which Power BI allows via the model view tabs) may help manage complexity, the erratic placement behavior remains. Microsoft hasn’t officially acknowledged a fix for this yet, but it's worth submitting feedback or upvoting similar issues on the Power BI Ideas forum, as this helps prioritize improvements. Until then, careful use of diagram layers and manually maintaining layout discipline is the most practical workaround.

 

Did I answer your question? Mark my post as a solution, this will help others!
If my response(s) assisted you in any way, don't forget to drop me a "Kudos"

Kind Regards,
Poojara - Proud to be a Super User
Data Analyst | MSBI Developer | Power BI Consultant
Consider Subscribing my YouTube for Beginners/Advance Concepts: https://youtube.com/@biconcepts?si=04iw9SYI2HN80HKS

Yeah I figured that would be, hopefully it's something that will get resolved but until then I created a new layout tab to re-order my layout where I can see it....hopefully it won't effect this tab.

rajendraongole1
Super User
Super User

Hi @Ben1981  - Use the "Reset Layout" Button. Some users keep most modeling work in the Modeling tab and use diagram view only sparingly due to performance and layout quirks.Before adding new tables, zoom out and scroll upward to roughly where they’ll appear.Add tables in small batches to better manage placement.

 

Hope this helps.

 





Did I answer your question? Mark my post as a solution!

Proud to be a Super User!





Is there a "Reset Layout" button?  I've searched for such a thing in power BI Model view and there doesn't appear to be... or even an auto-arrange.

What's mose frustrating is that you can't even multi-select the tables in the model view to move them!

Helpful resources

Announcements
Power BI DataViz World Championships

Power BI Dataviz World Championships

The Power BI Data Visualization World Championships is back! It's time to submit your entry.

January Power BI Update Carousel

Power BI Monthly Update - January 2026

Check out the January 2026 Power BI update to learn about new features.

FabCon Atlanta 2026 carousel

FabCon Atlanta 2026

Join us at FabCon Atlanta, March 16-20, for the ultimate Fabric, Power BI, AI and SQL community-led event. Save $200 with code FABCOMM.