Join us at FabCon Atlanta from March 16 - 20, 2026, for the ultimate Fabric, Power BI, AI and SQL community-led event. Save $200 with code FABCOMM.
Register now!The Power BI Data Visualization World Championships is back! It's time to submit your entry. Live now!
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?
Solved! Go to Solution.
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.
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 1004. 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()
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.
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.
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.
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!
The Power BI Data Visualization World Championships is back! It's time to submit your entry.
Check out the January 2026 Power BI update to learn about new features.
| User | Count |
|---|---|
| 60 | |
| 41 | |
| 27 | |
| 25 | |
| 23 |
| User | Count |
|---|---|
| 127 | |
| 109 | |
| 55 | |
| 39 | |
| 33 |