Skip to content
Closed
58 changes: 58 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -248,4 +248,62 @@ ggdraw_plot(res, plots_path / "geom_error_bar.png")
```
<img src="plots/geom_text.png?v=1" alt="geom_text" width="400px">

For `ggmulti` you can set where plots are empty using the 'empty_plots' variable. It can be either an int or list of ints. Note that the value is the index of the plot, starting from the top left and counting across. Also, as this is Python the indexes start at zero, so in a 2x3 grid, index no. 4 will be the bottom left hand side.
```python
mpg = pd.read_csv(data_path / "mpg.csv")
plot1 = ggplot(mpg, aes("class", fill="drv")) + geom_bar()

df = mpg.groupby(["class", "cyl"], as_index=False).agg(meanHwy=("hwy", "mean"))
plot2 = (
ggplot(df, aes("class", "cyl", fill="meanHwy"))
+ geom_tile()
+ geom_text(aes(text="meanHwy"))
+ scale_y_discrete()
)

plot3 = (
ggplot(mpg, aes(x="cty", fill="class"))
+ geom_freqpoly(alpha=0.3)
+ scale_x_continuous()
)

plot4 = ggplot(
mpg, aes(x="cty", fill="class")
) + geom_histogram() + scale_x_continuous()

mpg = mpg.copy(deep=True)
mpg["cty"] = mpg["cty"].astype(float)
plot5 = ggplot(mpg, aes(x="cty", y="displ", size="cyl", color="cty")) + geom_point()

ggmulti(
[plot1, plot2, plot3, plot4, plot5],
plots_path / "gg_multi_pmg_with_one_empty.png",
empty_plots=4
)
```
<img src="plots/gg_multi_pmg_with_one_empty.png?v=1" alt="gg_multi_pmg_with_one_empty" width="800px">

You can also set the `rows` or `cols`
```python
mpg = pd.read_csv(data_path / "mpg.csv")
plot1 = ggplot(mpg, aes("class", fill="drv")) + geom_bar()

df = mpg.groupby(["class", "cyl"], as_index=False).agg(meanHwy=("hwy", "mean"))
plot2 = (
ggplot(df, aes("class", "cyl", fill="meanHwy"))
+ geom_tile()
+ geom_text(aes(text="meanHwy"))
+ scale_y_discrete()
)

plot3 = (
ggplot(mpg, aes(x="cty", fill="class"))
+ geom_freqpoly(alpha=0.3)
+ scale_x_continuous()
)

ggmulti([plot1, plot2, plot3], plots_path / "gg_multi_pmg_set_rows1.png", rows=3)
```
<img src="plots/gg_multi_pmg_set_rows1.png?v=1" alt="gg_multi_pmg_set_rows1" width="800px">

![gg](plots/simple_test.png?v=1)
Binary file added plots/gg_multi_pmg_set_cols1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added plots/gg_multi_pmg_set_cols2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added plots/gg_multi_pmg_set_cols3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added plots/gg_multi_pmg_set_cols4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added plots/gg_multi_pmg_set_rows1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added plots/gg_multi_pmg_set_rows2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added plots/gg_multi_pmg_set_rows3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added plots/gg_multi_pmg_set_rows4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added plots/gg_multi_pmg_set_rows_and_cols1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added plots/gg_multi_pmg_set_rows_and_cols2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added plots/gg_multi_pmg_set_rows_and_cols3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added plots/gg_multi_pmg_set_rows_and_cols4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added plots/gg_multi_pmg_set_rows_and_cols5.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added plots/gg_multi_pmg_set_rows_and_cols6.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added plots/gg_multi_pmg_set_rows_and_cols7.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added plots/gg_multi_pmg_with_many_empty1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added plots/gg_multi_pmg_with_many_empty2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added plots/gg_multi_pmg_with_one_empty.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
130 changes: 106 additions & 24 deletions src/python_ggplot/public_interface/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -1292,7 +1292,6 @@ def generate_plot(
x_ticks, y_ticks = _generate_plot_ticks(
view, filled_scales, plot, theme, hide_ticks
)

_generate_plot_update_scales(
view,
filled_scales,
Expand Down Expand Up @@ -1918,6 +1917,11 @@ def ggmulti(
height: int = 480,
widths: Optional[List[int]] = None,
heights: Optional[List[int]] = None,
empty_plots: Optional[
Union[int, List[int]]
] = None, # Which plot(s) should be empty?
rows: Optional[int] = None,
cols: Optional[int] = None,
use_tex: bool = False,
only_tikz: bool = False,
standalone: bool = False,
Expand All @@ -1937,6 +1941,12 @@ def ggmulti(
width = widths[0] if len(widths) == 1 else width
height = heights[0] if len(heights) == 1 else height

if rows is not None and cols is not None:
if rows <= 0 and cols <= 0:
print("Warning: Existing values of rows and cols will be overwritten.")
elif max(1, rows) * max(1, cols) < len(plts):
raise ValueError("Not enough rows and cols set to display all plots ")

def raise_if_not_matching(arg: Any, arg_name: Any):
if len(arg) > 1 and len(arg) != len(plts):
raise ValueError(
Expand Down Expand Up @@ -1967,15 +1977,19 @@ def raise_if_not_matching(arg: Any, arg_name: Any):

layout(
img,
cols=max(len(widths), 1),
rows=max(len(heights), 1),
cols=cols if cols is not None else max(len(widths), 1),
rows=rows if rows is not None else max(len(heights), 1),
# pyright being wrong here, but we should fix anyway
col_widths=widths_q, # type: ignore
row_heights=heights_q, # type: ignore
)
empty_views = (len(heights_q) * len(widths_q) ) - len(plts)
empty_views = (len(heights_q) * len(widths_q)) - len(plts)
else:
cols, rows = calc_rows_columns(0, 0, len(plts))
rows, cols = calc_rows_columns(
rows if rows is not None else -1,
cols if cols is not None else -1,
len(plts),
)
img = ViewPort.from_coords(
CoordsInput(),
ViewPortInput(
Expand All @@ -1984,30 +1998,98 @@ def raise_if_not_matching(arg: Any, arg_name: Any):
),
)
layout(img, cols=cols, rows=rows)
empty_views = (rows * cols ) - len(plts)
empty_views = (rows * cols) - len(plts)

for i, plt in enumerate(plts):
w_val = widths[i] if i < len(widths) else width
h_val = heights[i] if i < len(heights) else height

pp = ggcreate(plt, width=w_val, height=h_val)
view_embed_at(img, i, pp.view)
if empty_plots is not None:
if isinstance(empty_plots, int):
if empty_plots == 0:
raise ValueError(
"'empty_plots' value is set but there are no empty plots"
)
if empty_plots > rows * cols:
raise ValueError(
"'empty_plots' value is set higher than number of plots"
)
elif isinstance(empty_plots, list):
if len(empty_plots) > empty_views:
raise ValueError("'empty_plots' list length is too large")
if max(empty_plots) > rows * cols:
raise ValueError(
"Max 'empty_plots' value is set higher than number of plots"
)
else:
raise TypeError(
f"Unexpected type for empty_plots: {type(empty_plots)} should be int or list of ints"
)

if empty_views > 0:
for i in range(0, empty_views):
if empty_plots is None:
for i, plt in enumerate(plts):
w_val = widths[i] if i < len(widths) else width
h_val = heights[i] if i < len(heights) else height
empty_view = ViewPort.from_coords(
CoordsInput(),
ViewPortInput(
w_img=PointUnit(width),
h_img=PointUnit(height),
),
)
background_style = img.get_current_background_style()

background(empty_view, background_style)
view_embed_at(img, i + len(plts), empty_view)
pp = ggcreate(plt, width=w_val, height=h_val)
view_embed_at(img, i, pp.view)

if empty_views > 0:
for i in range(0, empty_views):
w_val = widths[i] if i < len(widths) else width
h_val = heights[i] if i < len(heights) else height
empty_view = ViewPort.from_coords(
CoordsInput(),
ViewPortInput(
w_img=PointUnit(width),
h_img=PointUnit(height),
),
)
background_style = img.get_current_background_style()

background(empty_view, background_style)
view_embed_at(img, i + len(plts), empty_view)
else:
add_empty = 0
if isinstance(empty_plots, int):
total_plots = len(plts) + 1
else:
total_plots = len(plts) + len(empty_plots)
for i in range(rows * cols):
i1 = i - add_empty
if i >= total_plots:
w_val = widths[0] if len(widths) == 1 else width
h_val = heights[0] if len(heights) == 1 else height
empty_view = ViewPort.from_coords(
CoordsInput(),
ViewPortInput(
w_img=PointUnit(width),
h_img=PointUnit(height),
),
)
background_style = img.get_current_background_style()

background(empty_view, background_style)
view_embed_at(img, i, empty_view)

elif (isinstance(empty_plots, int) and i == empty_plots) or (
isinstance(empty_plots, list) and i in empty_plots
):
w_val = widths[i1] if i1 < len(widths) else width
h_val = heights[i1] if i1 < len(heights) else height
empty_view = ViewPort.from_coords(
CoordsInput(),
ViewPortInput(
w_img=PointUnit(width),
h_img=PointUnit(height),
),
)
background_style = img.get_current_background_style()

background(empty_view, background_style)
view_embed_at(img, i, empty_view)
add_empty += 1
else:
w_val = widths[i1] if i1 < len(widths) else width
h_val = heights[i1] if i1 < len(heights) else height

pp = ggcreate(plts[i1], width=w_val, height=h_val)
view_embed_at(img, i, pp.view)

draw_to_file(img, fname)
Loading