# Cropping dataframe table data left or center

**URL:** <https://discourse.julialang.org/t/cropping-dataframe-table-data-left-or-center/110344>\
**Category:** General Usage\
**Tags:** question, dataframes, prettytables\
**Created:** [February 17, 2024, 1:57pm UTC](https://discourse.julialang.org/t/cropping-dataframe-table-data-left-or-center/110344 "2024-02-17T13:57:30Z")\
**Posts on this page:** 14\
**Page:** 1

<div class="post-metadata">

**Author:** ![bertlhf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bertlhf/32/38078_2.png) [@bertlhf](https://discourse.julialang.org/u/bertlhf)\
**Post date:** [February 17, 2024, 1:57pm UTC](https://discourse.julialang.org/t/cropping-dataframe-table-data-left-or-center/110344/1 "2024-02-17T13:57:30Z")

</div>

Dataframe table data in Julia can easily be cropped right with the column\_width keyword of PrettyTables.jl. For some of my columns I need data cropped left or center. I used to do this in R with the str\_trunc function from the stringr package. I could not find this functionality in Julia, did I overlook it? How can I do this in Julia?

---

<div class="post-metadata">

**Author:** ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)\
**Post date:** [February 17, 2024, 2:39pm UTC](https://discourse.julialang.org/t/cropping-dataframe-table-data-left-or-center/110344/2 "2024-02-17T14:39:42Z")

</div>

What happens if you use column\_width together with alignment?

---

<div class="post-metadata">

**Author:** ![bertlhf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bertlhf/32/38078_2.png) [@bertlhf](https://discourse.julialang.org/u/bertlhf)\
**Post date:** [February 17, 2024, 2:54pm UTC](https://discourse.julialang.org/t/cropping-dataframe-table-data-left-or-center/110344/3 "2024-02-17T14:54:17Z")

</div>

Thanks for quick reply. Alignment either :l or :r doesn’t change the right truncation.

---

<div class="post-metadata">

**Author:** ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)\
**Post date:** [February 17, 2024, 6:13pm UTC](https://discourse.julialang.org/t/cropping-dataframe-table-data-left-or-center/110344/4 "2024-02-17T18:13:04Z")

</div>

Please check the following proposal (\*_edited_):

```julia
using DataFrames

# function by @StefanKarpinski (https://discourse.julialang.org/t/truncate-string/27978/14)
slice(s, n, m) = s[max(1, nextind(s, 0, n)):min(end, nextind(s, 0, m))]

lstr(s) = slice(s, 1, colwidth)
rstr(s) = slice(s, max(1, length(s) - colwidth + 1), length(s))
cstr(s) = slice(s, max(1, length(s)÷2 - colwidth÷2 + 1), min(length(s), length(s)÷2 + colwidth÷2))

df = DataFrame(strings = [join('α':'ω'), join('a':'z')])
df.length = length.(df.strings)

colwidth = 11
colswidths = [colwidth, 7]
textcols = names(df, String)
show(transform(df, textcols .=> ByRow(lstr); renamecols=false), alignment=:l, columns_width=colswidths)
show(transform(df, textcols .=> ByRow(rstr); renamecols=false), alignment=:r, columns_width=colswidths)
show(transform(df, textcols .=> ByRow(cstr); renamecols=false), alignment=:c, columns_width=colswidths)

```

---

<div class="post-metadata">

**Author:** ![bertlhf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bertlhf/32/38078_2.png) [@bertlhf](https://discourse.julialang.org/u/bertlhf)\
**Post date:** [February 18, 2024, 9:49am UTC](https://discourse.julialang.org/t/cropping-dataframe-table-data-left-or-center/110344/5 "2024-02-18T09:49:52Z")

</div>

Thanks a lot; almost there, I think

### Your suggestion

```jl
df = DataFrame(strings = ["0123456789", join('a':'z'), "short"])
#=
3×1 DataFrame
 Row │ strings
     │ String
─────┼────────────────────────────
   1 │ 0123456789
   2 │ abcdefghijklmnopqrstuvwxyz
   3 │ short
=#

colwidth = 10

pretty_table(df, formatters=leftstr, alignment=:l, columns_width=colwidth)
#=
┌────────────┐
│ strings │
│ String │
├────────────┤
│ 0123456789 │
│ abcdefghij │
│ short │
└────────────┘
=#

pretty_table(df, formatters=rightstr, alignment=:r, columns_width=colwidth)
#=
┌────────────┐
│ strings │
│ String │
├────────────┤
│ 0123456789 │
│ qrstuvwxyz │
│ short │
└────────────┘
=#

pretty_table(df, formatters=centerstr, alignment=:c, columns_width=colwidth)
#=
┌────────────┐
│ strings │
│ String │
├────────────┤
│ 0123456789 │
│ ijklmnopqr │
│ short │
└────────────┘
=#

```

### Solution I’m looking for

```jl
colwidth = 10

pretty_table(df, formatters=righttrunc, alignment=:l, columns_width=colwidth
#=
┌────────────┐
│ strings │
│ String │
├────────────┤
│ 0123456789 │
│ abcdefghi… │
│ short │
└────────────┘
=#

# alignment remains :l
pretty_table(df, formatters=lefttrunc, alignment=:l, columns_width=colwidth
#=
┌────────────┐
│ strings │
│ String │
├────────────┤
│ 0123456789 │
│ …rstuvwxyz │
│ short │
└────────────┘
=#

# alignment remains :l
pretty_table(df, formatters=centertrunc, alignment=:l, columns_width=colwidth
#=
┌────────────┐
│ strings │
│ String │
├────────────┤
│ 0123456789 │
│ abcd…wxyz │
│ short │
└────────────┘
=#

colwidth = 11

pretty_table(df, formatters=centertrunc, alignment=:l, columns_width=colwidth
#=
┌─────────────┐
│ strings │
│ String │
├─────────────┤
│ 0123456789 │
│ abcde…vwxyz │
│ short │
└─────────────┘
=#

```

---

<div class="post-metadata">

**Author:** ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)\
**Post date:** [February 18, 2024, 10:07am UTC](https://discourse.julialang.org/t/cropping-dataframe-table-data-left-or-center/110344/6 "2024-02-18T10:07:51Z")

</div>

Note that in my edited post, I got rid of `formatters` because I could not find an option in PrettyTables.jl to apply them only to text columns when the dataframe is of mixed types.

The code in the edited post looks for dataframe columns of type `String` and applies the formatting only to those. It uses `transform()` to create a new dataframe with the string columns reformatted, while leaving the others as is.

You could use the same logic to get the sought results.

---

<div class="post-metadata">

**Author:** ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)\
**Post date:** [February 18, 2024, 10:28am UTC](https://discourse.julialang.org/t/cropping-dataframe-table-data-left-or-center/110344/7 "2024-02-18T10:28:19Z")

</div>

See here below a modification of the formatting function following your template.  
I added your ASCII example and also my previous unicode example with a mixed types dataframe.

> **revised code**
>
> ```julia
> using DataFrames
> 
> # function by @StefanKarpinski (https://discourse.julialang.org/t/truncate-string/27978/14)
> slice(s, n, m) = s[max(1, nextind(s, 0, n)):min(end, nextind(s, 0, m))]
> 
> function lstr(s)
> ls = length(s)
> ls ≤ colwidth && return s
> return slice(s, 1, colwidth) * "…"
> end
> 
> function rstr(s)
> ls = length(s)
> ls ≤ colwidth && return s
> return "…" * slice(s, max(1, ls - colwidth + 1), ls)
> end
> 
> function cstr(s)
> ls = length(s)
> ls ≤ colwidth && return s
> r1 = slice(s, 1, colwidth÷2)
> r2 = colwidth÷2 ≥ ls ? "" : slice(s, max(1, ls - colwidth÷2 + 1), ls)
> return r1 * "…" * r2
> end
> 
> # Example#1
> df = DataFrame(strings = ["0123456789", join('a':'z'), "short"])
> colwidth = 10
> colswidths = [colwidth + 3]
> textcols = names(df, String)
> show(transform(df, textcols .=> ByRow(lstr); renamecols=false), alignment=:l, columns_width=colswidths)
> show(transform(df, textcols .=> ByRow(rstr); renamecols=false), alignment=:l, columns_width=colswidths)
> show(transform(df, textcols .=> ByRow(cstr); renamecols=false), alignment=:l, columns_width=colswidths)
> 
> # Example#2
> df = DataFrame(strings = [join('α':'ω'), join('a':'z')])
> df.length = length.(df.strings)
> colwidth = 11 # try also: 30
> colswidths = [colwidth + 3, 7]
> textcols = names(df, String)
> show(transform(df, textcols .=> ByRow(lstr); renamecols=false), alignment=:l, columns_width=colswidths)
> show(transform(df, textcols .=> ByRow(rstr); renamecols=false), alignment=:r, columns_width=colswidths)
> show(transform(df, textcols .=> ByRow(cstr); renamecols=false), alignment=:c, columns_width=colswidths)
> 
> ```

---

<div class="post-metadata">

**Author:** ![bertlhf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bertlhf/32/38078_2.png) [@bertlhf](https://discourse.julialang.org/u/bertlhf)\
**Post date:** [February 18, 2024, 11:17am UTC](https://discourse.julialang.org/t/cropping-dataframe-table-data-left-or-center/110344/8 "2024-02-18T11:17:44Z")

</div>

Thanks again. Two down, one to go, I think (the last one, cstr).

## Example#1

```jl
# I changed "..." to "…" in your str functions

df = DataFrame(strings = ["0123456789", join('a':'z'), "short"])
#=
3×1 DataFrame
 Row │ strings
     │ String
─────┼────────────────────────────
   1 │ 0123456789
   2 │ abcdefghijklmnopqrstuvwxyz
   3 │ short
=#

show(transform(df, textcols .=> ByRow(lstr); renamecols=false), alignment=:l, columns_width=colswidths)
#=
3×1 DataFrame
 Row │ strings
     │ String
─────┼────────────────
   1 │ 0123456789
   2 │ abcdefghij…
   3 │ short
=#

# note: alignment=:l
show(transform(df, textcols .=> ByRow(rstr); renamecols=false), alignment=:l, columns_width=colswidths)
#=
3×1 DataFrame
 Row │ strings
     │ String
─────┼────────────────
   1 │ 0123456789
   2 │ …qrstuvwxyz
   3 │ short
=#

# note: alignment=:l
show(transform(df, textcols .=> ByRow(cstr); renamecols=false), alignment=:l, columns_width=colswidths)
#=
3×1 DataFrame
 Row │ strings
     │ String
─────┼────────────────
   1 │ 01234456789
   2 │ ijklm…mnopqr
   3 │ shhort
=#

```

The last one should become something like

```jl
#=
3×1 DataFrame
 Row │ strings
     │ String
─────┼────────────────
   1 │ 01234456789
   2 │ abcde…vwxyz
   3 │ short
=#

```

---

<div class="post-metadata">

**Author:** ![bertlhf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bertlhf/32/38078_2.png) [@bertlhf](https://discourse.julialang.org/u/bertlhf)\
**Post date:** [February 18, 2024, 12:30pm UTC](https://discourse.julialang.org/t/cropping-dataframe-table-data-left-or-center/110344/10 "2024-02-18T12:30:48Z")

</div>

Just ran your last revised code. Everything fine now, only the last sees the “short” string mysteriously duplicated:

```jl
show(transform(df, textcols .=> ByRow(cstr); renamecols=false), alignment=:l, columns_width=colswidths)
#=
3×1 DataFrame
 Row │ strings       
     │ String        
─────┼───────────────
   1 │ 0123456789
   2 │ abcde…vwxyz
   3 │ shortshort
=#

```

---

<div class="post-metadata">

**Author:** ![Dan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dan/32/42581_2.png) [@Dan](https://discourse.julialang.org/u/Dan)\
**Post date:** [February 18, 2024, 12:42pm UTC](https://discourse.julialang.org/t/cropping-dataframe-table-data-left-or-center/110344/11 "2024-02-18T12:42:17Z")

</div>

> [@rafael.guerra](#):
>
> ```julia
> slice(s, n, m) = s[max(1, nextind(s, 0, n)):min(end, nextind(s, 0, m))]
> 
> ```

This should be replaced by a graphemes based slice, which is more appropriate (some codepoints combine to a single… grapheme). Rewriting the above is simple thanks to Unicode package:

```julia
using Unicode

slice(s, n, m) = graphemes(s, max(n,1):min(m,length(graphemes(s))))

```

---

<div class="post-metadata">

**Author:** ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)\
**Post date:** [February 18, 2024, 12:55pm UTC](https://discourse.julialang.org/t/cropping-dataframe-table-data-left-or-center/110344/12 "2024-02-18T12:55:37Z")

</div>

Fixed in the revised code in [post above](https://discourse.julialang.org/t/cropping-dataframe-table-data-left-or-center/110344/7) .

---

<div class="post-metadata">

**Author:** ![bertlhf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bertlhf/32/38078_2.png) [@bertlhf](https://discourse.julialang.org/u/bertlhf)\
**Post date:** [February 18, 2024, 2:33pm UTC](https://discourse.julialang.org/t/cropping-dataframe-table-data-left-or-center/110344/13 "2024-02-18T14:33:00Z")

</div>

Thanks, @rafael.guerra. For what it is worth, below an example how I now use this solution in my workflow.

```jl
function tbk_trunc(trunc::Function, df::AbstractDataFrame, field::String, colwidth::Int64)
    transform(df, field .=> ByRow(trunc); renamecols=false)
end

@pipe first(tbk_triple(), 5) |> tbk_trunc(ctrunc, _, "OBJECT", 10) |> tbk_page(_)

```

- first part of the pipe is a dataframe produced in some way or another from the more than 110,000 SUBJECT PREDICATE OBJECT triples of my personal “knowledge” base
- second part of the pipe is your solution a little bit adapted to my own taste
- third part of the pipe invokes PrettyTables and the less function; in this way I can easily browse large dataframes with the less pager in my terminal

---

<div class="post-metadata">

**Author:** ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)\
**Post date:** [February 19, 2024, 2:26pm UTC](https://discourse.julialang.org/t/cropping-dataframe-table-data-left-or-center/110344/14 "2024-02-19T14:26:27Z")

</div>

> [@bertlhf](#):
>
> third part of the pipe invokes PrettyTables and the less function; in this way I can easily browse large dataframes with the less pager in my terminal

Just in case, are you aware of the [TerminalPager](https://discourse.julialang.org/t/ann-terminalpager-jl-v0-5-0/104122) Julia package?

---

<div class="post-metadata">

**Author:** ![bertlhf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bertlhf/32/38078_2.png) [@bertlhf](https://discourse.julialang.org/u/bertlhf)\
**Post date:** [February 19, 2024, 2:39pm UTC](https://discourse.julialang.org/t/cropping-dataframe-table-data-left-or-center/110344/15 "2024-02-19T14:39:13Z")

</div>

I became aware of TerminalPager.jl after I implemented the tbk\_page function using a.o. the less function. Since I’m completely happy with it as it runs, I did not bother to look into TerminalPager.

Thanks anyway.
